From 16c96c21e2688aa3e966a15d3a386c7434ec3c5d Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Sun, 24 May 2015 16:17:56 -0400 Subject: [PATCH 1/2] Allow const declarations, read and store const field info --- src/alloc.c | 5 +++-- src/builtins.c | 3 +++ src/cgutils.cpp | 2 +- src/codegen.cpp | 19 ++++++++++++++++++- src/interpreter.c | 4 ++-- src/jltypes.c | 42 +++++++++++++++++++++++------------------- src/julia-parser.scm | 7 +------ src/julia-syntax.scm | 24 +++++++++++++++++++----- src/julia.h | 6 ++++-- src/julia_internal.h | 2 +- 10 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 913982d236e74..1610819f01c77 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -524,7 +524,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields) return t; } -void jl_compute_field_offsets(jl_datatype_t *st) +void jl_compute_field_offsets(jl_datatype_t *st, jl_svec_t *consts) { size_t sz = 0, alignm = 1; int ptrfree = 1; @@ -556,6 +556,7 @@ void jl_compute_field_offsets(jl_datatype_t *st) jl_throw(jl_overflow_exception); st->fields[i].offset = sz; st->fields[i].size = fsz; + st->fields[i].isconst = (jl_svec_len(consts) == 0) ? 0 : jl_svecref(consts, i)==jl_true; sz += fsz; } st->alignment = alignm; @@ -628,7 +629,7 @@ jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, else { t->uid = jl_assign_type_uid(); if (t->types != NULL) - jl_compute_field_offsets(t); + jl_compute_field_offsets(t, jl_emptysvec); } JL_GC_POP(); return t; diff --git a/src/builtins.c b/src/builtins.c index 84a81384ccc06..59583bcfdda70 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -704,6 +704,9 @@ JL_CALLABLE(jl_f_set_field) if (!jl_subtype(args[2], ft, 1)) { jl_type_error("setfield!", ft, args[2]); } + if (st->fields[idx].isconst) { + jl_errorf("field in type %s is immutable", st->name->name->name); + } jl_set_nth_field(v, idx, args[2]); return args[2]; } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 85e659aaf4b1e..04ac661e85123 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1805,7 +1805,7 @@ static void emit_checked_write_barrier(jl_codectx_t *ctx, Value *parent, Value * static Value *emit_setfield(jl_datatype_t *sty, Value *strct, size_t idx0, Value *rhs, jl_codectx_t *ctx, bool checked, bool wb) { - if (sty->mutabl || !checked) { + if ((sty->mutabl && !(sty->fields[idx0].isconst)) || !checked) { Value *addr = builder.CreateGEP(builder.CreateBitCast(strct, T_pint8), ConstantInt::get(T_size, sty->fields[idx0].offset)); diff --git a/src/codegen.cpp b/src/codegen.cpp index 5a0a71c4673da..3d896cde10d0f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1566,6 +1566,23 @@ static bool isbits_spec(jl_value_t *jt, bool allow_unsized = true) (jl_is_datatype(jt) && jl_datatype_nfields(jt)>0))); } +static bool is_constant_field(jl_datatype_t *ty, jl_value_t *fld) +{ + if (!jl_is_leaf_type((jl_value_t*)ty)) + return false; + jl_sym_t *name = NULL; + if (jl_is_quotenode(fld) && jl_is_symbol(jl_fieldref(fld,0))) { + name = (jl_sym_t*)jl_fieldref(fld,0); + } + for(size_t i=0; i < jl_svec_len(ty->types); i++) { + if (ty->fields[i].isconst && + (name && name == jl_field_name(ty,i))) { + return true; + } + } + return false; +} + // does "ex" compute something that doesn't need a root over the whole function? static bool is_stable_expr(jl_value_t *ex, jl_codectx_t *ctx) { @@ -1592,7 +1609,7 @@ static bool is_stable_expr(jl_value_t *ex, jl_codectx_t *ctx) // something reached via getfield from a stable value is also stable. if (jl_array_dim0(e->args) == 3) { jl_value_t *ty = expr_type(jl_exprarg(e,1), ctx); - if ((fptr == &jl_f_get_field && jl_is_immutable_datatype(ty) && + if ((fptr == &jl_f_get_field && (jl_is_immutable_datatype(ty) || is_constant_field((jl_datatype_t*)ty, jl_exprarg(e,2))) && is_getfield_nonallocating((jl_datatype_t*)ty, jl_exprarg(e,2)))) { if (is_stable_expr(jl_exprarg(e,1), ctx)) return true; diff --git a/src/interpreter.c b/src/interpreter.c index 2f4494fc7030c..f921cae21f8bb 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -395,7 +395,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ng temp = eval(args[2], locals, nl, ngensym); // field names dt = jl_new_datatype((jl_sym_t*)name, jl_any_type, (jl_svec_t*)para, (jl_svec_t*)temp, NULL, - 0, args[5]==jl_true ? 1 : 0, jl_unbox_long(args[6])); + 0, args[6]==jl_true ? 1 : 0, jl_unbox_long(args[7])); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; // save old value @@ -421,7 +421,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ng for(size_t i=0; i < jl_svec_len(para); i++) { ((jl_tvar_t*)jl_svecref(para,i))->bound = 0; } - jl_compute_field_offsets(dt); + jl_compute_field_offsets(dt, (jl_svec_t*)eval(args[5], locals, nl, ngensym)); if (para == (jl_value_t*)jl_emptysvec && jl_is_datatype_singleton(dt)) { dt->instance = newstruct(dt); gc_wb(dt, dt->instance); diff --git a/src/jltypes.c b/src/jltypes.c index 527554b3e6343..0ee037cf25def 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2007,7 +2007,11 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i ndt->pointerfree = dt->pointerfree; } else { - jl_compute_field_offsets(ndt); + int i; + jl_compute_field_offsets(ndt, jl_emptysvec); + for (i=0; i < jl_svec_len(ftypes); i++) { + ndt->fields[i].isconst = dt->fields[i].isconst; + } } if (jl_is_datatype_singleton(ndt)) { ndt->instance = newstruct(ndt); @@ -3391,24 +3395,24 @@ void jl_init_types(void) jl_svecset(jl_simplevector_type->types, 0, jl_long_type); jl_svecset(jl_typename_type->types, 6, jl_long_type); - jl_compute_field_offsets(jl_datatype_type); - jl_compute_field_offsets(jl_typename_type); - jl_compute_field_offsets(jl_uniontype_type); - jl_compute_field_offsets(jl_tvar_type); - jl_compute_field_offsets(jl_method_type); - jl_compute_field_offsets(jl_methtable_type); - jl_compute_field_offsets(jl_expr_type); - jl_compute_field_offsets(jl_linenumbernode_type); - jl_compute_field_offsets(jl_labelnode_type); - jl_compute_field_offsets(jl_gotonode_type); - jl_compute_field_offsets(jl_quotenode_type); - jl_compute_field_offsets(jl_topnode_type); - jl_compute_field_offsets(jl_module_type); - jl_compute_field_offsets(jl_lambda_info_type); - jl_compute_field_offsets(jl_box_type); - jl_compute_field_offsets(jl_typector_type); - jl_compute_field_offsets(jl_function_type); - jl_compute_field_offsets(jl_simplevector_type); + jl_compute_field_offsets(jl_datatype_type, jl_emptysvec); + jl_compute_field_offsets(jl_typename_type, jl_emptysvec); + jl_compute_field_offsets(jl_uniontype_type, jl_emptysvec); + jl_compute_field_offsets(jl_tvar_type, jl_emptysvec); + jl_compute_field_offsets(jl_method_type, jl_emptysvec); + jl_compute_field_offsets(jl_methtable_type, jl_emptysvec); + jl_compute_field_offsets(jl_expr_type, jl_emptysvec); + jl_compute_field_offsets(jl_linenumbernode_type, jl_emptysvec); + jl_compute_field_offsets(jl_labelnode_type, jl_emptysvec); + jl_compute_field_offsets(jl_gotonode_type, jl_emptysvec); + jl_compute_field_offsets(jl_quotenode_type, jl_emptysvec); + jl_compute_field_offsets(jl_topnode_type, jl_emptysvec); + jl_compute_field_offsets(jl_module_type, jl_emptysvec); + jl_compute_field_offsets(jl_lambda_info_type, jl_emptysvec); + jl_compute_field_offsets(jl_box_type, jl_emptysvec); + jl_compute_field_offsets(jl_typector_type, jl_emptysvec); + jl_compute_field_offsets(jl_function_type, jl_emptysvec); + jl_compute_field_offsets(jl_simplevector_type, jl_emptysvec); jl_simplevector_type->pointerfree = 0; call_sym = jl_symbol("call"); diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 36981c0ea0d50..ea1d2d05c7872 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -1217,12 +1217,7 @@ ((break continue) (list word)) ((const) (let ((assgn (parse-eq s))) - (if (not (and (pair? assgn) - (or (eq? (car assgn) '=) - (eq? (car assgn) 'global) - (eq? (car assgn) 'local)))) - (error "expected assignment after \"const\"") - `(const ,assgn)))) + `(const ,assgn))) ((module baremodule) (let* ((name (parse-unary-prefix s)) (body (parse-block s))) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 5718e656e3ec4..c0eb3dff02765 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -126,6 +126,9 @@ (define (llist-types lst) (map arg-type lst)) +(define (const-decl? e) + (and (pair? e) (eq? (car e) 'const) (eq? (caadr e) '|::|))) + (define (decl? e) (and (pair? e) (eq? (car e) '|::|))) @@ -137,10 +140,18 @@ ; get the variable name part of a declaration, x::int => x (define (decl-var v) - (if (decl? v) (cadr v) v)) + (if (decl? v) + (cadr v) + (if (const-decl? v) + (cadadr v) + v))) (define (decl-type v) - (if (decl? v) (caddr v) 'Any)) + (if (decl? v) + (caddr v) + (if (const-decl? v) + (caddr (cadr v)) + 'Any))) (define (sym-dot? e) (and (length= e 3) (eq? (car e) '|.|) @@ -922,11 +933,12 @@ (define (struct-def-expr- name params bounds super fields mut) (receive - (fields defs) (separate (lambda (x) (or (symbol? x) (decl? x))) + (fields defs) (separate (lambda (x) (or (symbol? x) (decl? x) (const-decl? x))) fields) (let* ((defs (filter (lambda (x) (not (effect-free? x))) defs)) (field-names (map decl-var fields)) (field-types (map decl-type fields)) + (field-const (map const-decl? fields)) (defs2 (if (null? defs) (default-inner-ctors name field-names field-types (null? params)) defs)) @@ -940,7 +952,8 @@ (global ,name) (const ,name) (composite_type ,name (call (top svec) ,@params) (call (top svec) ,@(map (lambda (x) `',x) field-names)) - ,super (call (top svec) ,@field-types) ,mut ,min-initialized) + ,super (call (top svec) ,@field-types) + (call (top svec) ,@field-const) ,mut ,min-initialized) (call (lambda () (scope-block @@ -959,7 +972,8 @@ ,@(map make-assignment params (symbols->typevars params bounds #t)) (composite_type ,name (call (top svec) ,@params) (call (top svec) ,@(map (lambda (x) `',x) field-names)) - ,super (call (top svec) ,@field-types) ,mut ,min-initialized))) + ,super (call (top svec) ,@field-types) + (call (top svec) ,@field-const) ,mut ,min-initialized))) ;; "inner" constructors (call (lambda () diff --git a/src/julia.h b/src/julia.h index 7d92895e9a9ea..a65e13cdd61e6 100644 --- a/src/julia.h +++ b/src/julia.h @@ -261,12 +261,13 @@ typedef struct { typedef struct { uint16_t offset; // offset relative to data start, excluding type tag - uint16_t size:15; + uint16_t size:14; + uint16_t isconst:1; uint16_t isptr:1; } jl_fielddesc_t; #define JL_FIELD_MAX_OFFSET ((1ul << 16) - 1ul) -#define JL_FIELD_MAX_SIZE ((1ul << 15) - 1ul) +#define JL_FIELD_MAX_SIZE ((1ul << 14) - 1ul) typedef struct _jl_datatype_t { JL_DATA_TYPE @@ -739,6 +740,7 @@ STATIC_INLINE jl_value_t *jl_cellset(void *a, size_t i, void *x) #define jl_field_offset(st,i) (((jl_datatype_t*)st)->fields[i].offset) #define jl_field_size(st,i) (((jl_datatype_t*)st)->fields[i].size) #define jl_field_isptr(st,i) (((jl_datatype_t*)st)->fields[i].isptr) +#define jl_field_isconst(st,i) (((jl_datatype_t*)st)->fields[i].isconst) #define jl_field_name(st,i) (jl_sym_t*)jl_svecref(((jl_datatype_t*)st)->name->names, (i)) #define jl_field_type(st,i) jl_svecref(((jl_datatype_t*)st)->types, (i)) #define jl_datatype_size(t) (((jl_datatype_t*)t)->size) diff --git a/src/julia_internal.h b/src/julia_internal.h index 2474f70bf1017..044c20b62f240 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -95,7 +95,7 @@ void jl_initialize_generic_function(jl_function_t *f, jl_sym_t *name); void jl_add_constructors(jl_datatype_t *t); jl_value_t *jl_nth_slot_type(jl_tupletype_t *sig, size_t i); -void jl_compute_field_offsets(jl_datatype_t *st); +void jl_compute_field_offsets(jl_datatype_t *st, jl_svec_t *consts); jl_array_t *jl_new_array_for_deserialization(jl_value_t *atype, uint32_t ndims, size_t *dims, int isunboxed, int elsz); #ifdef JL_USE_INTEL_JITEVENTS From dc300d701dd3a05b1fd241c2d6c662b0dc090dd3 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Sun, 24 May 2015 16:18:12 -0400 Subject: [PATCH 2/2] Make the BitArray chunks field constant --- base/bitarray.jl | 14 ++++++++------ base/mmap.jl | 8 +------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/base/bitarray.jl b/base/bitarray.jl index 14cb014aa2cb8..ef716daa3a703 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -5,7 +5,7 @@ # notes: bits are stored in contiguous chunks # unused bits must always be set to 0 type BitArray{N} <: DenseArray{Bool, N} - chunks::Vector{UInt64} + const chunks::Vector{UInt64} len::Int dims::NTuple{N,Int} function BitArray(dims::Int...) @@ -24,6 +24,12 @@ type BitArray{N} <: DenseArray{Bool, N} N != 1 && (b.dims = dims) return b end + + function BitArray(chunks::Vector{UInt64}, dims::NTuple{N,Int}) + len = prod(dims) + num_bit_chunks(len) <= length(chunks) || throw(ArgumentError("chunks vector is too short for the given dimensions")) + return new(chunks, len, dims) + end end BitArray{N}(dims::NTuple{N,Int}) = BitArray{N}(dims...) @@ -280,11 +286,7 @@ function reshape{N}(B::BitArray, dims::NTuple{N,Int}) prod(dims) == length(B) || throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(B))")) dims == size(B) && return B - Br = BitArray{N}(ntuple(N,i->0)...) - Br.chunks = B.chunks - Br.len = prod(dims) - N != 1 && (Br.dims = dims) - return Br + return BitArray{N}(B.chunks, dims) end ## Conversions ## diff --git a/base/mmap.jl b/base/mmap.jl index 9ed92112f8325..82720c3c6eee0 100644 --- a/base/mmap.jl +++ b/base/mmap.jl @@ -166,11 +166,5 @@ function mmap_bitarray{N}(dims::NTuple{N,Integer}, s::IOStream, offset::FileOffs throw(ArgumentError("the given file does not contain a valid BitArray of size $(join(dims, 'x')) (open with \"r+\" mode to override)")) end end - B = BitArray{N}(ntuple(N,i->0)...) - B.chunks = chunks - B.len = n - if N != 1 - B.dims = dims - end - return B + return BitArray{N}(chunks, dims) end