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/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 47edb5348b1e8..73be858fd6ab6 100644 --- a/base/array.jl +++ b/base/array.jl @@ -18,6 +18,29 @@ call{T}(::Type{Matrix{T}}, m::Integer, n::Integer) = Array{T}(m, n) ## Basic functions ## +# convert Arrays to pointer arrays for ccall +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(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{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) size(a::Matrix) = (arraysize(a,1), arraysize(a,2)) diff --git a/base/base.jl b/base/base.jl index eecfcfdcc7399..ed3a735c2c31f 100644 --- a/base/base.jl +++ b/base/base.jl @@ -52,16 +52,15 @@ 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{T}(::Type{Ptr{T}}, x) = cconvert(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/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/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/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 8b131d1f7e012..213b857a4b78b 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)) @@ -2119,8 +2132,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 @@ -2364,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, unsafe_convert) || is(f, cconvert) cost /= 4 end if !inline_worthy(body, cost) diff --git a/base/io.jl b/base/io.jl index f40ee1ee70aed..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 = convert(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 b6f7820559fa9..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, 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/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/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/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 277f084d06597..05d7f839c65de 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -7,27 +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 -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) +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(::Type{Ptr{UInt8}}, s::AbstractString) = bytestring(s) +cconvert(::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_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) @@ -52,8 +49,9 @@ 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)) -pointer_from_objref(x::Any) = ccall(:jl_value_ptr, Ptr{Void}, (Any,), x) +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) +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/process.jl b/base/process.jl index 469dc1f06a750..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) @@ -199,7 +198,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, @@ -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 @@ -339,10 +338,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 +555,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/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/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 diff --git a/base/refpointer.jl b/base/refpointer.jl new file mode 100644 index 0000000000000..32fa9b7f4a2a4 --- /dev/null +++ b/base/refpointer.jl @@ -0,0 +1,77 @@ +### 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 +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 + +type RefValue{T} <: Ref{T} + x::T + RefValue() = new() + RefValue(x) = new(x) +end +RefValue{T}(x::T) = RefValue{T}(x) + +Ref(x::Ref) = 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.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.unsafe_convert(P::Type{Ptr{Any}}, b::RefValue{Any}) + return convert(P, data_pointer_from_objref(b)) +end +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}) = 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 + i::Int + roots::R # should be either ::Void or ::Any + RefArray(x,i,roots=nothing) = (@assert(eltype(A) == T); new(x,i,roots)) +end +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.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.unsafe_convert(P::Type{Ptr{Any}}, b::RefArray{Any}) + return convert(P, pointer(b.x, b.i)) +end +Base.unsafe_convert{T}(::Type{Ptr{Void}}, b::RefArray{T}) = Base.convert(Ptr{Void}, Base.unsafe_convert(Ptr{T}, b)) + +### + +Base.getindex(b::RefValue) = b.x +Base.getindex(b::RefArray) = b.x[b.i] + +Base.setindex!(b::RefValue, x) = (b.x = x; b) +Base.setindex!(b::RefArray, x) = (b.x[b.i] = x; b) + +### diff --git a/base/serialize.jl b/base/serialize.jl index ee1174d0b47ce..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 = convert(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 6968c142e9522..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 -convert{T}(::Type{Ptr{T}}, S::SharedArray) = convert(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 ed76f649dc81d..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) @@ -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/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 feb5590651d75..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 convert{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 8373c04c879bc..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 -convert{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) -convert{T,N,P<:Array,I<:(RangeIndex...)}(::Type{Ptr{Void}}, V::SubArray{T,N,P,I}) = - convert(Ptr{Void}, convert(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/sysimg.jl b/base/sysimg.jl index 3b7577ee0496a..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") diff --git a/base/utf16.jl b/base/utf16.jl index c38ecbf1c735e..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) -convert{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 7e74fa290e95f..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) -convert{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/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 ac545d2ef108a..1102b28060bf0 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 ------------------------------------------------------------------- @@ -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); @@ -1200,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/src/ccall.cpp b/src/ccall.cpp index c34c58427dc4d..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) @@ -1000,7 +918,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 +930,25 @@ 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); + } 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]; + 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)); } - Value *ary = boxed(emit_expr(argi, ctx),ctx); 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); @@ -1032,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; @@ -1063,11 +996,9 @@ 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) { - 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 +1007,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]; @@ -1086,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); @@ -1116,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; } @@ -1172,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)); @@ -1221,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 e2b25908af677..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 @@ -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,19 +1842,20 @@ 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, - 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 7877ad1c11d8f..7813b5d4f9cc4 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 }; @@ -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; @@ -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/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..240137c3283a7 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 '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)))))))) (define (block-returns? e) (if (assignment? e) diff --git a/src/julia.h b/src/julia.h index bb43e8ed3013a..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) && @@ -800,7 +819,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..f83b90bffff5b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,11 +1,11 @@ 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 -$(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; +} diff --git a/test/core.jl b/test/core.jl index 3cbddf0b067cf..4147b55e23277 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) @@ -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