From 51fc652a85ef8fd3862d89805f28d4017561bccc Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 21 Feb 2015 19:40:03 -0500 Subject: [PATCH 1/6] add missing argument verification in some rand! calls --- base/random.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/base/random.jl b/base/random.jl index c0c26f737d5c6..3ea594d8327bb 100644 --- a/base/random.jl +++ b/base/random.jl @@ -300,6 +300,9 @@ function rand!{I<:FloatInterval}(r::MersenneTwister, A::Array{Float64}, n::Int=l # so, even for well aligned arrays, fill_array! is used to generate only # the n-2 first values (or n-3 if n is odd), and the remaining values are # generated by the scalar version of rand + if n > length(A) + error(BoundsError(A,n)) + end n2 = (n-2) ÷ 2 * 2 if n2 < dsfmt_get_min_array_size() rand_AbstractArray_Float64!(r, A, n, I) @@ -308,13 +311,13 @@ function rand!{I<:FloatInterval}(r::MersenneTwister, A::Array{Float64}, n::Int=l align = Csize_t(pA) % 16 if align > 0 pA2 = pA + 16 - align - fill_array!(r.state, pA2, n2, I) - unsafe_copy!(pA, pA2, n2) + fill_array!(r.state, pA2, n2, I) # generate the data in-place, but shifted + unsafe_copy!(pA, pA2, n2) # move the data to the beginning of the array else fill_array!(r.state, pA, n2, I) end for i=n2+1:n - A[i] = rand(r, I) + @inbounds A[i] = rand(r, I) end end A @@ -360,6 +363,9 @@ rand!{T<:Union(Float16, Float32)}(r::MersenneTwister, A::Array{T}) = rand!(r, A, function rand!(r::MersenneTwister, A::Array{UInt128}, n::Int=length(A)) + if n > length(A) + error(BoundsError(A,n)) + end Af = pointer_to_array(convert(Ptr{Float64}, pointer(A)), 2n) i = n while true From c6ee2f9a64109a40c6906a0471f7ef6c32dd344c Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 2 Jan 2015 23:50:45 -0500 Subject: [PATCH 2/6] eliminate pointertoref Intrinsic and just use jl_value_ptr function reversably --- base/inference.jl | 3 +-- base/pointer.jl | 2 +- src/builtins.c | 4 ++-- src/ccall.cpp | 25 +++++++++++++++++++------ src/dump.c | 2 -- src/intrinsics.cpp | 11 ++--------- src/julia.h | 2 +- test/Makefile | 2 +- 8 files changed, 27 insertions(+), 24 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 8b131d1f7e012..35e8add58da5d 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -2119,8 +2119,7 @@ function is_pure_builtin(f) f === Intrinsics.pointerset || # this one is never effect-free f === Intrinsics.ccall || # this one is never effect-free f === Intrinsics.llvmcall || # this one is never effect-free - f === Intrinsics.jl_alloca || # this one is volatile, TODO: possibly also effect-free? - f === Intrinsics.pointertoref) # this one is volatile + f === Intrinsics.jl_alloca) return true end end diff --git a/base/pointer.jl b/base/pointer.jl index 277f084d06597..e94c43a3c7ff2 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -52,7 +52,7 @@ unsafe_store!{T}(p::Ptr{T}, x, i::Integer) = pointerset(p, convert(T,x), Int(i)) unsafe_store!{T}(p::Ptr{T}, x) = pointerset(p, convert(T,x), 1) # convert a raw Ptr to an object reference, and vice-versa -unsafe_pointer_to_objref(p::Ptr) = pointertoref(unbox(Ptr{Void},p)) +unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Void},), x) pointer_from_objref(x::Any) = ccall(:jl_value_ptr, Ptr{Void}, (Any,), x) integer(x::Ptr) = convert(UInt, x) diff --git a/src/builtins.c b/src/builtins.c index ac545d2ef108a..3ab3d2728dc4b 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -730,9 +730,9 @@ DLLEXPORT void *jl_array_ptr(jl_array_t *a) { return a->data; } -DLLEXPORT void *jl_value_ptr(jl_value_t *a) +DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a) { - return (void*)a; + return a; } // printing ------------------------------------------------------------------- diff --git a/src/ccall.cpp b/src/ccall.cpp index c34c58427dc4d..3a1eaf7f12642 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1000,7 +1000,11 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) if (fptr == (void *) &jl_array_ptr || (f_lib==NULL && f_name && !strcmp(f_name,"jl_array_ptr"))) { assert(lrt->isPointerTy()); - Value *ary = emit_expr(args[4], ctx); + assert(!isVa); + assert(nargt==1); + jl_value_t *argi = args[4]; + assert(!(jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym)); + Value *ary = emit_expr(argi, ctx); JL_GC_POP(); return mark_or_box_ccall_result(builder.CreateBitCast(emit_arrayptr(ary),lrt), args[2], rt, static_rt, ctx); @@ -1008,13 +1012,22 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) if (fptr == (void *) &jl_value_ptr || (f_lib==NULL && f_name && !strcmp(f_name,"jl_value_ptr"))) { assert(lrt->isPointerTy()); + assert(!isVa); + assert(nargt==1); jl_value_t *argi = args[4]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } - Value *ary = boxed(emit_expr(argi, ctx),ctx); + Value *ary; + Type *largty = fargt[0]; + if (largty == jl_pvalue_llvmt) { + ary = boxed(emit_expr(argi, ctx),ctx); + } else { + assert(!addressOf); + ary = emit_unbox(largty, emit_unboxed(argi, ctx), jl_tupleref(tt, 0)); + } JL_GC_POP(); return mark_or_box_ccall_result(builder.CreateBitCast(emit_nthptr_addr(ary, addressOf?1:0), lrt), args[2], rt, static_rt, ctx); @@ -1067,7 +1080,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) bool needTempSpace = false; bool needStackRestore = false; for(i=4; i < nargs+1; i+=2) { - int ai = (i-4)/2; + size_t ai = (i-4)/2; jl_value_t *argi = args[i]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { @@ -1076,9 +1089,9 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) } Type *largty; jl_value_t *jargty; - if (isVa && ai >= nargty-1) { - largty = fargt[nargty-1]; - jargty = jl_tparam0(jl_tupleref(tt,nargty-1)); + if (isVa && ai >= nargt-1) { + largty = fargt[nargt-1]; + jargty = jl_tparam0(jl_tupleref(tt,nargt-1)); } else { largty = fargt[ai]; diff --git a/src/dump.c b/src/dump.c index e2b25908af677..645efba41e3c9 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1822,7 +1822,6 @@ void jl_init_serializer(void) jl_box_int32(45), jl_box_int32(46), jl_box_int32(47), jl_box_int32(48), jl_box_int32(49), jl_box_int32(50), jl_box_int32(51), jl_box_int32(52), jl_box_int32(53), - jl_box_int32(54), jl_box_int32(55), jl_box_int32(56), #endif jl_box_int64(0), jl_box_int64(1), jl_box_int64(2), jl_box_int64(3), jl_box_int64(4), jl_box_int64(5), @@ -1843,7 +1842,6 @@ void jl_init_serializer(void) jl_box_int64(45), jl_box_int64(46), jl_box_int64(47), jl_box_int64(48), jl_box_int64(49), jl_box_int64(50), jl_box_int64(51), jl_box_int64(52), jl_box_int64(53), - jl_box_int64(54), jl_box_int64(55), jl_box_int64(56), #endif jl_labelnode_type, jl_linenumbernode_type, jl_gotonode_type, jl_quotenode_type, jl_topnode_type, jl_type_type, jl_bottom_type, diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 7877ad1c11d8f..3faefc5f35e04 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -39,7 +39,7 @@ namespace JL_I { sqrt_llvm, powi_llvm, sqrt_llvm_fast, // pointer access - pointerref, pointerset, pointertoref, + pointerref, pointerset, // c interface ccall, cglobal, jl_alloca, llvmcall }; @@ -803,13 +803,6 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, HANDLE(zext_int,2) return generic_zext(args[1], args[2], ctx); HANDLE(pointerref,2) return emit_pointerref(args[1], args[2], ctx); HANDLE(pointerset,3) return emit_pointerset(args[1], args[2], args[3], ctx); - HANDLE(pointertoref,1) { - Value *p = auto_unbox(args[1], ctx); - if (p->getType()->isIntegerTy()) { - return builder.CreateIntToPtr(p, jl_pvalue_llvmt); - } - return builder.CreateBitCast(p, jl_pvalue_llvmt); - } HANDLE(checked_fptosi,2) { Value *x = FP(auto_unbox(args[2], ctx)); return emit_checked_fptosi(args[1], x, ctx); @@ -1361,7 +1354,7 @@ extern "C" void jl_init_intrinsic_functions(void) ADD_I(ceil_llvm); ADD_I(floor_llvm); ADD_I(trunc_llvm); ADD_I(rint_llvm); ADD_I(sqrt_llvm); ADD_I(powi_llvm); ADD_I(sqrt_llvm_fast); - ADD_I(pointerref); ADD_I(pointerset); ADD_I(pointertoref); + ADD_I(pointerref); ADD_I(pointerset); ADD_I(checked_sadd); ADD_I(checked_uadd); ADD_I(checked_ssub); ADD_I(checked_usub); ADD_I(checked_smul); ADD_I(checked_umul); diff --git a/src/julia.h b/src/julia.h index bb43e8ed3013a..1c99eb8d4cc62 100644 --- a/src/julia.h +++ b/src/julia.h @@ -800,7 +800,7 @@ DLLEXPORT jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i); DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i, jl_value_t *rhs); DLLEXPORT int jl_field_isdefined(jl_value_t *v, size_t i); DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, char *fld); -DLLEXPORT void *jl_value_ptr(jl_value_t *a); +DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a); // arrays diff --git a/test/Makefile b/test/Makefile index 3a30a86e79944..8c97294bc5bc1 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,7 +1,7 @@ JULIAHOME = $(abspath ..) include ../Make.inc -TESTS = all linalg sparse $(filter-out TestHelpers runtests testdefs,$(subst .jl,,$(wildcard *.jl))) +TESTS = all linalg $(filter-out TestHelpers runtests testdefs,$(subst .jl,,$(wildcard *.jl))) default: all From 5202f8eca603b34ef6d4c670989c5382aa44063a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 24 Jan 2015 17:13:59 -0500 Subject: [PATCH 3/6] change lowering of ccall cconvert arguments ccall(:a, B, (C,), d) is now lowered as: d#1 = cconvert_gcroot(C, d) Expr(:call, :ccall, :a, B, (C,), cconvert(C, d#1), d#1) This allows implementation of the special-case ccall lowering logic in Julia and still create a gcroot for it as needed the Ref{T} type is the new supertype of Ptr{T}. the ccall emission turns a Ref{T} into a Ptr{T}, as if the &addressOf operator had been applied. the specific rules for this will be moved from the current gist to the documentation at a later point. --- .gitignore | 1 + base/abstractarray.jl | 11 ++ base/base.jl | 16 +- base/boot.jl | 5 +- base/inference.jl | 15 +- base/pcre.jl | 8 +- base/pointer.jl | 12 +- base/refpointer.jl | 121 ++++++++++++++ base/socket.jl | 3 +- base/sysimg.jl | 1 + src/alloc.c | 1 + src/builtins.c | 1 + src/ccall.cpp | 371 ++++++++++++++++-------------------------- src/cgutils.cpp | 3 +- src/codegen.cpp | 32 +--- src/dump.c | 30 ++-- src/intrinsics.cpp | 2 +- src/jltypes.c | 11 +- src/julia-syntax.scm | 46 ++---- src/julia.h | 21 ++- test/Makefile | 3 +- test/ccall.jl | 23 ++- test/ccalltest.c | 5 +- 23 files changed, 398 insertions(+), 344 deletions(-) create mode 100644 base/refpointer.jl diff --git a/.gitignore b/.gitignore index d3126887d0b12..ee3c038c0c5db 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ *.do *.o *.obj +*.so *.dylib *.dSYM *.jl.cov diff --git a/base/abstractarray.jl b/base/abstractarray.jl index becbe491695d9..b130367e3d8e8 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -47,6 +47,17 @@ else end end +# convert Arrays to pointer arrays for ccall +cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array{P}) = a +function cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array) + ptrs = Array(P, length(a)+1) + for i = 1:length(a) + ptrs[i] = convert(P, a[i]) + end + ptrs[length(a)+1] = C_NULL + return ptrs +end + size{T,n}(t::AbstractArray{T,n}, d) = d <= n ? size(t)[d] : 1 size(x, d1::Integer, d2::Integer, dx::Integer...) = tuple(size(x, d1), size(x, d2, dx...)...) eltype{T}(::Type{AbstractArray{T}}) = T diff --git a/base/base.jl b/base/base.jl index eecfcfdcc7399..0aab4f545d362 100644 --- a/base/base.jl +++ b/base/base.jl @@ -52,16 +52,12 @@ convert{T}(::Type{(T...)}, x::Tuple) = cnvt_all(T, x...) cnvt_all(T) = () cnvt_all(T, x, rest...) = tuple(convert(T,x), cnvt_all(T, rest...)...) - -ptr_arg_convert{T}(::Type{Ptr{T}}, x) = convert(T, x) -ptr_arg_convert(::Type{Ptr{Void}}, x) = x - -# conversion used by ccall -cconvert(T, x) = convert(T, x) -# use the code in ccall.cpp to safely allocate temporary pointer arrays -cconvert{T}(::Type{Ptr{Ptr{T}}}, a::Array) = a -# convert strings to ByteString to pass as pointers -cconvert{P<:Union(Int8,UInt8)}(::Type{Ptr{P}}, s::AbstractString) = bytestring(s) +# conversions used by ccall +ptr_arg_cconvert_gcroot{T}(::Type{Ptr{T}}, x) = cconvert_gcroot(T, x) +ptr_arg_cconvert{T}(::Type{Ptr{T}}, x) = cconvert(T, x) +ptr_arg_cconvert(::Type{Ptr{Void}}, x) = x +cconvert_gcroot(T, x) = x +cconvert(T, x) = convert(T,x) reinterpret{T,S}(::Type{T}, x::S) = box(T,unbox(S,x)) diff --git a/base/boot.jl b/base/boot.jl index 686aea13b16f6..019c045811777 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -73,7 +73,8 @@ # contents::T #end -#bitstype {32|64} Ptr{T} +#abstract Ref{T} +#bitstype {32|64} Ptr{T} <: Ref{T} # types for the front end @@ -125,7 +126,7 @@ export Module, Symbol, Task, Array, GenSym, # numeric types Bool, FloatingPoint, Float16, Float32, Float64, Number, Integer, Int, Int8, Int16, - Int32, Int64, Int128, Ptr, Real, Signed, UInt, UInt8, UInt16, UInt32, + Int32, Int64, Int128, Ref, Ptr, Real, Signed, UInt, UInt8, UInt16, UInt32, UInt64, UInt128, Unsigned, # string types Char, ASCIIString, ByteString, DirectIndexString, AbstractString, UTF8String, diff --git a/base/inference.jl b/base/inference.jl index 35e8add58da5d..2509413eee054 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -112,7 +112,20 @@ t_func[fpiseq] = (2, 2, cmp_tfunc) t_func[fpislt] = (2, 2, cmp_tfunc) t_func[nan_dom_err] = (2, 2, (a, b)->a) t_func[eval(Core.Intrinsics,:ccall)] = - (3, Inf, (fptr, rt, at, a...)->(isType(rt) ? rt.parameters[1] : Any)) + (3, Inf, function(fptr, rt, at, a...) + if !isType(rt) + return Any + end + t = rt.parameters[1] + if isa(t,DataType) && is((t::DataType).name,Ref.name) + t = t.parameters[1] + if is(t,Any) + return Union() # a return type of Box{Any} is invalid + end + return t + end + return t + end) t_func[eval(Core.Intrinsics,:llvmcall)] = (3, Inf, (fptr, rt, at, a...)->(isType(rt) ? rt.parameters[1] : isa(rt,Tuple) ? map(x->x.parameters[1],rt) : Any)) diff --git a/base/pcre.jl b/base/pcre.jl index 55935b98e895e..30abd8f148a08 100644 --- a/base/pcre.jl +++ b/base/pcre.jl @@ -57,7 +57,7 @@ function info{T}( regex::Ptr{Void}, extra::Ptr{Void}, what::Integer, ::Type{T} ) - buf = Array(UInt8,sizeof(T)) + buf = zeros(UInt8,sizeof(T)) ret = ccall((:pcre_fullinfo, :libpcre), Int32, (Ptr{Void}, Ptr{Void}, Int32, Ptr{UInt8}), regex, extra, what, buf) @@ -71,7 +71,7 @@ function info{T}( end function config{T}(what::Integer, ::Type{T}) - buf = Array(UInt8, sizeof(T)) + buf = zeros(UInt8, sizeof(T)) ret = ccall((:pcre_config, :libpcre), Int32, (Int32, Ptr{UInt8}), what, buf) @@ -84,7 +84,8 @@ end function compile(pattern::AbstractString, options::Integer) errstr = Array(Ptr{UInt8},1) - erroff = Array(Int32,1) + errstr[1] = C_NULL + erroff = zeros(Int32,1) re_ptr = ccall((:pcre_compile, :libpcre), Ptr{Void}, (Ptr{UInt8}, Int32, Ptr{Ptr{UInt8}}, Ptr{Int32}, Ptr{UInt8}), pattern, options, errstr, erroff, C_NULL) @@ -100,6 +101,7 @@ end function study(regex::Ptr{Void}, options::Integer) # NOTE: options should always be zero in current PCRE errstr = Array(Ptr{UInt8},1) + errstr[1] = C_NULL extra = ccall((:pcre_study, :libpcre), Ptr{Void}, (Ptr{Void}, Int32, Ptr{Ptr{UInt8}}), regex, options, errstr) diff --git a/base/pointer.jl b/base/pointer.jl index e94c43a3c7ff2..78f42983bebcb 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -19,16 +19,13 @@ convert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any convert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x) convert(::Type{Ptr{UInt8}}, s::ByteString) = convert(Ptr{UInt8}, s.data) convert(::Type{Ptr{Int8}}, s::ByteString) = convert(Ptr{Int8}, s.data) +# convert strings to ByteString to pass as pointers +cconvert_gcroot(::Type{Ptr{UInt8}}, s::AbstractString) = bytestring(s) +cconvert_gcroot(::Type{Ptr{Int8}}, s::AbstractString) = bytestring(s) convert{T}(::Type{Ptr{T}}, a::Array{T}) = ccall(:jl_array_ptr, Ptr{T}, (Any,), a) convert(::Type{Ptr{Void}}, a::Array) = ccall(:jl_array_ptr, Ptr{Void}, (Any,), a) -# note: these definitions don't mean any AbstractArray is convertible to -# pointer. they just map the array element type to the pointer type for -# convenience in cases that work. -pointer{T}(x::AbstractArray{T}) = convert(Ptr{T},x) -pointer{T}(x::AbstractArray{T}, i::Integer) = convert(Ptr{T},x) + (i-1)*elsize(x) - # unsafe pointer to array conversions pointer_to_array(p, d::Integer, own=false) = pointer_to_array(p, (d,), own) function pointer_to_array{T,N}(p::Ptr{T}, dims::NTuple{N,Int}, own::Bool=false) @@ -53,7 +50,8 @@ unsafe_store!{T}(p::Ptr{T}, x) = pointerset(p, convert(T,x), 1) # convert a raw Ptr to an object reference, and vice-versa unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Void},), x) -pointer_from_objref(x::Any) = ccall(:jl_value_ptr, Ptr{Void}, (Any,), x) +pointer_from_objref(x::ANY) = ccall(:jl_value_ptr, Ptr{Void}, (Any,), x) +data_pointer_from_objref(x::ANY) = pointer_from_objref(x)::Ptr{Void}+Core.sizeof(Int) integer(x::Ptr) = convert(UInt, x) unsigned(x::Ptr) = convert(UInt, x) diff --git a/base/refpointer.jl b/base/refpointer.jl new file mode 100644 index 0000000000000..876093c7248df --- /dev/null +++ b/base/refpointer.jl @@ -0,0 +1,121 @@ +### General Methods for Ref{T} type + +Base.eltype{T}(x::Type{Ref{T}}) = T +Base.convert{T}(::Type{Ref{T}}, x::Ref{T}) = x + +# create Ref objects for general object conversion +@inline Base.cconvert_gcroot{T}(::Type{Ref{T}}, x) = convert(Ref{T}, x) +@inline Base.cconvert{T}(::Type{Ref{T}}, x) = convert(Ptr{T}, x) + +### Methods for a Ref object that can store a single value + +type RefValue{T} <: Ref{T} + x::T + RefValue() = new() + RefValue(x) = new(x) +end +Base.convert{T}(::Type{Ref{T}}, x) = RefValue{T}(x) +Base.call{T}(::Type{Ref{T}}) = RefValue{T}() + +Ref(x::Ref) = x +Ref{T}(x::T) = RefValue{T}(x) +Ref{T}(x::Ptr{T}, i::Integer=1) = x + (i-1)*Core.sizeof(T) +Ref(x, i::Integer) = (i != 1 && error("Object only has one element"); Ref(x)) + +@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefValue{T}) + if isbits(T) + return convert(P, data_pointer_from_objref(b)) + else + return convert(P, data_pointer_from_objref(b.x)) + end +end +@inline function Base.convert(P::Type{Ptr{Any}}, b::RefValue{Any}) + return convert(P, data_pointer_from_objref(b)) +end +@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefValue{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) + +### Methods for a Ref object that is backed by an array at index i + +# note: the following type definitions don't mean any AbstractArray is convertible to +# a data Ref. they just map the array element type to the pointer type for +# convenience in cases that work. +pointer{T}(x::AbstractArray{T}) = convert(Ptr{T},x) +pointer{T}(x::AbstractArray{T}, i::Integer) = convert(Ptr{T},x) + (i-1)*elsize(x) + +immutable RefArray{T, A<:AbstractArray} <: Ref{T} + x::A + i::Int + RefArray(x,i) = (@assert(eltype(A) == T); new(x,i)) +end +convert{T}(::Type{Ref{T}}, x::AbstractArray{T}) = RefArray{T,typeof(x)}(x, 1) +Ref{T}(x::AbstractArray{T}, i::Integer=1) = RefArray{T,typeof(x)}(x, i) + +@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefArray{T}) + if isbits(T) + convert(P, pointer(b.x, b.i)) + else + convert(P, data_pointer_from_objref(b.x[b.i])) + end +end +@inline function Base.convert(P::Type{Ptr{Any}}, b::RefArray{Any}) + return convert(P, pointer(b.x, b.i)) +end +@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefArray{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) + +### Methods for a Ref object that is backed by an array at index (i...) + +immutable RefArrayND{T, A<:AbstractArray} <: Ref{T} + x::A + i::(Int...) + RefArrayND(x,i) = (@assert(eltype(A) == T); new(x,i)) +end +Ref{A<:AbstractArray}(x::A, i::Integer...) = RefArrayND{eltype(A),A}(x, i) +Ref{A<:AbstractArray}(x::A, i::(Integer...)) = RefArrayND{eltype(A),A}(x, i) + +@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefArrayND{T}) + if isbits(T) + convert(P, pointer(b.x, b.i...)) + else + convert(P, data_pointer_from_objref(b.x[b.i...])) + end +end +@inline function Base.convert(P::Type{Ptr{Any}}, b::RefArrayND{Any}) + return convert(P, pointer(b.x, b.i...)) +end +@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefArrayND{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) + +### Methods for a Ref object that is backed by an array at index (Any...) + +immutable RefArrayI{T} <: Ref{T} + x::AbstractArray{T} + i::Tuple + RefArrayI(x,i::ANY) = (@assert(eltype(A) == T); new(x,i)) +end +Ref{T}(x::AbstractArray{T}, i...) = RefArrayI{T}(x, i) +Ref{T}(x::AbstractArray{T}, i::Tuple) = RefArrayI{T}(x, i) + +@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefArrayI{T}) + if isbits(T) + convert(P, pointer(b.x, b.i...)) + else + convert(P, data_pointer_from_objref(b.x[b.i...])) + end +end +@inline function Base.convert(P::Type{Ptr{Any}}, b::RefArrayI{Any}) + return convert(P, pointer(b.x, b.i...)) +end +@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefArrayI{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) + +### + +Base.getindex(b::RefValue) = b.x +Base.getindex(b::RefArray) = b.x[b.i] +Base.getindex(b::RefArrayND) = b.x[b.i...] +Base.getindex(b::RefArrayI) = b.x[b.i...] + +Base.setindex!(b::RefValue, x) = (b.x = x; b) +Base.setindex!(b::RefArray, x) = (b.x[b.i] = x; b) +Base.setindex!(b::RefArrayND, x) = (b.x[b.i...] = x; b) +Base.setindex!(b::RefArrayI, x) = (b.x[b.i...] = x; b) + +### diff --git a/base/socket.jl b/base/socket.jl index ed76f649dc81d..24bb3b4e35073 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -593,7 +593,8 @@ const _sizeof_uv_interface_address = ccall(:jl_uv_sizeof_interface_address,Int32 function getipaddr() addr = Array(Ptr{UInt8},1) - count = Array(Int32,1) + addr[1] = C_NULL + count = zeros(Int32,1) lo_present = false err = ccall(:jl_uv_interface_addresses,Int32,(Ptr{Ptr{UInt8}},Ptr{Int32}),addr,count) addr, count = addr[1],count[1] diff --git a/base/sysimg.jl b/base/sysimg.jl index 3b7577ee0496a..9c6ece84c568f 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -67,6 +67,7 @@ include("dict.jl") include("set.jl") include("hashing.jl") include("iterator.jl") +include("refpointer.jl") #XXX: move this earlier when we don't need @inline annotations anymore # SIMD loops include("simdloop.jl") diff --git a/src/alloc.c b/src/alloc.c index 91fed046f4acf..c1bb50159036d 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -54,6 +54,7 @@ jl_datatype_t *jl_typeerror_type; jl_datatype_t *jl_methoderror_type; jl_datatype_t *jl_loaderror_type; jl_datatype_t *jl_undefvarerror_type; +jl_datatype_t *jl_ref_type; jl_datatype_t *jl_pointer_type; jl_datatype_t *jl_void_type; jl_datatype_t *jl_voidpointer_type; diff --git a/src/builtins.c b/src/builtins.c index 3ab3d2728dc4b..8da6f06c693b0 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1156,6 +1156,7 @@ void jl_init_primitives(void) add_builtin("IntrinsicFunction", (jl_value_t*)jl_intrinsic_type); add_builtin("Function", (jl_value_t*)jl_function_type); add_builtin("LambdaStaticData", (jl_value_t*)jl_lambda_info_type); + add_builtin("Ref", (jl_value_t*)jl_ref_type); add_builtin("Ptr", (jl_value_t*)jl_pointer_type); add_builtin("Box", (jl_value_t*)jl_box_type); add_builtin("Task", (jl_value_t*)jl_task_type); diff --git a/src/ccall.cpp b/src/ccall.cpp index 3a1eaf7f12642..50ceb0071626e 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -217,141 +217,21 @@ static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_na llvmf = builder.CreateLoad(llvmgv); return builder.CreatePointerCast(llvmf,funcptype); } -// --- argument passing and scratch space utilities --- - -static Function *value_to_pointer_func; - -// TODO: per-thread -static char *temp_arg_area; -static const uint32_t arg_area_sz = 4196; -static uint32_t arg_area_loc; -#define N_TEMP_ARG_BLOCKS 1024 -static void *temp_arg_blocks[N_TEMP_ARG_BLOCKS]; -static uint32_t arg_block_n = 0; -static Function *save_arg_area_loc_func; -static Function *restore_arg_area_loc_func; - -extern "C" DLLEXPORT uint64_t save_arg_area_loc() -{ - return (((uint64_t)arg_block_n)<<32) | ((uint64_t)arg_area_loc); -} - -extern "C" DLLEXPORT void restore_arg_area_loc(uint64_t l) -{ - arg_area_loc = l&0xffffffff; - uint32_t ab = l>>32; - while (arg_block_n > ab) { - arg_block_n--; - free(temp_arg_blocks[arg_block_n]); - } -} - -static void *alloc_temp_arg_space(uint32_t sz) -{ - void *p; - if (arg_area_loc+sz > arg_area_sz) { -#ifdef JL_GC_MARKSWEEP - if (arg_block_n >= N_TEMP_ARG_BLOCKS) - jl_error("internal compiler error: out of temporary argument space in ccall"); - p = malloc(sz); - temp_arg_blocks[arg_block_n++] = p; -#else -#error "fixme" -#endif - } - else { - p = &temp_arg_area[arg_area_loc]; - arg_area_loc += sz; - } - return p; -} - -static void *alloc_temp_arg_copy(void *obj, uint32_t sz) -{ - void *p = alloc_temp_arg_space(sz); - memcpy(p, obj, sz); - return p; -} - -// this is a run-time function -// warning: cannot allocate memory except using alloc_temp_arg_space -extern "C" DLLEXPORT void *jl_value_to_pointer(jl_value_t *jt, jl_value_t *v, int argn, - int addressof) -{ - jl_value_t *jvt = (jl_value_t*)jl_typeof(v); - if (addressof) { - if (jvt == jt) { - if (jl_is_bitstype(jvt)) { - size_t osz = jl_datatype_size(jt); - return alloc_temp_arg_copy(jl_data_ptr(v), osz); - } - else if (!jl_is_tuple(jvt) && jl_is_leaf_type(jvt) && !jl_is_array_type(jvt)) { - return v + 1; - } - } - goto value_to_pointer_error; - } - else { - if (jl_is_cpointer_type(jvt) && jl_tparam0(jvt) == jt) { - return (void*)jl_unbox_voidpointer(v); - } - } - - if (((jl_value_t*)jl_uint8_type == jt || - (jl_value_t*)jl_int8_type == jt) && jl_is_byte_string(v)) { - return jl_string_data(v); - } - if (jl_is_array_type(jvt)) { - if (jl_tparam0(jl_typeof(v)) == jt || jt == (jl_value_t*)jl_bottom_type || - jt == (jl_value_t*)jl_void_type) { - return ((jl_array_t*)v)->data; - } - if (jl_is_cpointer_type(jt)) { - jl_array_t *ar = (jl_array_t*)v; - void **temp=(void**)alloc_temp_arg_space((1+jl_array_len(ar))*sizeof(void*)); - size_t i; - for(i=0; i < jl_array_len(ar); i++) { - temp[i] = jl_value_to_pointer(jl_tparam0(jt), - jl_arrayref(ar, i), argn, 0); - } - temp[i] = 0; - return temp; - } - } - - value_to_pointer_error: - std::map::iterator it = argNumberStrings.find(argn); - if (it == argNumberStrings.end()) { - std::stringstream msg; - msg << "argument "; - msg << argn; - argNumberStrings[argn] = msg.str(); - it = argNumberStrings.find(argn); - } - jl_value_t *targ=NULL, *pty=NULL; - JL_GC_PUSH2(&targ, &pty); - targ = (jl_value_t*)jl_tuple1(jt); - pty = (jl_value_t*)jl_apply_type((jl_value_t*)jl_pointer_type, - (jl_tuple_t*)targ); - jl_type_error_rt("ccall", (*it).second.c_str(), pty, v); - // doesn't return - return (jl_value_t*)jl_null; -} static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, jl_value_t *argex, bool addressOf, int argn, jl_codectx_t *ctx, - bool *mightNeedTempSpace, bool *needStackRestore) + bool *needStackRestore) { Type *vt = jv->getType(); if (ty == jl_pvalue_llvmt) { return boxed(jv,ctx); } - else if (ty == vt && !addressOf) { + if (ty == vt && !addressOf) { return jv; } - else if (vt != jl_pvalue_llvmt) { - // argument value is unboxed + if (vt != jl_pvalue_llvmt) { + // argument value is passed unboxed if (addressOf) { if (ty->isPointerTy() && ty->getContainedType(0)==vt) { // pass the address of an alloca'd thing, not a box @@ -370,62 +250,83 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, return builder.CreateBitCast(jv, ty); } } - // error. box for error handling. - jv = boxed(jv,ctx); + emit_error("ccall: argument type did not match declaration", ctx); } - else if (jl_is_cpointer_type(jt)) { + if (jl_is_tuple(jt)) { + return emit_unbox(ty,jv,jt); + } + if (jl_is_cpointer_type(jt) && addressOf) { assert(ty->isPointerTy()); + jl_value_t *ety = jl_tparam0(jt); jl_value_t *aty = expr_type(argex, ctx); - if (jl_is_array_type(aty) && - (jl_tparam0(jt) == jl_tparam0(aty) || jl_tparam0(jt) == (jl_value_t*)jl_bottom_type || - jl_tparam0(jt) == (jl_value_t*)jl_void_type)) { - // array to pointer - return builder.CreateBitCast(emit_arrayptr(jv), ty); - } - if (aty == (jl_value_t*)jl_ascii_string_type || aty == (jl_value_t*)jl_utf8_string_type) { - return builder.CreateBitCast(emit_arrayptr(emit_nthptr(jv,1,tbaa_const)), ty); - } - if (jl_is_structtype(aty) && jl_is_leaf_type(aty) && !jl_is_array_type(aty)) { - if (!addressOf) { - emit_error("ccall: expected & on argument", ctx); - return literal_pointer_val(jl_nothing); - } - return builder.CreateBitCast(emit_nthptr_addr(jv, (size_t)1), ty); // skip type tag field - } - *mightNeedTempSpace = true; - Value *p = builder.CreateCall4(prepare_call(value_to_pointer_func), - literal_pointer_val(jl_tparam0(jt)), jv, - ConstantInt::get(T_int32, argn), - ConstantInt::get(T_int32, (int)addressOf)); - return builder.CreateBitCast(p, ty); - } - else if (jl_is_structtype(jt)) { - if (addressOf) - jl_error("ccall: unexpected & on argument"); // the only "safe" thing to emit here is the expected struct - assert (ty->isStructTy() && (Type*)((jl_datatype_t*)jt)->struct_decl == ty); - jl_value_t *aty = expr_type(argex, ctx); - if (aty != jt) { + if (aty != ety && ety != (jl_value_t*)jl_any_type && jt != (jl_value_t*)jl_voidpointer_type) { std::stringstream msg; msg << "ccall argument "; msg << argn; - emit_typecheck(jv, jt, msg.str(), ctx); + emit_typecheck(jv, ety, msg.str(), ctx); } - //TODO: check instead that prefix matches - //if (!jl_is_structtype(aty)) - // emit_typecheck(emit_typeof(jv), (jl_value_t*)jl_struct_kind, "ccall: Struct argument called with something that isn't a struct", ctx); - // //safe thing would be to also check that jl_typeof(aty)->size > sizeof(ty) here and/or at runtime - Value *pjv = builder.CreateBitCast(emit_nthptr_addr(jv, (size_t)1), PointerType::get(ty,0)); - return builder.CreateLoad(pjv, false); - } - else if (jl_is_tuple(jt)) { - return emit_unbox(ty,jv,jt); + if (jl_is_mutable_datatype(ety)) { + // no copy, just reference the data field + return builder.CreateBitCast(emit_nthptr_addr(jv, (size_t)1), ty); // skip type tag field + } + else if (jl_is_immutable_datatype(ety) && jt != (jl_value_t*)jl_voidpointer_type) { + // yes copy + Value *nbytes; + if (jl_is_leaf_type(ety)) + nbytes = ConstantInt::get(T_int32, jl_datatype_size(ety)); + else + nbytes = tbaa_decorate(tbaa_datatype, builder.CreateLoad( + builder.CreateGEP(builder.CreatePointerCast(emit_typeof(jv), T_pint32), + ConstantInt::get(T_size, offsetof(jl_datatype_t,size)/4)), + false)); + *needStackRestore = true; + AllocaInst *ai = builder.CreateAlloca(T_int8, nbytes); + ai->setAlignment(16); + builder.CreateMemCpy(ai, builder.CreateBitCast(emit_nthptr_addr(jv, (size_t)1), T_pint8), nbytes, 1); + return builder.CreateBitCast(ai, ty); + } + // emit maybe copy + *needStackRestore = true; + Value *jvt = emit_typeof(jv); + BasicBlock *mutableBB = BasicBlock::Create(getGlobalContext(),"is-mutable",ctx->f); + BasicBlock *immutableBB = BasicBlock::Create(getGlobalContext(),"is-immutable",ctx->f); + BasicBlock *afterBB = BasicBlock::Create(getGlobalContext(),"after",ctx->f); + Value *ismutable = builder.CreateTrunc( + tbaa_decorate(tbaa_datatype, builder.CreateLoad( + builder.CreateGEP(builder.CreatePointerCast(jvt, T_pint8), + ConstantInt::get(T_size, offsetof(jl_datatype_t,mutabl))), + false)), + T_int1); + builder.CreateCondBr(ismutable, mutableBB, immutableBB); + builder.SetInsertPoint(mutableBB); + Value *p1 = builder.CreatePointerCast(emit_nthptr_addr(jv, (size_t)1), ty); // skip type tag field + builder.CreateBr(afterBB); + builder.SetInsertPoint(immutableBB); + Value *nbytes = tbaa_decorate(tbaa_datatype, builder.CreateLoad( + builder.CreateGEP(builder.CreatePointerCast(jvt, T_pint32), + ConstantInt::get(T_size, offsetof(jl_datatype_t,size)/4)), + false)); + AllocaInst *ai = builder.CreateAlloca(T_int8, nbytes); + ai->setAlignment(16); + builder.CreateMemCpy(ai, builder.CreatePointerCast(emit_nthptr_addr(jv, (size_t)1), T_pint8), nbytes, 1); + Value *p2 = builder.CreatePointerCast(ai, ty); + builder.CreateBr(afterBB); + builder.SetInsertPoint(afterBB); + PHINode *p = builder.CreatePHI(ty, 2); + p->addIncoming(p1, mutableBB); + p->addIncoming(p2, immutableBB); + return p; + } + if (addressOf) + jl_error("ccall: unexpected & on argument"); // the only "safe" thing to emit here is the expected struct + assert(jl_is_datatype(jt)); + jl_value_t *aty = expr_type(argex, ctx); + if (aty != jt) { + std::stringstream msg; + msg << "ccall argument "; + msg << argn; + emit_typecheck(jv, jt, msg.str(), ctx); } - // TODO: error for & with non-pointer argument type - assert(jl_is_bitstype(jt)); - std::stringstream msg; - msg << "ccall argument "; - msg << argn; - emit_typecheck(jv, jt, msg.str(), ctx); Value *p = data_pointer(jv); return builder.CreateLoad(builder.CreateBitCast(p, PointerType::get(ty,0)), @@ -691,7 +592,7 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) } #endif bool mightNeedTempSpace = false; - argvals[i] = julia_to_native(t,tti,arg,argi,false,i,ctx,&mightNeedTempSpace,&mightNeedTempSpace); + argvals[i] = julia_to_native(t,tti,arg,argi,false,i,ctx,&mightNeedTempSpace); } Function *f; @@ -869,8 +770,14 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) ": ccall: missing return type"; jl_error(msg.c_str()); } - if (rt == (jl_value_t*)jl_pointer_type) - jl_error("ccall: return type Ptr should have an element type, Ptr{T}"); + if (jl_is_cpointer_type(rt) && jl_is_typevar(jl_tparam0(rt))) + jl_error("ccall: return type Ptr should have an element type, not Ptr{_<:T}"); + + if (jl_is_abstract_ref_type(rt)) { + if (jl_tparam0(rt) == (jl_value_t*)jl_any_type) + jl_error("ccall: return type Box{Any} is invalid. use Ptr{Any} instead."); + rt = (jl_value_t*)jl_any_type; // convert return type to jl_value_t* + } JL_TYPECHK(ccall, type, rt); Type *lrt = julia_struct_to_llvm(rt); @@ -916,54 +823,65 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) paramattrs.push_back(AttrBuilder()); #endif jl_value_t *tti = jl_tupleref(tt,i); - if (tti == (jl_value_t*)jl_pointer_type) - jl_error("ccall: argument type Ptr should have an element type, Ptr{T}"); + if (jl_is_vararg_type(tti)) { isVa = true; tti = jl_tparam0(tti); } - if (jl_is_bitstype(tti)) { - // see pull req #978. need to annotate signext/zeroext for - // small integer arguments. - jl_datatype_t *bt = (jl_datatype_t*)tti; - if (bt->size < 4) { - if (jl_signed_type == NULL) { - jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed")); - } + + Type *t = NULL; + if (jl_is_abstract_ref_type(tti)) { + tti = jl_tparam0(tti); + if (jl_is_typevar(tti)) + jl_error("ccall: argument type Ref should have an element type, not Ref{_<:T}"); + t = T_pint8; + } + else { + if (jl_is_cpointer_type(tti) && jl_is_typevar(jl_tparam0(tti))) + jl_error("ccall: argument type Ptr should have an element type, not Ptr{_<:T}"); + if (jl_is_bitstype(tti)) { + // see pull req #978. need to annotate signext/zeroext for + // small integer arguments. + jl_datatype_t *bt = (jl_datatype_t*)tti; + if (bt->size < 4) { + if (jl_signed_type == NULL) { + jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed")); + } #if LLVM33 - Attribute::AttrKind av; + Attribute::AttrKind av; #elif LLVM32 - Attributes::AttrVal av; + Attributes::AttrVal av; #else - Attribute::AttrConst av; + Attribute::AttrConst av; #endif #if LLVM32 && !LLVM33 - if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) - av = Attributes::SExt; - else - av = Attributes::ZExt; + if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) + av = Attributes::SExt; + else + av = Attributes::ZExt; #else - if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) - av = Attribute::SExt; - else - av = Attribute::ZExt; + if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) + av = Attribute::SExt; + else + av = Attribute::ZExt; #endif #if LLVM32 || LLVM33 - paramattrs[i+sret].addAttribute(av); + paramattrs[i+sret].addAttribute(av); #else - attrs.push_back(AttributeWithIndex::get(i+1+sret, av)); + attrs.push_back(AttributeWithIndex::get(i+1+sret, av)); #endif + } + } + t = julia_struct_to_llvm(tti); + if (t == NULL || t == T_void) { + JL_GC_POP(); + std::stringstream msg; + msg << "ccall: the type of argument "; + msg << i+1; + msg << " doesn't correspond to a C type"; + emit_error(msg.str(), ctx); + return literal_pointer_val(jl_nothing); } - } - Type *t = julia_struct_to_llvm(tti); - if (t == NULL || t == T_void) { - JL_GC_POP(); - std::stringstream msg; - msg << "ccall: the type of argument "; - msg << i+1; - msg << " doesn't correspond to a C type"; - emit_error(msg.str(), ctx); - return literal_pointer_val(jl_nothing); } fargt.push_back(t); if (!isVa) @@ -1019,6 +937,9 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); + } else if (jl_is_abstract_ref_type(jl_tupleref(tt,0))) { + if (!jl_is_cpointer_type(expr_type(argi, 0))) + addressOf = true; } Value *ary; Type *largty = fargt[0]; @@ -1045,7 +966,6 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) // save place before arguments, for possible insertion of temp arg // area saving code. - Value *saveloc=NULL; Value *stacksave=NULL; BasicBlock::InstListType &instList = builder.GetInsertBlock()->getInstList(); Instruction *savespot; @@ -1076,8 +996,6 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) fargt_sig[0]); } int last_depth = ctx->argDepth; - int nargty = jl_tuple_len(tt); - bool needTempSpace = false; bool needStackRestore = false; for(i=4; i < nargs+1; i+=2) { size_t ai = (i-4)/2; @@ -1099,7 +1017,17 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) } Value *arg; bool needroot = false; - if (largty == jl_pvalue_llvmt || largty->isStructTy()) { + if (jl_is_abstract_ref_type(jargty)) { + arg = emit_unboxed((jl_value_t*)argi, ctx); + if (arg->getType() == jl_pvalue_llvmt) { + emit_cpointercheck(arg, "ccall: argument to Ref{T} is not a pointer", ctx); + arg = emit_unbox(largty, arg, (jl_value_t*)jl_voidpointer_type); + } + if (arg->getType() != T_pint8) + arg = builder.CreatePointerCast(arg, T_pint8); + jargty = (jl_value_t*)jl_voidpointer_type; + } + else if (largty == jl_pvalue_llvmt || largty->isStructTy()) { arg = emit_expr(argi, ctx, true); if (largty == jl_pvalue_llvmt && arg->getType() != jl_pvalue_llvmt) { arg = boxed(arg,ctx); @@ -1129,11 +1057,9 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) } #endif - bool mightNeed=false; bool nSR=false; argvals[ai+sret] = julia_to_native(largty, jargty, arg, argi, addressOf, - ai+1, ctx, &mightNeed, &nSR); - needTempSpace |= mightNeed; + ai+1, ctx, &nSR); needStackRestore |= nSR; } @@ -1185,16 +1111,6 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) } } - if (needTempSpace) { - // save temp argument area stack pointer - // TODO: inline this - saveloc = CallInst::Create(prepare_call(save_arg_area_loc_func)); - if (savespot) - instList.insertAfter(savespot, (Instruction*)saveloc); - else - instList.push_front((Instruction*)saveloc); - savespot = (Instruction*)saveloc; - } if (needStackRestore) { stacksave = CallInst::Create(Intrinsic::getDeclaration(jl_Module, Intrinsic::stacksave)); @@ -1234,11 +1150,6 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) Intrinsic::stackrestore), stacksave); } - if (needTempSpace) { - // restore temp argument area stack pointer - assert(saveloc != NULL); - builder.CreateCall(prepare_call(restore_arg_area_loc_func), saveloc); - } ctx->argDepth = last_depth; if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall #if LLVM32 && !LLVM33 diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 2e71c660c599e..a13f62c099ae9 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -547,7 +547,7 @@ DLLEXPORT Type *julia_type_to_llvm(jl_value_t *jt) if (lt == NULL) return NULL; if (lt == T_void) - lt = T_int8; + return T_pint8; return PointerType::get(lt, 0); } if (jl_is_bitstype(jt)) { @@ -1552,6 +1552,7 @@ static Value *init_bits_value(Value *newv, Value *jt, Type *t, Value *v) // allocate a box where the type might not be known at compile time static Value *allocate_box_dynamic(Value *jlty, Value *nb, Value *v) { + // TODO: allocate on the stack if !envescapes if (v->getType()->isPointerTy()) { v = builder.CreatePtrToInt(v, T_size); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 2b372ef1485d8..b51bfc531ae1a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4274,7 +4274,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) builder.CreateAlloca(T_int8, ConstantInt::get(T_int32, sizeof(jl_handler_t))); - handlr->setAlignment(128); // bits == 16 bytes + handlr->setAlignment(16); handlers[labl] = handlr; } } @@ -5466,36 +5466,6 @@ extern "C" void jl_init_codegen(void) box64_func = boxfunc_llvm(ft2arg(jl_pvalue_llvmt, jl_pvalue_llvmt, T_int64), "jl_box64", (void*)&jl_box64, m); - std::vector toptrargs(0); - toptrargs.push_back(jl_pvalue_llvmt); - toptrargs.push_back(jl_pvalue_llvmt); - toptrargs.push_back(T_int32); - toptrargs.push_back(T_int32); - value_to_pointer_func = - Function::Create(FunctionType::get(T_pint8, toptrargs, false), - Function::ExternalLinkage, "jl_value_to_pointer", - m); - add_named_global(value_to_pointer_func, - (void*)&jl_value_to_pointer); - - temp_arg_area = (char*)malloc(arg_area_sz); - arg_area_loc = 0; - - std::vector noargs(0); - save_arg_area_loc_func = - Function::Create(FunctionType::get(T_uint64, noargs, false), - Function::ExternalLinkage, "save_arg_area_loc", - m); - add_named_global(save_arg_area_loc_func, - (void*)&save_arg_area_loc); - - restore_arg_area_loc_func = - Function::Create(ft1arg(T_void, T_uint64), - Function::ExternalLinkage, "restore_arg_area_loc", - m); - add_named_global(restore_arg_area_loc_func, - (void*)&restore_arg_area_loc); - typeToTypeId = jl_alloc_cell_1d(16); } diff --git a/src/dump.c b/src/dump.c index 645efba41e3c9..c2ba79fdb7a86 100644 --- a/src/dump.c +++ b/src/dump.c @@ -904,9 +904,9 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc) dt->super = (jl_datatype_t*)jl_deserialize_value(s, (jl_value_t**)&dt->super); gc_wb(dt, dt->super); if (datatype_list) { - if (dt->name == jl_array_type->name || dt->name == jl_pointer_type->name || - dt->name == jl_type_type->name || dt->name == jl_vararg_type->name || - dt->name == jl_abstractarray_type->name || + if (dt->name == jl_array_type->name || dt->name == jl_ref_type->name || + dt->name == jl_pointer_type->name || dt->name == jl_type_type->name || + dt->name == jl_vararg_type->name || dt->name == jl_abstractarray_type->name || dt->name == jl_densearray_type->name) { // builtin types are not serialized, so their caches aren't // explicitly saved. so we reconstruct the caches of builtin @@ -1843,17 +1843,19 @@ void jl_init_serializer(void) jl_box_int64(48), jl_box_int64(49), jl_box_int64(50), jl_box_int64(51), jl_box_int64(52), jl_box_int64(53), #endif - jl_labelnode_type, jl_linenumbernode_type, jl_gotonode_type, - jl_quotenode_type, jl_topnode_type, jl_type_type, jl_bottom_type, - jl_pointer_type, jl_vararg_type, jl_ntuple_type, - jl_abstractarray_type, jl_densearray_type, jl_box_type, jl_void_type, - jl_typector_type, jl_typename_type, jl_task_type, jl_uniontype_type, - jl_typetype_type, jl_typetype_tvar, jl_ANY_flag, jl_array_any_type, - jl_intrinsic_type, jl_method_type, jl_methtable_type, - jl_voidpointer_type, jl_newvarnode_type, jl_array_symbol_type, - jl_tupleref(jl_tuple_type,0), - - jl_symbol_type->name, jl_gensym_type->name, jl_pointer_type->name, + jl_labelnode_type, jl_linenumbernode_type, + jl_gotonode_type, jl_quotenode_type, jl_topnode_type, + jl_type_type, jl_bottom_type, jl_ref_type, jl_pointer_type, + jl_vararg_type, jl_ntuple_type, jl_abstractarray_type, + jl_densearray_type, jl_box_type, jl_void_type, + jl_typector_type, jl_typename_type, + jl_task_type, jl_uniontype_type, jl_typetype_type, jl_typetype_tvar, + jl_ANY_flag, jl_array_any_type, jl_intrinsic_type, jl_method_type, + jl_methtable_type, jl_voidpointer_type, jl_newvarnode_type, + jl_array_symbol_type, jl_tupleref(jl_tuple_type,0), + + jl_symbol_type->name, jl_gensym_type->name, + jl_ref_type->name, jl_pointer_type->name, jl_datatype_type->name, jl_uniontype_type->name, jl_array_type->name, jl_expr_type->name, jl_typename_type->name, jl_type_type->name, jl_methtable_type->name, jl_method_type->name, jl_tvar_type->name, diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 3faefc5f35e04..7813b5d4f9cc4 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -162,7 +162,7 @@ static Constant *julia_const_to_llvm(jl_value_t *e) // If we have a floating point type that's not hardware supported, just treat it like an integer for LLVM purposes } Constant *asInt = ConstantInt::get(IntegerType::get(jl_LLVMContext,8*nb),val); - if (jl_is_cpointer_type(bt)) { + if (jl_is_cpointer_type(jt)) { return ConstantExpr::getIntToPtr(asInt, julia_type_to_llvm((jl_value_t*)bt)); } return asInt; diff --git a/src/jltypes.c b/src/jltypes.c index 450dc5c8c3d39..17f994d64711a 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3281,22 +3281,27 @@ void jl_init_types(void) jl_intrinsic_type = jl_new_bitstype((jl_value_t*)jl_symbol("IntrinsicFunction"), jl_any_type, jl_null, 32); + tv = jl_tuple1(tvar("T")); + jl_ref_type = + jl_new_abstracttype((jl_value_t*)jl_symbol("Ref"), jl_any_type, tv); + tv = jl_tuple1(tvar("T")); jl_pointer_type = - jl_new_bitstype((jl_value_t*)jl_symbol("Ptr"), jl_any_type, tv, + jl_new_bitstype((jl_value_t*)jl_symbol("Ptr"), + (jl_datatype_t*)jl_apply_type((jl_value_t*)jl_ref_type, tv), tv, sizeof(void*)*8); // Type{T} jl_typetype_tvar = jl_new_typevar(jl_symbol("T"), (jl_value_t*)jl_bottom_type,(jl_value_t*)jl_any_type); jl_typetype_type = (jl_datatype_t*)jl_apply_type((jl_value_t*)jl_type_type, - jl_tuple(1,jl_typetype_tvar)); + jl_tuple1(jl_typetype_tvar)); jl_ANY_flag = (jl_value_t*)tvar("ANY"); // complete builtin type metadata jl_value_t *pointer_void = jl_apply_type((jl_value_t*)jl_pointer_type, - jl_tuple(1,jl_void_type)); + jl_tuple1(jl_void_type)); jl_voidpointer_type = (jl_datatype_t*)pointer_void; jl_tupleset(jl_datatype_type->types, 6, jl_int32_type); jl_tupleset(jl_datatype_type->types, 7, (jl_value_t*)jl_bool_type); diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index c95a3bfeb1ac8..33d313165de60 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -994,20 +994,6 @@ ;; insert calls to convert() in ccall, and pull out expressions that might ;; need to be rooted before conversion. (define (lower-ccall name RT atypes args) - (define (ccall-conversion T x) - (cond ((eq? T 'Any) x) - ((and (pair? x) (eq? (car x) '&)) - `(& (call (top ptr_arg_convert) ,T ,(cadr x)))) - (else - `(call (top cconvert) ,T ,x)))) - (define (argument-root a) - ;; something to keep rooted for this argument - (cond ((and (pair? a) (eq? (car a) '&)) - (argument-root (cadr a))) - ((and (pair? a) (sym-dot? a)) - (cadr a)) - ((symbol-like? a) a) - (else 0))) (let loop ((F atypes) ;; formals (A args) ;; actuals (stmts '()) ;; initializers @@ -1019,28 +1005,16 @@ ,@A)) (let* ((a (car A)) (isseq (and (pair? (car F)) (eq? (caar F) '...))) - (ty (if isseq (cadar F) (car F))) - (rt (if (eq? ty 'Any) - 0 - (argument-root a))) - (ca (cond ((eq? ty 'Any) - a) - ((and (pair? a) (eq? (car a) '&)) - (if (and (pair? (cadr a)) (not (sym-dot? (cadr a)))) - (let ((g (make-jlgensym))) - (begin - (set! stmts (cons `(= ,g ,(cadr a)) stmts)) - `(& ,g))) - a)) - ((and (pair? a) (not (sym-dot? a)) (not (quoted? a))) - (let ((g (make-jlgensym))) - (begin - (set! stmts (cons `(= ,g ,a) stmts)) - g))) - (else - a)))) - (loop (if isseq F (cdr F)) (cdr A) stmts - (list* rt (ccall-conversion ty ca) C)))))) + (ty (if isseq (cadar F) (car F)))) + (if (eq? ty 'Any) + (loop (if isseq F (cdr F)) (cdr A) stmts (list* 0 a C)) + (let* ((g (make-jlgensym)) + (isamp (and (pair? a) (eq? (car a) '&))) + (a (if isamp (cadr a) a)) + (stmts (cons `(= ,g (call (top ,(if isamp 'ptr_arg_cconvert_gcroot 'cconvert_gcroot)) ,ty ,a)) stmts)) + (ca `(call (top ,(if isamp 'ptr_arg_cconvert 'cconvert)) ,ty ,g))) + (loop (if isseq F (cdr F)) (cdr A) stmts + (list* g (if isamp `(& ,ca) ca) C)))))))) (define (block-returns? e) (if (assignment? e) diff --git a/src/julia.h b/src/julia.h index 1c99eb8d4cc62..60cfb93acf2f9 100644 --- a/src/julia.h +++ b/src/julia.h @@ -367,6 +367,7 @@ extern DLLEXPORT jl_datatype_t *jl_number_type; extern DLLEXPORT jl_datatype_t *jl_void_type; extern DLLEXPORT jl_datatype_t *jl_voidpointer_type; extern DLLEXPORT jl_datatype_t *jl_pointer_type; +extern DLLEXPORT jl_datatype_t *jl_ref_type; extern DLLEXPORT jl_value_t *jl_array_uint8_type; extern DLLEXPORT jl_value_t *jl_array_any_type; @@ -646,12 +647,30 @@ STATIC_INLINE int jl_is_array(void *v) return jl_is_array_type(t); } -STATIC_INLINE int jl_is_cpointer_type(void *t) +STATIC_INLINE int jl_is_cpointer_type(jl_value_t *t) { return (jl_is_datatype(t) && ((jl_datatype_t*)(t))->name == jl_pointer_type->name); } +STATIC_INLINE int jl_is_abstract_ref_type(jl_value_t *t) +{ + return (jl_is_datatype(t) && + ((jl_datatype_t*)(t))->name == jl_ref_type->name); +} + +STATIC_INLINE jl_value_t *jl_is_ref_type(jl_value_t *t) +{ + if (!jl_is_datatype(t)) return 0; + jl_datatype_t *dt = (jl_datatype_t*)t; + while (dt != jl_any_type && dt->name != dt->super->name) { + if (dt->name == jl_ref_type->name) + return (jl_value_t*)dt; + dt = dt->super; + } + return 0; +} + STATIC_INLINE int jl_is_vararg_type(jl_value_t *v) { return (jl_is_datatype(v) && diff --git a/test/Makefile b/test/Makefile index 8c97294bc5bc1..f83b90bffff5b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,7 +5,7 @@ TESTS = all linalg $(filter-out TestHelpers runtests testdefs,$(subst .jl,,$(wil default: all -$(TESTS) :: +$(TESTS): @$(call PRINT_JULIA, $(call spawn,$(JULIA_EXECUTABLE)) --check-bounds=yes --startup-file=no ./runtests.jl $@) perf: @@ -19,6 +19,7 @@ clean: libccalltest.$(SHLIB_EXT): ccalltest.c $(CC) $(CFLAGS) $(DEBUGFLAGS) -O3 $< -fPIC -shared -o $@ $(LDFLAGS) -DCC=$(CC) +ccall: libccalltest.$(SHLIB_EXT) ccalltest: ccalltest.c $(CC) $(CFLAGS) $(DEBUGFLAGS) -O3 $< -o $@ $(LDFLAGS) -DCC=$(CC) diff --git a/test/ccall.jl b/test/ccall.jl index 25221003e0dcc..67f3be04ade7a 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -1,3 +1,24 @@ -ccall_test_func(x) = ccall((:testUcharX, "./libccalltest"), Int32, (UInt8,), x) +ccall_test_func(x) = ccall((:testUcharX, "./libccalltest"), Int32, (UInt8,), x % UInt8) @test ccall_test_func(3) == 1 @test ccall_test_func(259) == 1 + +ccall_echo_func{T,U}(x, ::Type{T}, ::Type{U}) = ccall((:test_echo_p, "./libccalltest"), T, (U,), x) + +type IntLike + x::Int +end +@test unsafe_load(ccall_echo_func(132, Ptr{Int}, Ref{Int})) === 132 +@test unsafe_load(ccall_echo_func(Ref(921), Ptr{Int}, Ref{Int})) === 921 +@test unsafe_load(ccall_echo_func(IntLike(993), Ptr{Int}, Ref{IntLike})) === 993 +@test unsafe_load(ccall_echo_func(IntLike(881), Ptr{IntLike}, Ref{IntLike})).x === 881 +@test ccall_echo_func(532, Int, Int) === 532 +@test ccall_echo_func(164, IntLike, Int).x === 164 +@test ccall_echo_func(IntLike(828), Int, IntLike) === 828 +@test ccall_echo_func(913, Any, Any) === 913 +@test unsafe_pointer_to_objref(ccall_echo_func(553, Ptr{Any}, Any)) === 553 +@test ccall_echo_func(124, Ref{Int}, Any) === 124 +@test unsafe_load(ccall_echo_func(422, Ptr{Any}, Ref{Any})) === 422 + +@test unsafe_load(ccall_echo_func([383], Ptr{Int}, Ref{Int})) === 383 +@test unsafe_load(ccall_echo_func(Ref([144,172],2), Ptr{Int}, Ref{Int})) === 172 +#@test unsafe_load(ccall_echo_func(Ref([8],1,1), Ptr{Int}, Ref{Int})) === 8 diff --git a/test/ccalltest.c b/test/ccalltest.c index e88304d991a49..802e21713d2c2 100644 --- a/test/ccalltest.c +++ b/test/ccalltest.c @@ -2,7 +2,7 @@ int xs[300] = {0,0,0,1,0}; -int __attribute((noinline)) testUcharX(unsigned char x) { +int __attribute__((noinline)) testUcharX(unsigned char x) { return xs[x]; } @@ -22,3 +22,6 @@ int main() { xstr(CC), xs[a], xs[b], testUcharX(a), b, testUcharX(b), fptr(a), fptr(b)); } +void *test_echo_p(void *p) { + return p; +} From 571096b3dda81554510a6abcbfb59d307d5d1a73 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 8 Feb 2015 00:10:15 -0500 Subject: [PATCH 4/6] remove unused Ref subtypes. disallow implicit convert to Ptr{T} (ref #6618) --- base/abstractarray.jl | 11 ------- base/array.jl | 11 +++++++ base/gmp.jl | 2 +- base/inference.jl | 2 +- base/io.jl | 2 +- base/iostream.jl | 2 +- base/libc.jl | 14 ++++----- base/pointer.jl | 14 ++++----- base/process.jl | 20 ++---------- base/refpointer.jl | 72 ++++++++----------------------------------- base/serialize.jl | 2 +- base/sharedarray.jl | 2 +- base/string.jl | 2 +- base/subarray.jl | 6 ++-- base/sysimg.jl | 2 +- base/utf16.jl | 2 +- base/utf32.jl | 2 +- src/builtins.c | 6 ++-- test/core.jl | 2 +- 19 files changed, 57 insertions(+), 119 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index b130367e3d8e8..becbe491695d9 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -47,17 +47,6 @@ else end end -# convert Arrays to pointer arrays for ccall -cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array{P}) = a -function cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array) - ptrs = Array(P, length(a)+1) - for i = 1:length(a) - ptrs[i] = convert(P, a[i]) - end - ptrs[length(a)+1] = C_NULL - return ptrs -end - size{T,n}(t::AbstractArray{T,n}, d) = d <= n ? size(t)[d] : 1 size(x, d1::Integer, d2::Integer, dx::Integer...) = tuple(size(x, d1), size(x, d2, dx...)...) eltype{T}(::Type{AbstractArray{T}}) = T diff --git a/base/array.jl b/base/array.jl index 47edb5348b1e8..58e76f06e4893 100644 --- a/base/array.jl +++ b/base/array.jl @@ -18,6 +18,17 @@ call{T}(::Type{Matrix{T}}, m::Integer, n::Integer) = Array{T}(m, n) ## Basic functions ## +# convert Arrays to pointer arrays for ccall +cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array{P}) = a +function cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array) + ptrs = Array(P, length(a)+1) + for i = 1:length(a) + ptrs[i] = cconvert(P, a[i]) + end + ptrs[length(a)+1] = C_NULL + return ptrs +end + size(a::Array) = arraysize(a) size(a::Array, d) = arraysize(a, d) size(a::Matrix) = (arraysize(a,1), arraysize(a,2)) diff --git a/base/gmp.jl b/base/gmp.jl index 3331dc3f53838..c394b127e96af 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -82,7 +82,7 @@ function Base.parseint_nocheck(::Type{BigInt}, s::AbstractString, base::Int) z = BigInt() err = ccall((:__gmpz_set_str, :libgmp), Int32, (Ptr{BigInt}, Ptr{UInt8}, Int32), - &z, convert(Ptr{UInt8},SubString(s,i)), base) + &z, SubString(s,i), base) err == 0 || throw(ArgumentError("invalid BigInt: $(repr(s))")) return sgn < 0 ? -z : z end diff --git a/base/inference.jl b/base/inference.jl index 2509413eee054..934445c7d62b8 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -2376,7 +2376,7 @@ function inlineable(f::ANY, e::Expr, atypes::Tuple, sv::StaticVarInfo, enclosing if incompletematch cost *= 4 end - if is(f, next) || is(f, done) + if is(f, next) || is(f, done) || is(f, cconvert) || is(f, cconvert_gcroot) cost /= 4 end if !inline_worthy(body, cost) diff --git a/base/io.jl b/base/io.jl index f40ee1ee70aed..49c9e6db0da86 100644 --- a/base/io.jl +++ b/base/io.jl @@ -96,7 +96,7 @@ function write(s::IO, p::Ptr, n::Integer) end function write(io::IO, s::Symbol) - pname = convert(Ptr{UInt8}, s) + pname = cconvert(Ptr{UInt8}, s) write(io, pname, int(ccall(:strlen, Csize_t, (Ptr{UInt8},), pname))) end diff --git a/base/iostream.jl b/base/iostream.jl index b6f7820559fa9..d70efdca639e1 100644 --- a/base/iostream.jl +++ b/base/iostream.jl @@ -22,7 +22,7 @@ function IOStream(name::AbstractString, finalize::Bool) end IOStream(name::AbstractString) = IOStream(name, true) -convert(T::Type{Ptr{Void}}, s::IOStream) = convert(T, s.ios) +convert(T::Type{Ptr{Void}}, s::IOStream) = convert(T, pointer(s.ios)) show(io::IO, s::IOStream) = print(io, "IOStream(", s.name, ")") fd(s::IOStream) = int(ccall(:jl_ios_fd, Clong, (Ptr{Void},), s.ios)) stat(s::IOStream) = stat(fd(s)) diff --git a/base/libc.jl b/base/libc.jl index 23e5d1e4af076..6b144ce949797 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -28,7 +28,7 @@ type TmStruct t = floor(t) tm = TmStruct() # TODO: add support for UTC via gmtime_r() - ccall(:localtime_r, Ptr{Void}, (Ptr{Int}, Ptr{Void}), &t, &tm) + ccall(:localtime_r, Ptr{TmStruct}, (Ptr{Int}, Ptr{TmStruct}), &t, &tm) return tm end end @@ -37,18 +37,18 @@ strftime(t) = strftime("%c", t) strftime(fmt::AbstractString, t::Real) = strftime(fmt, TmStruct(t)) function strftime(fmt::AbstractString, tm::TmStruct) timestr = Array(UInt8, 128) - n = ccall(:strftime, Int, (Ptr{UInt8}, Int, Ptr{UInt8}, Ptr{Void}), + n = ccall(:strftime, Int, (Ptr{UInt8}, Int, Ptr{UInt8}, Ptr{TmStruct}), timestr, length(timestr), fmt, &tm) if n == 0 return "" end - bytestring(convert(Ptr{UInt8},timestr)) + bytestring(pointer(timestr), n) end strptime(timestr::AbstractString) = strptime("%c", timestr) function strptime(fmt::AbstractString, timestr::AbstractString) tm = TmStruct() - r = ccall(:strptime, Ptr{UInt8}, (Ptr{UInt8}, Ptr{UInt8}, Ptr{Void}), + r = ccall(:strptime, Ptr{UInt8}, (Ptr{UInt8}, Ptr{UInt8}, Ptr{TmStruct}), timestr, fmt, &tm) # the following would tell mktime() that this is a local time, and that # it should try to guess the timezone. not sure if/how this should be @@ -62,13 +62,13 @@ function strptime(fmt::AbstractString, timestr::AbstractString) # if we didn't explicitly parse the weekday or year day, use mktime # to fill them in automatically. if !ismatch(r"([^%]|^)%(a|A|j|w|Ow)", fmt) - ccall(:mktime, Int, (Ptr{Void},), &tm) + ccall(:mktime, Int, (Ptr{TmStruct},), &tm) end end tm end -time(tm::TmStruct) = float64(ccall(:mktime, Int, (Ptr{Void},), &tm)) +time(tm::TmStruct) = float64(ccall(:mktime, Int, (Ptr{TmStruct},), &tm)) ## process-related functions ## @@ -81,7 +81,7 @@ function gethostname() @unix_only err=ccall(:gethostname, Int32, (Ptr{UInt8}, UInt), hn, length(hn)) @windows_only err=ccall(:gethostname, stdcall, Int32, (Ptr{UInt8}, UInt32), hn, length(hn)) systemerror("gethostname", err != 0) - bytestring(convert(Ptr{UInt8},hn)) + bytestring(pointer(hn)) end ## Memory related ## diff --git a/base/pointer.jl b/base/pointer.jl index 78f42983bebcb..248475ac92ccb 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -14,17 +14,17 @@ convert{T}(::Type{Ptr{T}}, x::Signed) = box(Ptr{T},unbox(Int,Int(x))) convert{T}(::Type{Ptr{T}}, p::Ptr{T}) = p convert{T}(::Type{Ptr{T}}, p::Ptr) = box(Ptr{T}, unbox(Ptr,p)) -# object to pointer -convert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any,), x) -convert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x) -convert(::Type{Ptr{UInt8}}, s::ByteString) = convert(Ptr{UInt8}, s.data) -convert(::Type{Ptr{Int8}}, s::ByteString) = convert(Ptr{Int8}, s.data) +# object to pointer (when used with ccall) +cconvert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any,), x) +cconvert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x) +cconvert(::Type{Ptr{UInt8}}, s::ByteString) = cconvert(Ptr{UInt8}, s.data) +cconvert(::Type{Ptr{Int8}}, s::ByteString) = cconvert(Ptr{Int8}, s.data) # convert strings to ByteString to pass as pointers cconvert_gcroot(::Type{Ptr{UInt8}}, s::AbstractString) = bytestring(s) cconvert_gcroot(::Type{Ptr{Int8}}, s::AbstractString) = bytestring(s) -convert{T}(::Type{Ptr{T}}, a::Array{T}) = ccall(:jl_array_ptr, Ptr{T}, (Any,), a) -convert(::Type{Ptr{Void}}, a::Array) = ccall(:jl_array_ptr, Ptr{Void}, (Any,), a) +cconvert{T}(::Type{Ptr{T}}, a::Array{T}) = ccall(:jl_array_ptr, Ptr{T}, (Any,), a) +cconvert(::Type{Ptr{Void}}, a::Array) = ccall(:jl_array_ptr, Ptr{Void}, (Any,), a) # unsafe pointer to array conversions pointer_to_array(p, d::Integer, own=false) = pointer_to_array(p, (d,), own) diff --git a/base/process.jl b/base/process.jl index 469dc1f06a750..c1a88f731d620 100644 --- a/base/process.jl +++ b/base/process.jl @@ -199,7 +199,7 @@ type ProcessChain end typealias ProcessChainOrNot Union(Bool,ProcessChain) -function _jl_spawn(cmd::Ptr{UInt8}, argv::Ptr{Ptr{UInt8}}, loop::Ptr{Void}, pp::Process, +function _jl_spawn(cmd, argv, loop::Ptr{Void}, pp::Process, in, out, err) proc = c_malloc(_sizeof_uv_process) error = ccall(:jl_spawn, Int32, @@ -339,10 +339,9 @@ function spawn(pc::ProcessChainOrNot, cmd::Cmd, stdios::StdIOSet, exitcb::Callba loop = eventloop() pp = Process(cmd, C_NULL, stdios[1], stdios[2], stdios[3]); @setup_stdio - ptrs = _jl_pre_exec(cmd.exec) pp.exitcb = exitcb pp.closecb = closecb - pp.handle = _jl_spawn(ptrs[1], convert(Ptr{Ptr{UInt8}}, ptrs), loop, pp, + pp.handle = _jl_spawn(cmd.exec[1], cmd.exec, loop, pp, in, out, err) @cleanup_stdio if isa(pc, ProcessChain) @@ -557,21 +556,6 @@ function process_status(s::Process) error("process status error") end -# WARNING: do not call this and keep the returned array of pointers -# around longer than the args vector and then use array of pointers. -# this could cause a segfault. this is really just for use by the -# spawn function below so that we can exec more efficiently. -# -function _jl_pre_exec(args::Vector{ByteString}) - isempty(args) && throw(ArgumentError("exec called with no arguments")) - ptrs = Array(Ptr{UInt8}, length(args)+1) - for i = 1:length(args) - ptrs[i] = args[i].data - end - ptrs[length(args)+1] = C_NULL - return ptrs -end - ## implementation of `cmd` syntax ## arg_gen() = ByteString[] diff --git a/base/refpointer.jl b/base/refpointer.jl index 876093c7248df..2e9285578b452 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -4,10 +4,10 @@ Base.eltype{T}(x::Type{Ref{T}}) = T Base.convert{T}(::Type{Ref{T}}, x::Ref{T}) = x # create Ref objects for general object conversion -@inline Base.cconvert_gcroot{T}(::Type{Ref{T}}, x) = convert(Ref{T}, x) -@inline Base.cconvert{T}(::Type{Ref{T}}, x) = convert(Ptr{T}, x) +Base.cconvert_gcroot{T}(::Type{Ref{T}}, x) = convert(Ref{T}, x) +Base.cconvert{T}(::Type{Ref{T}}, x) = cconvert(Ptr{T}, x) -### Methods for a Ref object that can store a single value +### Methods for a Ref object that can store a single value of any type type RefValue{T} <: Ref{T} x::T @@ -22,100 +22,52 @@ Ref{T}(x::T) = RefValue{T}(x) Ref{T}(x::Ptr{T}, i::Integer=1) = x + (i-1)*Core.sizeof(T) Ref(x, i::Integer) = (i != 1 && error("Object only has one element"); Ref(x)) -@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefValue{T}) +function Base.cconvert{T}(P::Type{Ptr{T}}, b::RefValue{T}) if isbits(T) return convert(P, data_pointer_from_objref(b)) else return convert(P, data_pointer_from_objref(b.x)) end end -@inline function Base.convert(P::Type{Ptr{Any}}, b::RefValue{Any}) +function Base.cconvert(P::Type{Ptr{Any}}, b::RefValue{Any}) return convert(P, data_pointer_from_objref(b)) end -@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefValue{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) +Base.cconvert{T}(::Type{Ptr{Void}}, b::RefValue{T}) = Base.convert(Ptr{Void}, Base.cconvert(Ptr{T}, b)) ### Methods for a Ref object that is backed by an array at index i # note: the following type definitions don't mean any AbstractArray is convertible to # a data Ref. they just map the array element type to the pointer type for # convenience in cases that work. -pointer{T}(x::AbstractArray{T}) = convert(Ptr{T},x) -pointer{T}(x::AbstractArray{T}, i::Integer) = convert(Ptr{T},x) + (i-1)*elsize(x) +pointer{T}(x::AbstractArray{T}) = cconvert(Ptr{T}, x) +pointer{T}(x::AbstractArray{T}, i::Integer) = cconvert(Ptr{T},x) + (i-1)*elsize(x) immutable RefArray{T, A<:AbstractArray} <: Ref{T} x::A i::Int RefArray(x,i) = (@assert(eltype(A) == T); new(x,i)) end -convert{T}(::Type{Ref{T}}, x::AbstractArray{T}) = RefArray{T,typeof(x)}(x, 1) +Base.convert{T}(::Type{Ref{T}}, x::AbstractArray{T}) = RefArray{T,typeof(x)}(x, 1) Ref{T}(x::AbstractArray{T}, i::Integer=1) = RefArray{T,typeof(x)}(x, i) -@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefArray{T}) +function Base.cconvert{T}(P::Type{Ptr{T}}, b::RefArray{T}) if isbits(T) convert(P, pointer(b.x, b.i)) else convert(P, data_pointer_from_objref(b.x[b.i])) end end -@inline function Base.convert(P::Type{Ptr{Any}}, b::RefArray{Any}) +function Base.cconvert(P::Type{Ptr{Any}}, b::RefArray{Any}) return convert(P, pointer(b.x, b.i)) end -@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefArray{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) - -### Methods for a Ref object that is backed by an array at index (i...) - -immutable RefArrayND{T, A<:AbstractArray} <: Ref{T} - x::A - i::(Int...) - RefArrayND(x,i) = (@assert(eltype(A) == T); new(x,i)) -end -Ref{A<:AbstractArray}(x::A, i::Integer...) = RefArrayND{eltype(A),A}(x, i) -Ref{A<:AbstractArray}(x::A, i::(Integer...)) = RefArrayND{eltype(A),A}(x, i) - -@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefArrayND{T}) - if isbits(T) - convert(P, pointer(b.x, b.i...)) - else - convert(P, data_pointer_from_objref(b.x[b.i...])) - end -end -@inline function Base.convert(P::Type{Ptr{Any}}, b::RefArrayND{Any}) - return convert(P, pointer(b.x, b.i...)) -end -@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefArrayND{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) - -### Methods for a Ref object that is backed by an array at index (Any...) - -immutable RefArrayI{T} <: Ref{T} - x::AbstractArray{T} - i::Tuple - RefArrayI(x,i::ANY) = (@assert(eltype(A) == T); new(x,i)) -end -Ref{T}(x::AbstractArray{T}, i...) = RefArrayI{T}(x, i) -Ref{T}(x::AbstractArray{T}, i::Tuple) = RefArrayI{T}(x, i) - -@inline function Base.convert{T}(P::Type{Ptr{T}}, b::RefArrayI{T}) - if isbits(T) - convert(P, pointer(b.x, b.i...)) - else - convert(P, data_pointer_from_objref(b.x[b.i...])) - end -end -@inline function Base.convert(P::Type{Ptr{Any}}, b::RefArrayI{Any}) - return convert(P, pointer(b.x, b.i...)) -end -@inline Base.convert{T}(::Type{Ptr{Void}}, b::RefArrayI{T}) = Base.convert(Ptr{Void}, Base.convert(Ptr{T}, b)) +Base.cconvert{T}(::Type{Ptr{Void}}, b::RefArray{T}) = Base.convert(Ptr{Void}, Base.cconvert(Ptr{T}, b)) ### Base.getindex(b::RefValue) = b.x Base.getindex(b::RefArray) = b.x[b.i] -Base.getindex(b::RefArrayND) = b.x[b.i...] -Base.getindex(b::RefArrayI) = b.x[b.i...] Base.setindex!(b::RefValue, x) = (b.x = x; b) Base.setindex!(b::RefArray, x) = (b.x[b.i] = x; b) -Base.setindex!(b::RefArrayND, x) = (b.x[b.i...] = x; b) -Base.setindex!(b::RefArrayI, x) = (b.x[b.i...] = x; b) ### diff --git a/base/serialize.jl b/base/serialize.jl index ee1174d0b47ce..9fa97e041835d 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -84,7 +84,7 @@ function serialize(s, x::Symbol) if haskey(ser_tag, x) return write_as_tag(s, x) end - pname = convert(Ptr{UInt8}, x) + pname = cconvert(Ptr{UInt8}, x) ln = int(ccall(:strlen, Csize_t, (Ptr{UInt8},), pname)) if ln <= 255 writetag(s, Symbol) diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 6968c142e9522..60fc36f49e19c 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -139,7 +139,7 @@ sdata(A::AbstractArray) = A localindexes(S::SharedArray) = S.pidx > 0 ? range_1dim(S, S.pidx) : 1:0 -convert{T}(::Type{Ptr{T}}, S::SharedArray) = convert(Ptr{T}, sdata(S)) +cconvert{T}(::Type{Ptr{T}}, S::SharedArray) = cconvert(Ptr{T}, sdata(S)) convert(::Type{SharedArray}, A::Array) = (S = SharedArray(eltype(A), size(A)); copy!(S, A)) convert{T}(::Type{SharedArray{T}}, A::Array) = (S = SharedArray(T, size(A)); copy!(S, A)) diff --git a/base/string.jl b/base/string.jl index feb5590651d75..f416f729711c4 100644 --- a/base/string.jl +++ b/base/string.jl @@ -646,7 +646,7 @@ function getindex(s::AbstractString, r::UnitRange{Int}) SubString(s, first(r), last(r)) end -function convert{P<:Union(Int8,UInt8),T<:ByteString}(::Type{Ptr{P}}, s::SubString{T}) +function cconvert{P<:Union(Int8,UInt8),T<:ByteString}(::Type{Ptr{P}}, s::SubString{T}) if s.offset+s.endof < endof(s.string) throw(ArgumentError("a SubString must coincide with the end of the original string to be convertible to pointer")) end diff --git a/base/subarray.jl b/base/subarray.jl index 8373c04c879bc..e709b7d3b2471 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -415,11 +415,11 @@ function subarray_linearindexing_dim{A<:AbstractArray}(::Type{A}, It::Tuple) LD end -convert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) = +cconvert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) = pointer(V.parent) + (V.first_index-1)*sizeof(T) -convert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{Void}}, V::SubArray{T,N,P,I}) = - convert(Ptr{Void}, convert(Ptr{T}, V)) +cconvert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{Void}}, V::SubArray{T,N,P,I}) = + convert(Ptr{Void}, cconvert(Ptr{T}, V)) pointer(V::SubArray, i::Int) = pointer(V, ind2sub(size(V), i)) diff --git a/base/sysimg.jl b/base/sysimg.jl index 9c6ece84c568f..5dedbb1c4afd9 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -46,6 +46,7 @@ include("number.jl") include("int.jl") include("operators.jl") include("pointer.jl") +include("refpointer.jl") # rounding utilities include("rounding.jl") @@ -67,7 +68,6 @@ include("dict.jl") include("set.jl") include("hashing.jl") include("iterator.jl") -include("refpointer.jl") #XXX: move this earlier when we don't need @inline annotations anymore # SIMD loops include("simdloop.jl") diff --git a/base/utf16.jl b/base/utf16.jl index c38ecbf1c735e..c437b30edbad2 100644 --- a/base/utf16.jl +++ b/base/utf16.jl @@ -75,7 +75,7 @@ convert(::Type{UTF8String}, s::UTF16String) = sprint(length(s.data)-1, io->for c in s; write(io,c::Char); end) sizeof(s::UTF16String) = sizeof(s.data) - sizeof(UInt16) -convert{T<:Union(Int16,UInt16)}(::Type{Ptr{T}}, s::UTF16String) = +cconvert{T<:Union(Int16,UInt16)}(::Type{Ptr{T}}, s::UTF16String) = convert(Ptr{T}, pointer(s)) function is_valid_utf16(data::AbstractArray{UInt16}) diff --git a/base/utf32.jl b/base/utf32.jl index 7e74fa290e95f..ecc5e844541d4 100644 --- a/base/utf32.jl +++ b/base/utf32.jl @@ -66,7 +66,7 @@ convert(::Type{Array{Char}}, s::UTF32String) = s.data reverse(s::UTF32String) = UTF32String(reverse!(copy(s.data), 1, length(s))) sizeof(s::UTF32String) = sizeof(s.data) - sizeof(Char) -convert{T<:Union(Int32,UInt32,Char)}(::Type{Ptr{T}}, s::UTF32String) = +cconvert{T<:Union(Int32,UInt32,Char)}(::Type{Ptr{T}}, s::UTF32String) = convert(Ptr{T}, pointer(s)) function convert(T::Type{UTF32String}, bytes::AbstractArray{UInt8}) diff --git a/src/builtins.c b/src/builtins.c index 8da6f06c693b0..1102b28060bf0 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1201,13 +1201,15 @@ static size_t jl_show_tuple(JL_STREAM *out, jl_tuple_t *t, char *opn, char *cls, return n; } -#define MAX_DEPTH 5 +#define MAX_DEPTH 25 size_t jl_static_show_x(JL_STREAM *out, jl_value_t *v, int depth) { // mimic jl_show, but never calling a julia method size_t n = 0; - if(depth > MAX_DEPTH) return 0; // cheap way of bailing out of cycles + if(depth > MAX_DEPTH) { // cheap way of bailing out of cycles + return jl_printf(out, "•"); + } depth++; if (v == NULL) { n += jl_printf(out, "#"); diff --git a/test/core.jl b/test/core.jl index 3cbddf0b067cf..649d4caad54fc 100644 --- a/test/core.jl +++ b/test/core.jl @@ -787,7 +787,7 @@ end begin local X, p X = FooBar[ FooBar(3,1), FooBar(4,4) ] - p = convert(Ptr{FooBar}, X) + p = pointer(X) @test unsafe_load(p, 2) == FooBar(4,4) unsafe_store!(p, FooBar(7,3), 1) @test X[1] == FooBar(7,3) From 9edf5a416a62f193ef753ba4cb702f98e6234de8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 26 Feb 2015 23:10:06 -0500 Subject: [PATCH 5/6] add an optional "roots" field to RefArray for tracking any additional required references --- base/array.jl | 26 +++++++++++++++++++------- base/linalg/tridiag.jl | 2 +- base/multi.jl | 4 ++-- base/refpointer.jl | 19 ++++++++++++------- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/base/array.jl b/base/array.jl index 58e76f06e4893..f0d9d1cc8b4fc 100644 --- a/base/array.jl +++ b/base/array.jl @@ -19,15 +19,27 @@ call{T}(::Type{Matrix{T}}, m::Integer, n::Integer) = Array{T}(m, n) ## Basic functions ## # convert Arrays to pointer arrays for ccall -cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array{P}) = a -function cconvert_gcroot{P<:Ptr}(::Type{Ptr{P}}, a::Array) - ptrs = Array(P, length(a)+1) - for i = 1:length(a) - ptrs[i] = cconvert(P, a[i]) +function call{P<:Ptr,T<:Ptr}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array{T<:Ptr}) + return RefArray(a) # effectively a no-op +end +function call{P<:Ptr,T}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array) + if (!isbits(T) && T <: eltype(P)) + # this Array already has the right memory layout for the requested Ref + return RefArray(a,1,false) # root something, so that this function is type-stable + else + ptrs = Array(P, length(a)+1) + roots = Array(Any, length(a)) + for i = 1:length(a) + root = cconvert_gcroot(P, a[i]) + ptrs[i] = cconvert(P, root)::P + roots[i] = root + end + ptrs[length(a)+1] = C_NULL + return RefArray(ptrs,1,roots) end - ptrs[length(a)+1] = C_NULL - return ptrs end +cconvert_gcroot{P<:Ptr,T<:Ptr}(::Union(Type{Ptr{P}},Type{Ref{P}}), a::Array{T}) = a +cconvert_gcroot{P<:Ptr}(::Union(Type{Ptr{P}},Type{Ref{P}}), a::Array) = Ref{P}(a) size(a::Array) = arraysize(a) size(a::Array, d) = arraysize(a, d) diff --git a/base/linalg/tridiag.jl b/base/linalg/tridiag.jl index 29b3d276fec84..155de46419aab 100644 --- a/base/linalg/tridiag.jl +++ b/base/linalg/tridiag.jl @@ -127,7 +127,7 @@ setindex!(a::ZeroOffsetVector, x, i) = a.data[i+1]=x #Implements the inverse using the recurrence relation between principal minors # a, b, c are assumed to be the subdiagonal, diagonal, and superdiagonal of # a tridiagonal matrix. -#Ref: +#Reference: # R. Usmani, "Inversion of a tridiagonal Jacobi matrix", # Linear Algebra and its Applications 212-213 (1994), pp.413-414 # doi:10.1016/0024-3795(94)90414-6 diff --git a/base/multi.jl b/base/multi.jl index c4575f393e255..2e89448a3cbc6 100644 --- a/base/multi.jl +++ b/base/multi.jl @@ -722,7 +722,7 @@ fetch_ref(rid) = wait_full(lookup_ref(rid)) fetch(r::RemoteRef) = call_on_owner(fetch_ref, r) fetch(x::ANY) = x -# storing a value to a Ref +# storing a value to a RemoteRef function put!(rv::RemoteValue, val::ANY) wait_empty(rv) rv.result = val @@ -772,7 +772,7 @@ function deliver_result(sock::IO, msg, oid, value) end end -# notify waiters that a certain job has finished or Ref has been emptied +# notify waiters that a certain job has finished or RemoteRef has been emptied notify_full (rv::RemoteValue) = notify(rv.full, work_result(rv)) notify_empty(rv::RemoteValue) = notify(rv.empty) diff --git a/base/refpointer.jl b/base/refpointer.jl index 2e9285578b452..070906e9e4e22 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -14,13 +14,15 @@ type RefValue{T} <: Ref{T} RefValue() = new() RefValue(x) = new(x) end -Base.convert{T}(::Type{Ref{T}}, x) = RefValue{T}(x) -Base.call{T}(::Type{Ref{T}}) = RefValue{T}() +RefValue{T}(x::T) = RefValue{T}(x) Ref(x::Ref) = x -Ref{T}(x::T) = RefValue{T}(x) +Ref(x::Any) = RefValue(x) Ref{T}(x::Ptr{T}, i::Integer=1) = x + (i-1)*Core.sizeof(T) Ref(x, i::Integer) = (i != 1 && error("Object only has one element"); Ref(x)) +Base.call{T}(::Type{Ref{T}}) = RefValue{T}() # Ref{T}() +Base.call{T}(::Type{Ref{T}}, x) = RefValue{T}(x) # Ref{T}(x) +Base.convert{T}(::Type{Ref{T}}, x) = RefValue{T}(x) function Base.cconvert{T}(P::Type{Ptr{T}}, b::RefValue{T}) if isbits(T) @@ -42,13 +44,16 @@ Base.cconvert{T}(::Type{Ptr{Void}}, b::RefValue{T}) = Base.convert(Ptr{Void}, Ba pointer{T}(x::AbstractArray{T}) = cconvert(Ptr{T}, x) pointer{T}(x::AbstractArray{T}, i::Integer) = cconvert(Ptr{T},x) + (i-1)*elsize(x) -immutable RefArray{T, A<:AbstractArray} <: Ref{T} +immutable RefArray{T, A<:AbstractArray, R} <: Ref{T} x::A i::Int - RefArray(x,i) = (@assert(eltype(A) == T); new(x,i)) + roots::R # should be either ::Void or ::Any + RefArray(x,i,roots=nothing) = (@assert(eltype(A) == T); new(x,i,roots)) end -Base.convert{T}(::Type{Ref{T}}, x::AbstractArray{T}) = RefArray{T,typeof(x)}(x, 1) -Ref{T}(x::AbstractArray{T}, i::Integer=1) = RefArray{T,typeof(x)}(x, i) +RefArray{T}(x::AbstractArray{T},i::Int,roots::Any) = RefArray{T,typeof(x),Any}(x, 1, roots) +RefArray{T}(x::AbstractArray{T},i::Int=1,roots::Void=nothing) = RefArray{T,typeof(x),Void}(x, 1, nothing) +Base.convert{T}(::Type{Ref{T}}, x::AbstractArray{T}) = RefArray(x, 1) +Ref(x::AbstractArray, i::Integer=1) = RefArray(x, i) function Base.cconvert{T}(P::Type{Ptr{T}}, b::RefArray{T}) if isbits(T) From 721f3e23d187b13199ba46b770e4a4d4126ec678 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 7 Mar 2015 01:54:08 -0500 Subject: [PATCH 6/6] renames cconvert(cconvert_gcroot()) to unsafe_convert(cconvert()) this also makes changes such that cconvert is mostly unchanged from its functionality before this change. cconvert is expected to typically call convert. in some cases (such as when intending to create a Ptr for C-compatiblity), it should defer the actual unsafe step of making the Ptr to unsafe_convert. any code intending to allow conversion of an object to a Ptr should define the operation as a method of unsafe_convert after this commit, rather than the current behavior of making them a method of convert --- base/REPL.jl | 2 +- base/array.jl | 8 ++++---- base/base.jl | 11 +++++++---- base/deprecated.jl | 15 +++++++++++++++ base/fs.jl | 3 ++- base/inference.jl | 2 +- base/io.jl | 2 +- base/iostream.jl | 2 +- base/pointer.jl | 20 ++++++++++---------- base/process.jl | 9 ++++----- base/profile.jl | 8 ++++---- base/refpointer.jl | 19 +++++++++---------- base/serialize.jl | 2 +- base/sharedarray.jl | 2 +- base/socket.jl | 6 +++--- base/stream.jl | 2 +- base/string.jl | 2 +- base/subarray.jl | 6 +++--- base/utf16.jl | 2 +- base/utf32.jl | 2 +- src/julia-syntax.scm | 4 ++-- test/core.jl | 2 +- test/intfuncs.jl | 1 - 23 files changed, 74 insertions(+), 58 deletions(-) diff --git a/base/REPL.jl b/base/REPL.jl index dfc86c60f9274..d4faf005a2758 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -259,7 +259,7 @@ end immutable LatexCompletions <: CompletionProvider; end -bytestring_beforecursor(buf::IOBuffer) = bytestring(pointer(buf.data), buf.ptr-1) +bytestring_beforecursor(buf::IOBuffer) = bytestring(buf.data[1:buf.ptr-1]) function complete_line(c::REPLCompletionProvider, s) partial = bytestring_beforecursor(s.input_buffer) diff --git a/base/array.jl b/base/array.jl index f0d9d1cc8b4fc..73be858fd6ab6 100644 --- a/base/array.jl +++ b/base/array.jl @@ -30,16 +30,16 @@ function call{P<:Ptr,T}(::Type{Ref{P}}, a::Array{T}) # Ref{P<:Ptr}(a::Array) ptrs = Array(P, length(a)+1) roots = Array(Any, length(a)) for i = 1:length(a) - root = cconvert_gcroot(P, a[i]) - ptrs[i] = cconvert(P, root)::P + root = cconvert(P, a[i]) + ptrs[i] = unsafe_convert(P, root)::P roots[i] = root end ptrs[length(a)+1] = C_NULL return RefArray(ptrs,1,roots) end end -cconvert_gcroot{P<:Ptr,T<:Ptr}(::Union(Type{Ptr{P}},Type{Ref{P}}), a::Array{T}) = a -cconvert_gcroot{P<:Ptr}(::Union(Type{Ptr{P}},Type{Ref{P}}), a::Array) = Ref{P}(a) +cconvert{P<:Ptr,T<:Ptr}(::Union(Type{Ptr{P}},Type{Ref{P}}), a::Array{T}) = a +cconvert{P<:Ptr}(::Union(Type{Ptr{P}},Type{Ref{P}}), a::Array) = Ref{P}(a) size(a::Array) = arraysize(a) size(a::Array, d) = arraysize(a, d) diff --git a/base/base.jl b/base/base.jl index 0aab4f545d362..ed3a735c2c31f 100644 --- a/base/base.jl +++ b/base/base.jl @@ -53,11 +53,14 @@ cnvt_all(T) = () cnvt_all(T, x, rest...) = tuple(convert(T,x), cnvt_all(T, rest...)...) # conversions used by ccall -ptr_arg_cconvert_gcroot{T}(::Type{Ptr{T}}, x) = cconvert_gcroot(T, x) ptr_arg_cconvert{T}(::Type{Ptr{T}}, x) = cconvert(T, x) -ptr_arg_cconvert(::Type{Ptr{Void}}, x) = x -cconvert_gcroot(T, x) = x -cconvert(T, x) = convert(T,x) +ptr_arg_unsafe_convert{T}(::Type{Ptr{T}}, x) = unsafe_convert(T, x) +ptr_arg_unsafe_convert(::Type{Ptr{Void}}, x) = x + +cconvert(T::Type, x) = convert(T, x) # do the conversion eagerly in most cases +cconvert{P<:Ptr}(::Type{P}, x) = x # but defer the conversion to Ptr to unsafe_convert +unsafe_convert{T}(::Type{T}, x::T) = x # unsafe_convert (like convert) defaults to assuming the convert occurred +unsafe_convert{P<:Ptr}(::Type{P}, x::Ptr) = convert(P, x) reinterpret{T,S}(::Type{T}, x::S) = box(T,unbox(S,x)) diff --git a/base/deprecated.jl b/base/deprecated.jl index 8eb1d71492334..9aed23d418eea 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -301,6 +301,21 @@ function subtypetree(x::DataType, level=-1) (level == 0 ? (x, []) : (x, Any[subtypetree(y, level-1) for y in subtypes(x)])) end +function unsafe_convert{P}(::Type{P}, x) + P<:Ptr || throw(MethodError(unsafe_convert, (Type{P}, x))) + depwarn("convert(::Type{Ptr}, ::$(typeof(x))) methods should be converted to be methods of unsafe_convert", :unsafe_convert) + return convert(P, x) +end + +function convert{T}(::Type{Ptr{T}}, x::Integer) + depwarn("converting integers to pointers is discontinued", :convert) + box(Ptr{T},unbox(UInt,UInt(x))) +end +function convert{T}(::Type{Ptr{T}}, x::Signed) + depwarn("converting signed numbers to pointers is discontinued", :convert) + box(Ptr{T},unbox(Int,Int(x))) +end + # 8898 @deprecate precision(x::DateTime) eps(x) @deprecate precision(x::Date) eps(x) diff --git a/base/fs.jl b/base/fs.jl index e3482a29272e9..f77e4a27af84a 100644 --- a/base/fs.jl +++ b/base/fs.jl @@ -63,8 +63,9 @@ end isopen(f::Union(File,AsyncFile)) = f.open +# Not actually a pointer, but that's how we pass it through the C API so it's fine +uvhandle(file::File) = convert(Ptr{Void}, file.handle % UInt) uvtype(::File) = Base.UV_RAW_FD -uvhandle(file::File) = file.handle _uv_fs_result(req) = ccall(:jl_uv_fs_result,Int32,(Ptr{Void},),req) diff --git a/base/inference.jl b/base/inference.jl index 934445c7d62b8..213b857a4b78b 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -2376,7 +2376,7 @@ function inlineable(f::ANY, e::Expr, atypes::Tuple, sv::StaticVarInfo, enclosing if incompletematch cost *= 4 end - if is(f, next) || is(f, done) || is(f, cconvert) || is(f, cconvert_gcroot) + if is(f, next) || is(f, done) || is(f, unsafe_convert) || is(f, cconvert) cost /= 4 end if !inline_worthy(body, cost) diff --git a/base/io.jl b/base/io.jl index 49c9e6db0da86..b3b11fb8e71f6 100644 --- a/base/io.jl +++ b/base/io.jl @@ -96,7 +96,7 @@ function write(s::IO, p::Ptr, n::Integer) end function write(io::IO, s::Symbol) - pname = cconvert(Ptr{UInt8}, s) + pname = unsafe_convert(Ptr{UInt8}, s) write(io, pname, int(ccall(:strlen, Csize_t, (Ptr{UInt8},), pname))) end diff --git a/base/iostream.jl b/base/iostream.jl index d70efdca639e1..1f8ab7e77e4e4 100644 --- a/base/iostream.jl +++ b/base/iostream.jl @@ -22,7 +22,7 @@ function IOStream(name::AbstractString, finalize::Bool) end IOStream(name::AbstractString) = IOStream(name, true) -convert(T::Type{Ptr{Void}}, s::IOStream) = convert(T, pointer(s.ios)) +unsafe_convert(T::Type{Ptr{Void}}, s::IOStream) = convert(T, pointer(s.ios)) show(io::IO, s::IOStream) = print(io, "IOStream(", s.name, ")") fd(s::IOStream) = int(ccall(:jl_ios_fd, Clong, (Ptr{Void},), s.ios)) stat(s::IOStream) = stat(fd(s)) diff --git a/base/pointer.jl b/base/pointer.jl index 248475ac92ccb..05d7f839c65de 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -7,24 +7,24 @@ convert{T<:Union(Int,UInt)}(::Type{T}, x::Ptr) = box(T, unbox(Ptr,x)) convert{T<:Integer}(::Type{T}, x::Ptr) = convert(T,unsigned(x)) # integer to pointer -convert{T}(::Type{Ptr{T}}, x::Integer) = box(Ptr{T},unbox(UInt,UInt(x))) -convert{T}(::Type{Ptr{T}}, x::Signed) = box(Ptr{T},unbox(Int,Int(x))) +convert{T}(::Type{Ptr{T}}, x::UInt) = box(Ptr{T},unbox(UInt,UInt(x))) +convert{T}(::Type{Ptr{T}}, x::Int) = box(Ptr{T},unbox(Int,Int(x))) # pointer to pointer convert{T}(::Type{Ptr{T}}, p::Ptr{T}) = p convert{T}(::Type{Ptr{T}}, p::Ptr) = box(Ptr{T}, unbox(Ptr,p)) # object to pointer (when used with ccall) -cconvert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any,), x) -cconvert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x) -cconvert(::Type{Ptr{UInt8}}, s::ByteString) = cconvert(Ptr{UInt8}, s.data) -cconvert(::Type{Ptr{Int8}}, s::ByteString) = cconvert(Ptr{Int8}, s.data) +unsafe_convert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any,), x) +unsafe_convert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x) +unsafe_convert(::Type{Ptr{UInt8}}, s::ByteString) = unsafe_convert(Ptr{UInt8}, s.data) +unsafe_convert(::Type{Ptr{Int8}}, s::ByteString) = unsafe_convert(Ptr{Int8}, s.data) # convert strings to ByteString to pass as pointers -cconvert_gcroot(::Type{Ptr{UInt8}}, s::AbstractString) = bytestring(s) -cconvert_gcroot(::Type{Ptr{Int8}}, s::AbstractString) = bytestring(s) +cconvert(::Type{Ptr{UInt8}}, s::AbstractString) = bytestring(s) +cconvert(::Type{Ptr{Int8}}, s::AbstractString) = bytestring(s) -cconvert{T}(::Type{Ptr{T}}, a::Array{T}) = ccall(:jl_array_ptr, Ptr{T}, (Any,), a) -cconvert(::Type{Ptr{Void}}, a::Array) = ccall(:jl_array_ptr, Ptr{Void}, (Any,), a) +unsafe_convert{T}(::Type{Ptr{T}}, a::Array{T}) = ccall(:jl_array_ptr, Ptr{T}, (Any,), a) +unsafe_convert(::Type{Ptr{Void}}, a::Array) = ccall(:jl_array_ptr, Ptr{Void}, (Any,), a) # unsafe pointer to array conversions pointer_to_array(p, d::Integer, own=false) = pointer_to_array(p, (d,), own) diff --git a/base/process.jl b/base/process.jl index c1a88f731d620..e2826c9316dd6 100644 --- a/base/process.jl +++ b/base/process.jl @@ -85,9 +85,8 @@ uvhandle(x::Ptr) = x uvtype(::Ptr) = UV_STREAM uvtype(::DevNullStream) = UV_STREAM -# Not actually a pointer, but that's how we pass it through the C API -# so it's fine -uvhandle(x::RawFD) = convert(Ptr{Void}, x.fd) +# Not actually a pointer, but that's how we pass it through the C API so it's fine +uvhandle(x::RawFD) = convert(Ptr{Void}, x.fd % UInt) uvtype(x::RawFD) = UV_RAW_FD typealias Redirectable Union(UVStream, FS.File, FileRedirect, DevNullStream, IOStream, RawFD) @@ -220,7 +219,7 @@ end function uvfinalize(proc::Process) proc.handle != C_NULL && ccall(:jl_close_uv, Void, (Ptr{Void},), proc.handle) disassociate_julia_struct(proc) - proc.handle = 0 + proc.handle = C_NULL end function _uv_hook_return_spawn(proc::Process, exit_status::Int64, termsignal::Int32) @@ -232,7 +231,7 @@ function _uv_hook_return_spawn(proc::Process, exit_status::Int64, termsignal::In end function _uv_hook_close(proc::Process) - proc.handle = 0 + proc.handle = C_NULL if isa(proc.closecb, Function) proc.closecb(proc) end notify(proc.closenotify) end diff --git a/base/profile.jl b/base/profile.jl index 1c5e800f4ec77..c3dfc2f909008 100644 --- a/base/profile.jl +++ b/base/profile.jl @@ -98,7 +98,7 @@ immutable LineInfo file::ByteString line::Int fromC::Bool - ip::Int + ip::Int64 # large enough that this struct can be losslessly read on any machine (32 or 64 bit) end const UNKNOWN = LineInfo("?", "?", -1, true, 0) @@ -130,15 +130,15 @@ len_data() = convert(Int, ccall(:jl_profile_len_data, Csize_t, ())) maxlen_data() = convert(Int, ccall(:jl_profile_maxlen_data, Csize_t, ())) -function lookup(ip::UInt) +function lookup(ip::Ptr{Void}) info = ccall(:jl_lookup_code_address, Any, (Ptr{Void},Cint), ip, false) if length(info) == 5 - return LineInfo(string(info[1]), string(info[2]), int(info[3]), info[4], int(info[5])) + return LineInfo(string(info[1]), string(info[2]), int(info[3]), info[4], int64(info[5])) else return UNKNOWN end end -lookup(ip::Ptr{Void}) = lookup(UInt(ip)) +lookup(ip::UInt) = lookup(convert(Ptr{Void},ip)) error_codes = Dict{Int,ASCIIString}( -1=>"cannot specify signal action for profiling", diff --git a/base/refpointer.jl b/base/refpointer.jl index 070906e9e4e22..32fa9b7f4a2a4 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -4,8 +4,7 @@ Base.eltype{T}(x::Type{Ref{T}}) = T Base.convert{T}(::Type{Ref{T}}, x::Ref{T}) = x # create Ref objects for general object conversion -Base.cconvert_gcroot{T}(::Type{Ref{T}}, x) = convert(Ref{T}, x) -Base.cconvert{T}(::Type{Ref{T}}, x) = cconvert(Ptr{T}, x) +Base.unsafe_convert{T}(::Type{Ref{T}}, x) = unsafe_convert(Ptr{T}, x) ### Methods for a Ref object that can store a single value of any type @@ -24,25 +23,25 @@ Base.call{T}(::Type{Ref{T}}) = RefValue{T}() # Ref{T}() Base.call{T}(::Type{Ref{T}}, x) = RefValue{T}(x) # Ref{T}(x) Base.convert{T}(::Type{Ref{T}}, x) = RefValue{T}(x) -function Base.cconvert{T}(P::Type{Ptr{T}}, b::RefValue{T}) +function Base.unsafe_convert{T}(P::Type{Ptr{T}}, b::RefValue{T}) if isbits(T) return convert(P, data_pointer_from_objref(b)) else return convert(P, data_pointer_from_objref(b.x)) end end -function Base.cconvert(P::Type{Ptr{Any}}, b::RefValue{Any}) +function Base.unsafe_convert(P::Type{Ptr{Any}}, b::RefValue{Any}) return convert(P, data_pointer_from_objref(b)) end -Base.cconvert{T}(::Type{Ptr{Void}}, b::RefValue{T}) = Base.convert(Ptr{Void}, Base.cconvert(Ptr{T}, b)) +Base.unsafe_convert{T}(::Type{Ptr{Void}}, b::RefValue{T}) = Base.convert(Ptr{Void}, Base.unsafe_convert(Ptr{T}, b)) ### Methods for a Ref object that is backed by an array at index i # note: the following type definitions don't mean any AbstractArray is convertible to # a data Ref. they just map the array element type to the pointer type for # convenience in cases that work. -pointer{T}(x::AbstractArray{T}) = cconvert(Ptr{T}, x) -pointer{T}(x::AbstractArray{T}, i::Integer) = cconvert(Ptr{T},x) + (i-1)*elsize(x) +pointer{T}(x::AbstractArray{T}) = unsafe_convert(Ptr{T}, x) +pointer{T}(x::AbstractArray{T}, i::Integer) = unsafe_convert(Ptr{T},x) + (i-1)*elsize(x) immutable RefArray{T, A<:AbstractArray, R} <: Ref{T} x::A @@ -55,17 +54,17 @@ RefArray{T}(x::AbstractArray{T},i::Int=1,roots::Void=nothing) = RefArray{T,typeo Base.convert{T}(::Type{Ref{T}}, x::AbstractArray{T}) = RefArray(x, 1) Ref(x::AbstractArray, i::Integer=1) = RefArray(x, i) -function Base.cconvert{T}(P::Type{Ptr{T}}, b::RefArray{T}) +function Base.unsafe_convert{T}(P::Type{Ptr{T}}, b::RefArray{T}) if isbits(T) convert(P, pointer(b.x, b.i)) else convert(P, data_pointer_from_objref(b.x[b.i])) end end -function Base.cconvert(P::Type{Ptr{Any}}, b::RefArray{Any}) +function Base.unsafe_convert(P::Type{Ptr{Any}}, b::RefArray{Any}) return convert(P, pointer(b.x, b.i)) end -Base.cconvert{T}(::Type{Ptr{Void}}, b::RefArray{T}) = Base.convert(Ptr{Void}, Base.cconvert(Ptr{T}, b)) +Base.unsafe_convert{T}(::Type{Ptr{Void}}, b::RefArray{T}) = Base.convert(Ptr{Void}, Base.unsafe_convert(Ptr{T}, b)) ### diff --git a/base/serialize.jl b/base/serialize.jl index 9fa97e041835d..68796e231ad9a 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -84,7 +84,7 @@ function serialize(s, x::Symbol) if haskey(ser_tag, x) return write_as_tag(s, x) end - pname = cconvert(Ptr{UInt8}, x) + pname = unsafe_convert(Ptr{UInt8}, x) ln = int(ccall(:strlen, Csize_t, (Ptr{UInt8},), pname)) if ln <= 255 writetag(s, Symbol) diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 60fc36f49e19c..0d544f80b5c03 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -139,7 +139,7 @@ sdata(A::AbstractArray) = A localindexes(S::SharedArray) = S.pidx > 0 ? range_1dim(S, S.pidx) : 1:0 -cconvert{T}(::Type{Ptr{T}}, S::SharedArray) = cconvert(Ptr{T}, sdata(S)) +unsafe_convert{T}(::Type{Ptr{T}}, S::SharedArray) = unsafe_convert(Ptr{T}, sdata(S)) convert(::Type{SharedArray}, A::Array) = (S = SharedArray(eltype(A), size(A)); copy!(S, A)) convert{T}(::Type{SharedArray{T}}, A::Array) = (S = SharedArray(T, size(A)); copy!(S, A)) diff --git a/base/socket.jl b/base/socket.jl index 24bb3b4e35073..341a172223522 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -324,7 +324,7 @@ end function uvfinalize(uv) close(uv) disassociate_julia_struct(uv) - uv.handle = 0 + uv.handle = C_NULL end isreadable(io::TCPSocket) = true @@ -395,11 +395,11 @@ function uvfinalize(uv::Union(TTY,Pipe,PipeServer,TCPServer,TCPSocket,UDPSocket) close(uv) end disassociate_julia_struct(uv) - uv.handle = 0 + uv.handle = C_NULL end function _uv_hook_close(sock::UDPSocket) - sock.handle = 0 + sock.handle = C_NULL sock.status = StatusClosed notify(sock.closenotify) notify(sock.sendnotify) diff --git a/base/stream.jl b/base/stream.jl index 4f5823b30c0ae..fd864df8c2e7d 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -472,7 +472,7 @@ end close(t::Timer) = ccall(:jl_close_uv,Void,(Ptr{Void},),t.handle) function _uv_hook_close(uv::Union(AsyncStream,UVServer)) - uv.handle = 0 + uv.handle = C_NULL uv.status = StatusClosed if isa(uv.closecb, Function) uv.closecb(uv) diff --git a/base/string.jl b/base/string.jl index f416f729711c4..6216538688619 100644 --- a/base/string.jl +++ b/base/string.jl @@ -646,7 +646,7 @@ function getindex(s::AbstractString, r::UnitRange{Int}) SubString(s, first(r), last(r)) end -function cconvert{P<:Union(Int8,UInt8),T<:ByteString}(::Type{Ptr{P}}, s::SubString{T}) +function unsafe_convert{P<:Union(Int8,UInt8),T<:ByteString}(::Type{Ptr{P}}, s::SubString{T}) if s.offset+s.endof < endof(s.string) throw(ArgumentError("a SubString must coincide with the end of the original string to be convertible to pointer")) end diff --git a/base/subarray.jl b/base/subarray.jl index e709b7d3b2471..64550b9ede7de 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -415,11 +415,11 @@ function subarray_linearindexing_dim{A<:AbstractArray}(::Type{A}, It::Tuple) LD end -cconvert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) = +unsafe_convert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{T}}, V::SubArray{T,N,P,I}) = pointer(V.parent) + (V.first_index-1)*sizeof(T) -cconvert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{Void}}, V::SubArray{T,N,P,I}) = - convert(Ptr{Void}, cconvert(Ptr{T}, V)) +unsafe_convert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{Void}}, V::SubArray{T,N,P,I}) = + convert(Ptr{Void}, unsafe_convert(Ptr{T}, V)) pointer(V::SubArray, i::Int) = pointer(V, ind2sub(size(V), i)) diff --git a/base/utf16.jl b/base/utf16.jl index c437b30edbad2..cab969691a708 100644 --- a/base/utf16.jl +++ b/base/utf16.jl @@ -75,7 +75,7 @@ convert(::Type{UTF8String}, s::UTF16String) = sprint(length(s.data)-1, io->for c in s; write(io,c::Char); end) sizeof(s::UTF16String) = sizeof(s.data) - sizeof(UInt16) -cconvert{T<:Union(Int16,UInt16)}(::Type{Ptr{T}}, s::UTF16String) = +unsafe_convert{T<:Union(Int16,UInt16)}(::Type{Ptr{T}}, s::UTF16String) = convert(Ptr{T}, pointer(s)) function is_valid_utf16(data::AbstractArray{UInt16}) diff --git a/base/utf32.jl b/base/utf32.jl index ecc5e844541d4..a88ad24409397 100644 --- a/base/utf32.jl +++ b/base/utf32.jl @@ -66,7 +66,7 @@ convert(::Type{Array{Char}}, s::UTF32String) = s.data reverse(s::UTF32String) = UTF32String(reverse!(copy(s.data), 1, length(s))) sizeof(s::UTF32String) = sizeof(s.data) - sizeof(Char) -cconvert{T<:Union(Int32,UInt32,Char)}(::Type{Ptr{T}}, s::UTF32String) = +unsafe_convert{T<:Union(Int32,UInt32,Char)}(::Type{Ptr{T}}, s::UTF32String) = convert(Ptr{T}, pointer(s)) function convert(T::Type{UTF32String}, bytes::AbstractArray{UInt8}) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 33d313165de60..240137c3283a7 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1011,8 +1011,8 @@ (let* ((g (make-jlgensym)) (isamp (and (pair? a) (eq? (car a) '&))) (a (if isamp (cadr a) a)) - (stmts (cons `(= ,g (call (top ,(if isamp 'ptr_arg_cconvert_gcroot 'cconvert_gcroot)) ,ty ,a)) stmts)) - (ca `(call (top ,(if isamp 'ptr_arg_cconvert 'cconvert)) ,ty ,g))) + (stmts (cons `(= ,g (call (top ,(if isamp 'ptr_arg_cconvert 'cconvert)) ,ty ,a)) stmts)) + (ca `(call (top ,(if isamp 'ptr_arg_unsafe_convert 'unsafe_convert)) ,ty ,g))) (loop (if isseq F (cdr F)) (cdr A) stmts (list* g (if isamp `(& ,ca) ca) C)))))))) diff --git a/test/core.jl b/test/core.jl index 649d4caad54fc..4147b55e23277 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1290,7 +1290,7 @@ type Z4681 x::Ptr{Void} Z4681() = new(C_NULL) end -Base.convert(::Type{Ptr{Z4681}},b::Z4681) = b.x +Base.unsafe_convert(::Type{Ptr{Z4681}},b::Z4681) = b.x @test_throws TypeError ccall(:printf,Int,(Ptr{UInt8},Ptr{Z4681}),"",Z4681()) # issue #4479 diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 19f73c802d5b8..9cefa210ac281 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -114,5 +114,4 @@ let ptr = Ptr{Void}(typemax(UInt)) @test ptr == Ptr{Void}(T(ptr)) @test typeof(Ptr{Float64}(T(ptr))) == Ptr{Float64} end - @test ptr == Ptr{Void}(Int8(-1)) # signed values are sign-extended to Int end