From 50a06e321ca02a0cb94cdff22546f96c0bb6a2e2 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 19 Apr 2016 19:17:01 -0400 Subject: [PATCH] separate Slot into SlotNumber and TypedSlot to save space serialize SlotNumber and GenSym more efficiently --- base/boot.jl | 8 ++-- base/expr.jl | 4 +- base/hashing.jl | 1 - base/inference.jl | 95 +++++++++++++++++++++++------------------------ base/show.jl | 4 +- src/alloc.c | 4 ++ src/ast.c | 11 ++---- src/builtins.c | 4 +- src/cgutils.cpp | 12 ++++-- src/codegen.cpp | 4 +- src/dump.c | 33 ++++++++++++---- src/interpreter.c | 6 +-- src/jltypes.c | 19 +++++++--- src/julia.h | 9 +++-- test/hashing.jl | 6 +-- 15 files changed, 125 insertions(+), 95 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 58a2382768a663..faec93a47fe9a5 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -139,7 +139,7 @@ export StackOverflowError, SegmentationFault, UndefRefError, UndefVarError, TypeError, # AST representation Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode, TopNode, - GlobalRef, NewvarNode, GenSym, Slot, + GlobalRef, NewvarNode, GenSym, Slot, SlotNumber, TypedSlot, # object model functions fieldtype, getfield, setfield!, nfields, throw, tuple, is, ===, isdefined, eval, # sizeof # not exported, to avoid conflicting with Base.sizeof @@ -277,13 +277,13 @@ _new(typ::Symbol, argty::Symbol) = eval(:((::Type{$typ})(n::$argty) = $(Expr(:ne _new(:LabelNode, :Int) _new(:GotoNode, :Int) _new(:TopNode, :Symbol) -_new(:NewvarNode, :Slot) +_new(:NewvarNode, :SlotNumber) _new(:QuoteNode, :ANY) _new(:GenSym, :Int) eval(:((::Type{LineNumberNode})(f::Symbol, l::Int) = $(Expr(:new, :LineNumberNode, :f, :l)))) eval(:((::Type{GlobalRef})(m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s)))) -eval(:((::Type{Slot})(n::Int) = $(Expr(:new, :Slot, :n, Any)))) -eval(:((::Type{Slot})(n::Int, t::ANY) = $(Expr(:new, :Slot, :n, :t)))) +eval(:((::Type{SlotNumber})(n::Int) = $(Expr(:new, :SlotNumber, :n)))) +eval(:((::Type{TypedSlot})(n::Int, t::ANY) = $(Expr(:new, :TypedSlot, :n, :t)))) Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool), name, std_imports) diff --git a/base/expr.jl b/base/expr.jl index 303a0a9159686c..132047b4e074ba 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -35,16 +35,14 @@ copy(e::Expr) = (n = Expr(e.head); n.args = astcopy(e.args); n.typ = e.typ; n) -copy(s::Slot) = Slot(s.id, s.typ) # copy parts of an AST that the compiler mutates -astcopy(x::Union{Slot,Expr}) = copy(x) +astcopy(x::Expr) = copy(x) astcopy(x::Array{Any,1}) = Any[astcopy(a) for a in x] astcopy(x) = x ==(x::Expr, y::Expr) = x.head === y.head && isequal(x.args, y.args) ==(x::QuoteNode, y::QuoteNode) = isequal(x.value, y.value) -==(x::Slot, y::Slot) = x.id === y.id && x.typ === y.typ expand(x::ANY) = ccall(:jl_expand, Any, (Any,), x) macroexpand(x::ANY) = ccall(:jl_macroexpand, Any, (Any,), x) diff --git a/base/hashing.jl b/base/hashing.jl index 0ea43d5fce927f..ab7ed4631b3def 100644 --- a/base/hashing.jl +++ b/base/hashing.jl @@ -63,7 +63,6 @@ else end hash(x::QuoteNode, h::UInt) = hash(x.value, hash(QuoteNode, h)) -hash(x::Slot, h::UInt) = hash(x.id, hash(x.typ, hash(Slot, h))) # hashing ranges by component at worst leads to collisions for very similar ranges const hashr_seed = UInt === UInt64 ? 0x80707b6821b70087 : 0x21b70087 diff --git a/base/inference.jl b/base/inference.jl index a321aba433f85b..e84a17ca8cade4 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1915,28 +1915,14 @@ function finish(me::InferenceState) nothing end -function record_var_type(s::Slot, t::ANY, decls) - t = widenconst(t) - otherTy = decls[s.id] - # keep track of whether a variable is always the same type - if !is(otherTy,NF) - if !typeseq(otherTy, t) - decls[s.id] = Any - end - else - decls[s.id] = t - end -end - -function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, decls, undefs) +function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, undefs) if isa(e, Slot) t = abstract_eval(e, vtypes, sv) s = vtypes[e.id] if s.undef undefs[e.id] = true end - record_var_type(e, t, decls) - return t === e.typ ? e : Slot(e.id, t) + return t === sv.linfo.slottypes[e.id] ? e : TypedSlot(e.id, t) end if !isa(e,Expr) @@ -1947,28 +1933,15 @@ function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, decls, undefs) head = e.head if is(head,:static_typeof) || is(head,:line) || is(head,:const) return e - #elseif is(head,:gotoifnot) || is(head,:return) - # e.typ = Any elseif is(head,:(=)) - # e.typ = Any - s = e.args[1] - # assignment LHS not subject to all-same-type variable checking, - # but the type of the RHS counts as one of its types. - e.args[2] = eval_annotate(e.args[2], vtypes, sv, decls, undefs) - if isa(s,Slot) - # TODO: if this def does not reach any uses, maybe don't do this - rhstype = exprtype(e.args[2], sv) - if !is(rhstype,Bottom) - record_var_type(s, rhstype, decls) - end - end + e.args[2] = eval_annotate(e.args[2], vtypes, sv, undefs) return e end i0 = is(head,:method) ? 2 : 1 for i=i0:length(e.args) subex = e.args[i] if !(isa(subex,Number) || isa(subex,AbstractString)) - e.args[i] = eval_annotate(subex, vtypes, sv, decls, undefs) + e.args[i] = eval_annotate(subex, vtypes, sv, undefs) end end return e @@ -1989,21 +1962,36 @@ end # annotate types of all symbols in AST function type_annotate!(linfo::LambdaInfo, states::Array{Any,1}, sv::ANY, rettype::ANY, nargs) nslots = length(states[1]) - decls = Any[ NF for i = 1:nslots ] - undefs = fill(false, nslots) - # initialize decls with argument types - for i = 1:nargs - decls[i] = widenconst(states[1][i].typ) + for i = 1:nslots + linfo.slottypes[i] = Bottom end + undefs = fill(false, nslots) body = linfo.code::Array{Any,1} nexpr = length(body) + for i=1:nexpr + # identify variables always used as the same type + st_i = states[i] + if st_i !== () + for j = 1:nslots + vt = widenconst(st_i[j].typ) + if vt !== Bottom + otherTy = linfo.slottypes[j] + if otherTy === Bottom + linfo.slottypes[j] = vt + elseif otherTy !== Any && !typeseq(otherTy, vt) + linfo.slottypes[j] = Any + end + end + end + end + end i = 1 optimize = sv.optimize::Bool while i <= nexpr st_i = states[i] if st_i !== () # st_i === () => unreached statement (see issue #7836) - body[i] = eval_annotate(body[i], st_i, sv, decls, undefs) + body[i] = eval_annotate(body[i], st_i, sv, undefs) elseif optimize expr = body[i] if isa(expr, Expr) && expr_cannot_delete(expr::Expr) @@ -2020,11 +2008,8 @@ function type_annotate!(linfo::LambdaInfo, states::Array{Any,1}, sv::ANY, rettyp i += 1 end - # add declarations for variables that are always the same type + # mark used-undef variables for i = 1:nslots - if decls[i] !== NF - linfo.slottypes[i] = decls[i] - end if undefs[i] linfo.slotflags[i] |= 32 end @@ -2034,7 +2019,7 @@ end # widen all Const elements in type annotations _widen_all_consts(x::ANY) = x -_widen_all_consts(x::Slot) = Slot(x.id, widenconst(x.typ)) +_widen_all_consts(x::TypedSlot) = TypedSlot(x.id, widenconst(x.typ)) function _widen_all_consts(x::Expr) x.typ = widenconst(x.typ) for i = 1:length(x.args) @@ -2059,7 +2044,11 @@ function substitute!(e::ANY, na, argexprs, spvals, offset) if 1 <= e.id <= na return argexprs[e.id] end - return Slot(e.id+offset, e.typ) + if isa(e, SlotNumber) + return SlotNumber(e.id+offset) + else + return TypedSlot(e.id+offset, e.typ) + end end if isa(e,NewvarNode) return NewvarNode(substitute!(e.slot, na, argexprs, spvals, offset)) @@ -2100,7 +2089,9 @@ end function exprtype(x::ANY, sv::InferenceState) if isa(x,Expr) return (x::Expr).typ - elseif isa(x,Slot) + elseif isa(x,SlotNumber) + return sv.linfo.slottypes[x.id] + elseif isa(x,TypedSlot) return (x::Slot).typ elseif isa(x,GenSym) return abstract_eval_gensym(x::GenSym, sv) @@ -2975,12 +2966,14 @@ function inlining_pass(e::Expr, sv, linfo) return (e,stmts) end +const compiler_temp_sym = symbol("#temp#") + function add_slot!(linfo::LambdaInfo, typ, is_sa) id = length(linfo.slotnames)+1 - push!(linfo.slotnames, :__temp__) + push!(linfo.slotnames, compiler_temp_sym) push!(linfo.slottypes, typ) push!(linfo.slotflags, 2+16*is_sa) - Slot(id, typ) + SlotNumber(id) end function is_known_call(e::Expr, func, sv) @@ -3049,7 +3042,8 @@ function remove_redundant_temp_vars(linfo, sa, T) # (from inlining improved type inference information) # and this transformation would worsen the type information # everywhere later in the function - if init.typ ⊑ (T===GenSym ? gensym_types[v+1] : linfo.slottypes[v]) + ityp = isa(init,TypedSlot) ? init.typ : linfo.slottypes[init.id] + if ityp ⊑ (T===GenSym ? gensym_types[v+1] : linfo.slottypes[v]) delete_var!(linfo, v, T) slot_replace!(linfo, v, init, T) end @@ -3279,8 +3273,11 @@ function replace_getfield!(linfo::LambdaInfo, e::Expr, tupname, vals, field_name # the tuple element expression that's replacing it. if isa(val,Slot) val = val::Slot - if a.typ ⊑ val.typ && !(val.typ ⊑ a.typ) - val.typ = a.typ + valtyp = isa(val,TypedSlot) ? val.typ : linfo.slottypes[val.id] + if a.typ ⊑ valtyp && !(valtyp ⊑ a.typ) + if isa(val,TypedSlot) + val = TypedSlot(val.id, a.typ) + end linfo.slottypes[val.id] = widenconst(a.typ) end elseif isa(val,GenSym) diff --git a/base/show.jl b/base/show.jl index e24f5720191f85..344f083fb16d93 100644 --- a/base/show.jl +++ b/base/show.jl @@ -526,7 +526,7 @@ show_unquoted(io::IO, ex::TopNode, ::Int, ::Int) = print(io,"top(",ex.nam show_unquoted(io::IO, ex::GlobalRef, ::Int, ::Int) = print(io, ex.mod, '.', ex.name) function show_unquoted(io::IO, ex::Slot, ::Int, ::Int) - typ = ex.typ + typ = isa(ex,TypedSlot) ? ex.typ : Any slotid = ex.id li = get(io, :LAMBDAINFO, false) if isa(li, LambdaInfo) @@ -545,7 +545,7 @@ function show_unquoted(io::IO, ex::Slot, ::Int, ::Int) print(io, "_", slotid) end emphstate = typeemphasize(io) - if emphstate || typ !== Any + if emphstate || (typ !== Any && isa(ex,TypedSlot)) show_expr_type(io, typ, emphstate) end end diff --git a/src/alloc.c b/src/alloc.c index 857e38c921f407..6609f789961c88 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1052,6 +1052,7 @@ UIBOX_FUNC(uint16, uint16_t, 1) UIBOX_FUNC(uint32, uint32_t, 1) UIBOX_FUNC(char, uint32_t, 1) UIBOX_FUNC(gensym, size_t, 1) +UIBOX_FUNC(slotnumber, size_t, 1) #ifdef _P64 SIBOX_FUNC(int64, int64_t, 1) UIBOX_FUNC(uint64, uint64_t, 1) @@ -1079,8 +1080,10 @@ void jl_init_int32_int64_cache(void) boxed_int64_cache[i] = jl_box64(jl_int64_type, i-NBOX_C/2); #ifdef _P64 boxed_gensym_cache[i] = jl_box64(jl_gensym_type, i); + boxed_slotnumber_cache[i] = jl_box64(jl_slotnumber_type, i); #else boxed_gensym_cache[i] = jl_box32(jl_gensym_type, i); + boxed_slotnumber_cache[i] = jl_box32(jl_slotnumber_type, i); #endif } for(i=0; i < 256; i++) { @@ -1119,6 +1122,7 @@ void jl_mark_box_caches(void) jl_gc_setmark(boxed_char_cache[i]); jl_gc_setmark(boxed_uint64_cache[i]); jl_gc_setmark(boxed_gensym_cache[i]); + jl_gc_setmark(boxed_slotnumber_cache[i]); } } diff --git a/src/ast.c b/src/ast.c index 1792fc773d38ea..187bb2738ad3db 100644 --- a/src/ast.c +++ b/src/ast.c @@ -443,13 +443,8 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, int eo) hd = car_(e); if (hd == jl_ast_ctx(fl_ctx)->jlgensym_sym) return jl_box_gensym(numval(car_(cdr_(e)))); - else if (hd == jl_ast_ctx(fl_ctx)->slot_sym) { - jl_value_t *slotnum = jl_box_long(numval(car_(cdr_(e)))); - JL_GC_PUSH1(&slotnum); - jl_value_t *res = jl_new_struct(jl_slot_type, slotnum, jl_any_type); - JL_GC_POP(); - return res; - } + else if (hd == jl_ast_ctx(fl_ctx)->slot_sym) + return jl_box_slotnumber(numval(car_(cdr_(e)))); else if (hd == jl_ast_ctx(fl_ctx)->null_sym && llength(e) == 1) return jl_nothing; } @@ -677,7 +672,7 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v) // GC Note: jl_fieldref(v, 0) allocate for LabelNode, GotoNode // but we don't need a GC root here because julia_to_list2 // shouldn't allocate in this case. - if (jl_typeis(v, jl_slot_type)) + if (jl_is_slot(v)) return julia_to_list2(fl_ctx, (jl_value_t*)slot_sym, jl_fieldref(v,0)); if (jl_typeis(v, jl_labelnode_type)) return julia_to_list2(fl_ctx, (jl_value_t*)label_sym, jl_fieldref(v,0)); diff --git a/src/builtins.c b/src/builtins.c index 7187595fb55a27..822d735ea367eb 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1140,7 +1140,9 @@ void jl_init_primitives(void) add_builtin("TypeMapLevel", (jl_value_t*)jl_typemap_level_type); add_builtin("Symbol", (jl_value_t*)jl_sym_type); add_builtin("GenSym", (jl_value_t*)jl_gensym_type); - add_builtin("Slot", (jl_value_t*)jl_slot_type); + add_builtin("Slot", (jl_value_t*)jl_abstractslot_type); + add_builtin("SlotNumber", (jl_value_t*)jl_slotnumber_type); + add_builtin("TypedSlot", (jl_value_t*)jl_typedslot_type); add_builtin("IntrinsicFunction", (jl_value_t*)jl_intrinsic_type); add_builtin("Function", (jl_value_t*)jl_function_type); add_builtin("Builtin", (jl_value_t*)jl_builtin_type); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 371082969831c8..9779cd58ca2194 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -857,8 +857,14 @@ static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx) jl_array_t *gensym_types = (jl_array_t*)ctx->linfo->gensymtypes; return jl_cellref(gensym_types, idx); } - if (jl_typeis(e, jl_slot_type)) { - jl_value_t *typ = jl_slot_get_type(e); + if (jl_typeis(e, jl_slotnumber_type)) { + jl_array_t *slot_types = (jl_array_t*)ctx->linfo->slottypes; + if (!jl_is_array(slot_types)) + return (jl_value_t*)jl_any_type; + return jl_cellref(slot_types, jl_slot_number(e)-1); + } + if (jl_typeis(e, jl_typedslot_type)) { + jl_value_t *typ = jl_typedslot_get_type(e); if (jl_is_typevar(typ)) typ = ((jl_tvar_t*)typ)->ub; return typ; @@ -1558,7 +1564,7 @@ static void emit_setfield(jl_datatype_t *sty, const jl_cgval_t &strct, size_t id static bool might_need_root(jl_value_t *ex) { - return (!jl_is_symbol(ex) && !jl_typeis(ex, jl_slot_type) && !jl_is_gensym(ex) && + return (!jl_is_symbol(ex) && !jl_is_slot(ex) && !jl_is_gensym(ex) && !jl_is_bool(ex) && !jl_is_quotenode(ex) && !jl_is_byte_string(ex) && !jl_is_globalref(ex)); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 492e87ff402095..e72315ee5ee9bd 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1521,7 +1521,7 @@ jl_value_t *jl_static_eval(jl_value_t *ex, void *ctx_, jl_module_t *mod, return jl_get_global(mod, sym); return NULL; } - if (jl_typeis(ex,jl_slot_type)) + if (jl_is_slot(ex)) return NULL; if (jl_is_gensym(ex)) { ssize_t idx = ((jl_gensym_t*)ex)->id; @@ -2889,7 +2889,7 @@ static jl_cgval_t emit_local(jl_value_t *slotload, jl_codectx_t *ctx) jl_value_t *typ; if (ctx->linfo->inferred) { // use the better type from inference for this load - typ = jl_slot_get_type(slotload); + typ = expr_type(slotload, ctx); if (jl_is_typevar(typ)) typ = ((jl_tvar_t*)typ)->ub; } diff --git a/src/dump.c b/src/dump.c index e30af872043451..8b7c840493da94 100644 --- a/src/dump.c +++ b/src/dump.c @@ -757,6 +757,14 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) jl_serialize_value(s, jl_globalref_name(v)); } } + else if (jl_is_gensym(v) && ((jl_gensym_t*)v)->id < 65536) { + writetag(s, (jl_value_t*)jl_gensym_type); + write_uint16(s, ((jl_gensym_t*)v)->id); + } + else if (jl_typeis(v,jl_slotnumber_type) && jl_slot_number(v) < 65536) { + writetag(s, (jl_value_t*)jl_slotnumber_type); + write_uint16(s, jl_slot_number(v)); + } else if (jl_is_array(v)) { jl_array_t *ar = (jl_array_t*)v; if (ar->flags.ndims == 1 && ar->elsize < 128) { @@ -1333,6 +1341,16 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t arraylist_push(&backref_list, sym); return sym; } + else if (vtag == (jl_value_t*)jl_gensym_type) { + jl_value_t *v = jl_box_gensym(read_uint16(s)); + if (usetable) arraylist_push(&backref_list, v); + return v; + } + else if (vtag == (jl_value_t*)jl_slotnumber_type) { + jl_value_t *v = jl_box_slotnumber(read_uint16(s)); + if (usetable) arraylist_push(&backref_list, v); + return v; + } else if (vtag == (jl_value_t*)jl_array_type || vtag == (jl_value_t*)Array1d_tag) { int16_t ndims; @@ -2347,8 +2365,8 @@ void jl_init_serializer(void) htable_new(&fptr_to_id, sizeof(id_to_fptrs)/sizeof(*id_to_fptrs)); htable_new(&backref_table, 0); - void *tags[] = { jl_symbol_type, jl_gensym_type, jl_datatype_type, - jl_simplevector_type, jl_array_type, jl_slot_type, + void *tags[] = { jl_symbol_type, jl_gensym_type, jl_datatype_type, jl_slotnumber_type, + jl_simplevector_type, jl_array_type, jl_typedslot_type, jl_expr_type, (void*)LongSymbol_tag, (void*)LongSvec_tag, (void*)LongExpr_tag, (void*)LiteralVal_tag, (void*)SmallInt64_tag, (void*)SmallDataType_tag, @@ -2379,8 +2397,7 @@ void jl_init_serializer(void) jl_box_int32(33), jl_box_int32(34), jl_box_int32(35), jl_box_int32(36), jl_box_int32(37), jl_box_int32(38), jl_box_int32(39), jl_box_int32(40), jl_box_int32(41), - jl_box_int32(42), jl_box_int32(43), jl_box_int32(44), - jl_box_int32(45), jl_box_int32(46), jl_box_int32(47), + jl_box_int32(42), jl_box_int32(43), #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), @@ -2397,8 +2414,7 @@ void jl_init_serializer(void) jl_box_int64(33), jl_box_int64(34), jl_box_int64(35), jl_box_int64(36), jl_box_int64(37), jl_box_int64(38), jl_box_int64(39), jl_box_int64(40), jl_box_int64(41), - jl_box_int64(42), jl_box_int64(43), jl_box_int64(44), - jl_box_int64(45), jl_box_int64(46), jl_box_int64(47), + jl_box_int64(42), jl_box_int64(43), #endif jl_labelnode_type, jl_linenumbernode_type, jl_gotonode_type, jl_quotenode_type, jl_topnode_type, @@ -2407,7 +2423,7 @@ void jl_init_serializer(void) jl_densearray_type, jl_void_type, jl_function_type, jl_typector_type, jl_typename_type, jl_builtin_type, jl_task_type, jl_uniontype_type, jl_typetype_type, jl_typetype_tvar, - jl_ANY_flag, jl_array_any_type, jl_intrinsic_type, + jl_ANY_flag, jl_array_any_type, jl_intrinsic_type, jl_abstractslot_type, jl_methtable_type, jl_typemap_level_type, jl_typemap_entry_type, jl_voidpointer_type, jl_newvarnode_type, jl_array_symbol_type, jl_anytuple_type, jl_tparam0(jl_anytuple_type), @@ -2419,7 +2435,8 @@ void jl_init_serializer(void) jl_methtable_type->name, jl_typemap_level_type->name, jl_typemap_entry_type->name, jl_tvar_type->name, jl_ntuple_type->name, jl_abstractarray_type->name, jl_vararg_type->name, jl_densearray_type->name, jl_void_type->name, jl_lambda_info_type->name, jl_method_type->name, - jl_module_type->name, jl_function_type->name, jl_slot_type->name, + jl_module_type->name, jl_function_type->name, jl_typedslot_type->name, + jl_abstractslot_type->name, jl_slotnumber_type->name, jl_typector_type->name, jl_intrinsic_type->name, jl_task_type->name, jl_labelnode_type->name, jl_linenumbernode_type->name, jl_builtin_type->name, jl_gotonode_type->name, jl_quotenode_type->name, jl_topnode_type->name, diff --git a/src/interpreter.c b/src/interpreter.c index fb55d5bc9dbc96..2ce282d8d280b3 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -148,7 +148,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, jl_lambda_info_t *la return v; } if (!jl_is_expr(e)) { - if (jl_typeis(e, jl_slot_type)) { + if (jl_is_slot(e)) { ssize_t n = jl_slot_number(e); if (n > jl_linfo_nslots(lam) || n < 1 || locals == NULL) jl_error("access to invalid slot number"); @@ -166,7 +166,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, jl_lambda_info_t *la } if (jl_is_newvarnode(e)) { jl_value_t *var = jl_fieldref(e,0); - assert(jl_typeis(var,jl_slot_type)); + assert(jl_is_slot(var)); ssize_t n = jl_slot_number(var); assert(n <= jl_linfo_nslots(lam) && n > 0); locals[n-1] = NULL; @@ -189,7 +189,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, jl_lambda_info_t *la jl_error("assignment to invalid GenSym location"); locals[jl_linfo_nslots(lam) + genid] = rhs; } - else if (jl_typeis(sym,jl_slot_type)) { + else if (jl_is_slot(sym)) { ssize_t n = jl_slot_number(sym); assert(n <= jl_linfo_nslots(lam) && n > 0); locals[n-1] = rhs; diff --git a/src/jltypes.c b/src/jltypes.c index bde4e445f49d8c..7c3c29bf148984 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -26,7 +26,9 @@ jl_datatype_t *jl_typename_type; jl_datatype_t *jl_sym_type; jl_datatype_t *jl_symbol_type; jl_datatype_t *jl_gensym_type; -jl_datatype_t *jl_slot_type; +jl_datatype_t *jl_abstractslot_type; +jl_datatype_t *jl_slotnumber_type; +jl_datatype_t *jl_typedslot_type; jl_datatype_t *jl_simplevector_type; jl_typename_t *jl_tuple_typename; jl_tupletype_t *jl_anytuple_type; @@ -3356,9 +3358,16 @@ void jl_init_types(void) jl_svec1(jl_symbol("id")), jl_svec1(jl_long_type), 0, 0, 1); - jl_slot_type = jl_new_datatype(jl_symbol("Slot"), jl_any_type, jl_emptysvec, - jl_svec(2, jl_symbol("id"), jl_symbol("typ")), - jl_svec(2, jl_long_type, jl_any_type), 0, 0, 2); + jl_abstractslot_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Slot"), jl_any_type, + jl_emptysvec); + + jl_slotnumber_type = jl_new_datatype(jl_symbol("SlotNumber"), jl_abstractslot_type, jl_emptysvec, + jl_svec1(jl_symbol("id")), + jl_svec1(jl_long_type), 0, 0, 1); + + jl_typedslot_type = jl_new_datatype(jl_symbol("TypedSlot"), jl_abstractslot_type, jl_emptysvec, + jl_svec(2, jl_symbol("id"), jl_symbol("typ")), + jl_svec(2, jl_long_type, jl_any_type), 0, 0, 2); jl_init_int32_int64_cache(); @@ -3466,7 +3475,7 @@ void jl_init_types(void) jl_newvarnode_type = jl_new_datatype(jl_symbol("NewvarNode"), jl_any_type, jl_emptysvec, jl_svec(1, jl_symbol("slot")), - jl_svec(1, jl_slot_type), 0, 0, 1); + jl_svec(1, jl_slotnumber_type), 0, 0, 1); jl_topnode_type = jl_new_datatype(jl_symbol("TopNode"), jl_any_type, jl_emptysvec, diff --git a/src/julia.h b/src/julia.h index 1c40c8e33283c4..9c5174364052f7 100644 --- a/src/julia.h +++ b/src/julia.h @@ -436,7 +436,9 @@ extern JL_DLLEXPORT jl_datatype_t *jl_typector_type; extern JL_DLLEXPORT jl_datatype_t *jl_sym_type; extern JL_DLLEXPORT jl_datatype_t *jl_symbol_type; extern JL_DLLEXPORT jl_datatype_t *jl_gensym_type; -extern JL_DLLEXPORT jl_datatype_t *jl_slot_type; +extern JL_DLLEXPORT jl_datatype_t *jl_abstractslot_type; +extern JL_DLLEXPORT jl_datatype_t *jl_slotnumber_type; +extern JL_DLLEXPORT jl_datatype_t *jl_typedslot_type; extern JL_DLLEXPORT jl_datatype_t *jl_simplevector_type; extern JL_DLLEXPORT jl_typename_t *jl_tuple_typename; extern JL_DLLEXPORT jl_datatype_t *jl_anytuple_type; @@ -726,7 +728,7 @@ STATIC_INLINE void jl_array_uint8_set(void *a, size_t i, uint8_t x) #define jl_linenode_line(x) (((intptr_t*)x)[1]) #define jl_labelnode_label(x) (((intptr_t*)x)[0]) #define jl_slot_number(x) (((intptr_t*)x)[0]) -#define jl_slot_get_type(x) (((jl_value_t**)x)[1]) +#define jl_typedslot_get_type(x) (((jl_value_t**)x)[1]) #define jl_gotonode_label(x) (((intptr_t*)x)[0]) #define jl_globalref_mod(s) (*(jl_module_t**)s) #define jl_globalref_name(s) (((jl_sym_t**)s)[1]) @@ -841,7 +843,7 @@ static inline uint32_t jl_fielddesc_size(int8_t fielddesc_type) #define jl_is_bool(v) jl_typeis(v,jl_bool_type) #define jl_is_symbol(v) jl_typeis(v,jl_sym_type) #define jl_is_gensym(v) jl_typeis(v,jl_gensym_type) -#define jl_is_slot(v) jl_typeis(v,jl_slot_type) +#define jl_is_slot(v) (jl_typeis(v,jl_slotnumber_type) || jl_typeis(v,jl_typedslot_type)) #define jl_is_expr(v) jl_typeis(v,jl_expr_type) #define jl_is_globalref(v) jl_typeis(v,jl_globalref_type) #define jl_is_labelnode(v) jl_typeis(v,jl_labelnode_type) @@ -1037,6 +1039,7 @@ JL_DLLEXPORT jl_value_t *jl_box_float32(float x); JL_DLLEXPORT jl_value_t *jl_box_float64(double x); JL_DLLEXPORT jl_value_t *jl_box_voidpointer(void *x); JL_DLLEXPORT jl_value_t *jl_box_gensym(size_t x); +JL_DLLEXPORT jl_value_t *jl_box_slotnumber(size_t x); JL_DLLEXPORT jl_value_t *jl_box8 (jl_datatype_t *t, int8_t x); JL_DLLEXPORT jl_value_t *jl_box16(jl_datatype_t *t, int16_t x); JL_DLLEXPORT jl_value_t *jl_box32(jl_datatype_t *t, int32_t x); diff --git a/test/hashing.jl b/test/hashing.jl index 9a28d1c37388ff..98bf8a4a0788a8 100644 --- a/test/hashing.jl +++ b/test/hashing.jl @@ -95,9 +95,9 @@ let a = QuoteNode(1), b = QuoteNode(1.0) @test (hash(a)==hash(b)) == (a==b) end -let a = Expr(:block, Slot(1, Any)), - b = Expr(:block, Slot(1, Any)), - c = Expr(:block, Slot(3, Any)) +let a = Expr(:block, TypedSlot(1, Any)), + b = Expr(:block, TypedSlot(1, Any)), + c = Expr(:block, TypedSlot(3, Any)) @test a == b && hash(a) == hash(b) @test a != c && hash(a) != hash(c) @test b != c && hash(b) != hash(c)