diff options
author | Damien Doligez <damien.doligez@inria.fr> | 2016-05-25 16:29:05 +0200 |
---|---|---|
committer | Damien Doligez <damien.doligez@inria.fr> | 2016-07-21 13:51:46 +0200 |
commit | d5a6e50ebee73ff98c4179bba7570cdd9e488a35 (patch) | |
tree | e47a161d4a0d06c3266ddd3eabb0abd6a9e1ba3d | |
parent | e82191fea3890426e4499668041c14694fef8dd2 (diff) | |
download | ocaml-d5a6e50ebee73ff98c4179bba7570cdd9e488a35.tar.gz |
GPR#606: add unboxed types
58 files changed, 882 insertions, 113 deletions
@@ -1,5 +1,5 @@ -utils/arg_helper.cmo : utils/arg_helper.cmi -utils/arg_helper.cmx : utils/arg_helper.cmi +utils/arg_helper.cmo : utils/misc.cmi utils/arg_helper.cmi +utils/arg_helper.cmx : utils/misc.cmx utils/arg_helper.cmi utils/arg_helper.cmi : utils/ccomp.cmo : utils/misc.cmi utils/config.cmi utils/clflags.cmi \ utils/ccomp.cmi @@ -180,11 +180,11 @@ typing/ctype.cmx : typing/types.cmx typing/subst.cmx typing/predef.cmx \ typing/ctype.cmi : typing/types.cmi typing/path.cmi parsing/longident.cmi \ typing/ident.cmi typing/env.cmi parsing/asttypes.cmi typing/datarepr.cmo : typing/types.cmi typing/path.cmi parsing/location.cmi \ - typing/ident.cmi typing/btype.cmi parsing/asttypes.cmi \ - typing/datarepr.cmi + typing/ident.cmi parsing/builtin_attributes.cmi typing/btype.cmi \ + parsing/asttypes.cmi typing/datarepr.cmi typing/datarepr.cmx : typing/types.cmx typing/path.cmx parsing/location.cmx \ - typing/ident.cmx typing/btype.cmx parsing/asttypes.cmi \ - typing/datarepr.cmi + typing/ident.cmx parsing/builtin_attributes.cmx typing/btype.cmx \ + parsing/asttypes.cmi typing/datarepr.cmi typing/datarepr.cmi : typing/types.cmi typing/path.cmi typing/ident.cmi typing/env.cmo : utils/warnings.cmi typing/types.cmi utils/tbl.cmi \ typing/subst.cmi typing/predef.cmi typing/path.cmi utils/misc.cmi \ @@ -218,12 +218,12 @@ typing/includeclass.cmx : typing/types.cmx typing/printtyp.cmx \ typing/includeclass.cmi : typing/types.cmi typing/env.cmi typing/ctype.cmi typing/includecore.cmo : typing/types.cmi typing/typedtree.cmi \ typing/path.cmi utils/misc.cmi typing/ident.cmi typing/env.cmi \ - typing/ctype.cmi typing/btype.cmi parsing/asttypes.cmi \ - typing/includecore.cmi + typing/ctype.cmi parsing/builtin_attributes.cmi typing/btype.cmi \ + parsing/asttypes.cmi typing/includecore.cmi typing/includecore.cmx : typing/types.cmx typing/typedtree.cmx \ typing/path.cmx utils/misc.cmx typing/ident.cmx typing/env.cmx \ - typing/ctype.cmx typing/btype.cmx parsing/asttypes.cmi \ - typing/includecore.cmi + typing/ctype.cmx parsing/builtin_attributes.cmx typing/btype.cmx \ + parsing/asttypes.cmi typing/includecore.cmi typing/includecore.cmi : typing/types.cmi typing/typedtree.cmi \ typing/ident.cmi typing/env.cmi typing/includemod.cmo : typing/types.cmi typing/typedtree.cmi utils/tbl.cmi \ @@ -382,19 +382,19 @@ typing/typedecl.cmo : utils/warnings.cmi typing/typetexp.cmi \ typing/printtyp.cmi typing/primitive.cmi typing/predef.cmi \ typing/path.cmi parsing/parsetree.cmi utils/misc.cmi \ parsing/longident.cmi parsing/location.cmi typing/includecore.cmi \ - typing/ident.cmi typing/env.cmi typing/ctype.cmi utils/config.cmi \ - utils/clflags.cmi parsing/builtin_attributes.cmi typing/btype.cmi \ - parsing/attr_helper.cmi parsing/asttypes.cmi parsing/ast_iterator.cmi \ - parsing/ast_helper.cmi typing/typedecl.cmi + typing/ident.cmi typing/env.cmi typing/datarepr.cmi typing/ctype.cmi \ + utils/config.cmi utils/clflags.cmi parsing/builtin_attributes.cmi \ + typing/btype.cmi parsing/attr_helper.cmi parsing/asttypes.cmi \ + parsing/ast_iterator.cmi parsing/ast_helper.cmi typing/typedecl.cmi typing/typedecl.cmx : utils/warnings.cmx typing/typetexp.cmx \ typing/types.cmx typing/typedtree.cmx typing/subst.cmx \ typing/printtyp.cmx typing/primitive.cmx typing/predef.cmx \ typing/path.cmx parsing/parsetree.cmi utils/misc.cmx \ parsing/longident.cmx parsing/location.cmx typing/includecore.cmx \ - typing/ident.cmx typing/env.cmx typing/ctype.cmx utils/config.cmx \ - utils/clflags.cmx parsing/builtin_attributes.cmx typing/btype.cmx \ - parsing/attr_helper.cmx parsing/asttypes.cmi parsing/ast_iterator.cmx \ - parsing/ast_helper.cmx typing/typedecl.cmi + typing/ident.cmx typing/env.cmx typing/datarepr.cmx typing/ctype.cmx \ + utils/config.cmx utils/clflags.cmx parsing/builtin_attributes.cmx \ + typing/btype.cmx parsing/attr_helper.cmx parsing/asttypes.cmi \ + parsing/ast_iterator.cmx parsing/ast_helper.cmx typing/typedecl.cmi typing/typedecl.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \ parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \ typing/includecore.cmi typing/ident.cmi typing/env.cmi \ @@ -441,9 +441,9 @@ typing/typemod.cmx : utils/warnings.cmx typing/typetexp.cmx typing/types.cmx \ parsing/asttypes.cmi parsing/ast_iterator.cmx typing/annot.cmi \ typing/typemod.cmi typing/typemod.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \ - parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \ - parsing/location.cmi typing/includemod.cmi typing/ident.cmi \ - typing/env.cmi parsing/asttypes.cmi + parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \ + typing/includemod.cmi typing/ident.cmi typing/env.cmi \ + parsing/asttypes.cmi typing/types.cmo : typing/primitive.cmi typing/path.cmi \ parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \ typing/ident.cmi parsing/asttypes.cmi typing/types.cmi @@ -533,17 +533,14 @@ bytecomp/dll.cmi : bytecomp/emitcode.cmo : bytecomp/translmod.cmi typing/primitive.cmi \ bytecomp/opcodes.cmo utils/misc.cmi bytecomp/meta.cmi \ parsing/location.cmi bytecomp/lambda.cmi bytecomp/instruct.cmi \ - typing/ident.cmi typing/env.cmi utils/config.cmi bytecomp/cmo_format.cmi \ - utils/clflags.cmi typing/btype.cmi parsing/asttypes.cmi \ - bytecomp/emitcode.cmi + typing/env.cmi utils/config.cmi bytecomp/cmo_format.cmi utils/clflags.cmi \ + typing/btype.cmi parsing/asttypes.cmi bytecomp/emitcode.cmi bytecomp/emitcode.cmx : bytecomp/translmod.cmx typing/primitive.cmx \ bytecomp/opcodes.cmx utils/misc.cmx bytecomp/meta.cmx \ parsing/location.cmx bytecomp/lambda.cmx bytecomp/instruct.cmx \ - typing/ident.cmx typing/env.cmx utils/config.cmx bytecomp/cmo_format.cmi \ - utils/clflags.cmx typing/btype.cmx parsing/asttypes.cmi \ - bytecomp/emitcode.cmi -bytecomp/emitcode.cmi : bytecomp/instruct.cmi typing/ident.cmi \ - bytecomp/cmo_format.cmi + typing/env.cmx utils/config.cmx bytecomp/cmo_format.cmi utils/clflags.cmx \ + typing/btype.cmx parsing/asttypes.cmi bytecomp/emitcode.cmi +bytecomp/emitcode.cmi : bytecomp/instruct.cmi bytecomp/cmo_format.cmi bytecomp/instruct.cmo : typing/types.cmi typing/subst.cmi \ parsing/location.cmi bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi \ bytecomp/instruct.cmi @@ -606,8 +603,8 @@ bytecomp/simplif.cmx : utils/warnings.cmx utils/tbl.cmx typing/stypes.cmx \ utils/misc.cmx parsing/location.cmx bytecomp/lambda.cmx typing/ident.cmx \ utils/config.cmx utils/clflags.cmx parsing/asttypes.cmi typing/annot.cmi \ bytecomp/simplif.cmi -bytecomp/simplif.cmi : utils/misc.cmi parsing/location.cmi \ - bytecomp/lambda.cmi typing/ident.cmi +bytecomp/simplif.cmi : parsing/location.cmi bytecomp/lambda.cmi \ + typing/ident.cmi bytecomp/switch.cmo : bytecomp/switch.cmi bytecomp/switch.cmx : bytecomp/switch.cmi bytecomp/switch.cmi : @@ -689,10 +686,12 @@ bytecomp/translobj.cmx : typing/primitive.cmx utils/misc.cmx \ bytecomp/translobj.cmi : bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi bytecomp/typeopt.cmo : typing/types.cmi typing/typedtree.cmi \ typing/predef.cmi typing/path.cmi bytecomp/lambda.cmi typing/ident.cmi \ - typing/env.cmi typing/ctype.cmi bytecomp/typeopt.cmi + typing/env.cmi typing/ctype.cmi parsing/builtin_attributes.cmi \ + bytecomp/typeopt.cmi bytecomp/typeopt.cmx : typing/types.cmx typing/typedtree.cmx \ typing/predef.cmx typing/path.cmx bytecomp/lambda.cmx typing/ident.cmx \ - typing/env.cmx typing/ctype.cmx bytecomp/typeopt.cmi + typing/env.cmx typing/ctype.cmx parsing/builtin_attributes.cmx \ + bytecomp/typeopt.cmi bytecomp/typeopt.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \ bytecomp/lambda.cmi typing/env.cmi asmcomp/CSE.cmo : asmcomp/mach.cmi asmcomp/CSEgen.cmi asmcomp/arch.cmo @@ -712,12 +711,12 @@ asmcomp/asmgen.cmo : asmcomp/un_anf.cmi bytecomp/translmod.cmi \ typing/primitive.cmi utils/misc.cmi asmcomp/mach.cmi parsing/location.cmi \ asmcomp/liveness.cmi middle_end/base_types/linkage_name.cmi \ asmcomp/linearize.cmi bytecomp/lambda.cmi asmcomp/interf.cmi \ - typing/ident.cmi asmcomp/flambda_to_clambda.cmi middle_end/flambda.cmi \ - asmcomp/emitaux.cmi asmcomp/emit.cmi asmcomp/deadcode.cmi \ - utils/config.cmi asmcomp/compilenv.cmi asmcomp/comballoc.cmi \ - asmcomp/coloring.cmi asmcomp/cmmgen.cmi asmcomp/cmm.cmi \ - asmcomp/closure.cmi utils/clflags.cmi asmcomp/clambda.cmi asmcomp/CSE.cmo \ - asmcomp/build_export_info.cmi asmcomp/asmgen.cmi + asmcomp/flambda_to_clambda.cmi middle_end/flambda.cmi asmcomp/emitaux.cmi \ + asmcomp/emit.cmi asmcomp/deadcode.cmi utils/config.cmi \ + asmcomp/compilenv.cmi asmcomp/comballoc.cmi asmcomp/coloring.cmi \ + asmcomp/cmmgen.cmi asmcomp/cmm.cmi asmcomp/closure.cmi utils/clflags.cmi \ + asmcomp/clambda.cmi asmcomp/CSE.cmo asmcomp/build_export_info.cmi \ + asmcomp/asmgen.cmi asmcomp/asmgen.cmx : asmcomp/un_anf.cmx bytecomp/translmod.cmx \ utils/timings.cmx middle_end/base_types/symbol.cmx asmcomp/split.cmx \ asmcomp/spill.cmx asmcomp/selection.cmx asmcomp/scheduling.cmx \ @@ -726,13 +725,13 @@ asmcomp/asmgen.cmx : asmcomp/un_anf.cmx bytecomp/translmod.cmx \ typing/primitive.cmx utils/misc.cmx asmcomp/mach.cmx parsing/location.cmx \ asmcomp/liveness.cmx middle_end/base_types/linkage_name.cmx \ asmcomp/linearize.cmx bytecomp/lambda.cmx asmcomp/interf.cmx \ - typing/ident.cmx asmcomp/flambda_to_clambda.cmx middle_end/flambda.cmx \ - asmcomp/emitaux.cmx asmcomp/emit.cmx asmcomp/deadcode.cmx \ - utils/config.cmx asmcomp/compilenv.cmx asmcomp/comballoc.cmx \ - asmcomp/coloring.cmx asmcomp/cmmgen.cmx asmcomp/cmm.cmx \ - asmcomp/closure.cmx utils/clflags.cmx asmcomp/clambda.cmx asmcomp/CSE.cmx \ - asmcomp/build_export_info.cmx asmcomp/asmgen.cmi -asmcomp/asmgen.cmi : utils/timings.cmi bytecomp/lambda.cmi typing/ident.cmi \ + asmcomp/flambda_to_clambda.cmx middle_end/flambda.cmx asmcomp/emitaux.cmx \ + asmcomp/emit.cmx asmcomp/deadcode.cmx utils/config.cmx \ + asmcomp/compilenv.cmx asmcomp/comballoc.cmx asmcomp/coloring.cmx \ + asmcomp/cmmgen.cmx asmcomp/cmm.cmx asmcomp/closure.cmx utils/clflags.cmx \ + asmcomp/clambda.cmx asmcomp/CSE.cmx asmcomp/build_export_info.cmx \ + asmcomp/asmgen.cmi +asmcomp/asmgen.cmi : utils/timings.cmi bytecomp/lambda.cmi \ middle_end/flambda.cmi asmcomp/cmm.cmi middle_end/backend_intf.cmi asmcomp/asmlibrarian.cmo : utils/misc.cmi parsing/location.cmi \ asmcomp/export_info.cmi utils/config.cmi asmcomp/compilenv.cmi \ @@ -1949,7 +1948,6 @@ middle_end/base_types/variable.cmx : utils/misc.cmx utils/identifiable.cmx \ middle_end/base_types/variable.cmi middle_end/base_types/variable.cmi : utils/identifiable.cmi typing/ident.cmi \ middle_end/base_types/compilation_unit.cmi -driver/compdynlink.cmi : driver/compenv.cmo : utils/warnings.cmi utils/misc.cmi parsing/location.cmi \ utils/config.cmi utils/clflags.cmi driver/compenv.cmi driver/compenv.cmx : utils/warnings.cmx utils/misc.cmx parsing/location.cmx \ @@ -1960,7 +1958,7 @@ driver/compile.cmo : utils/warnings.cmi typing/typemod.cmi \ utils/timings.cmi typing/stypes.cmi bytecomp/simplif.cmi \ typing/printtyped.cmi typing/printtyp.cmi bytecomp/printlambda.cmi \ bytecomp/printinstr.cmi parsing/printast.cmi parsing/pprintast.cmi \ - driver/pparse.cmi utils/misc.cmi parsing/location.cmi bytecomp/lambda.cmi \ + driver/pparse.cmi utils/misc.cmi parsing/location.cmi \ typing/includemod.cmi typing/env.cmi bytecomp/emitcode.cmi \ driver/compmisc.cmi driver/compenv.cmi utils/clflags.cmi utils/ccomp.cmi \ bytecomp/bytegen.cmi parsing/builtin_attributes.cmi driver/compile.cmi @@ -1969,7 +1967,7 @@ driver/compile.cmx : utils/warnings.cmx typing/typemod.cmx \ utils/timings.cmx typing/stypes.cmx bytecomp/simplif.cmx \ typing/printtyped.cmx typing/printtyp.cmx bytecomp/printlambda.cmx \ bytecomp/printinstr.cmx parsing/printast.cmx parsing/pprintast.cmx \ - driver/pparse.cmx utils/misc.cmx parsing/location.cmx bytecomp/lambda.cmx \ + driver/pparse.cmx utils/misc.cmx parsing/location.cmx \ typing/includemod.cmx typing/env.cmx bytecomp/emitcode.cmx \ driver/compmisc.cmx driver/compenv.cmx utils/clflags.cmx utils/ccomp.cmx \ bytecomp/bytegen.cmx parsing/builtin_attributes.cmx driver/compile.cmi @@ -2056,7 +2054,7 @@ driver/pparse.cmx : utils/timings.cmx parsing/parsetree.cmi \ parsing/parse.cmx utils/misc.cmx parsing/location.cmx utils/config.cmx \ utils/clflags.cmx utils/ccomp.cmx parsing/ast_mapper.cmx \ parsing/ast_invariants.cmx driver/pparse.cmi -driver/pparse.cmi : parsing/parsetree.cmi utils/misc.cmi +driver/pparse.cmi : parsing/parsetree.cmi toplevel/expunge.cmo : bytecomp/symtable.cmi bytecomp/runtimedef.cmi \ utils/misc.cmi typing/ident.cmi bytecomp/bytesections.cmi toplevel/expunge.cmx : bytecomp/symtable.cmx bytecomp/runtimedef.cmx \ @@ -2064,13 +2062,13 @@ toplevel/expunge.cmx : bytecomp/symtable.cmx bytecomp/runtimedef.cmx \ toplevel/genprintval.cmo : typing/types.cmi typing/printtyp.cmi \ typing/predef.cmi typing/path.cmi typing/outcometree.cmi \ typing/oprint.cmi utils/misc.cmi parsing/longident.cmi typing/ident.cmi \ - typing/env.cmi typing/datarepr.cmi typing/ctype.cmi typing/btype.cmi \ - toplevel/genprintval.cmi + typing/env.cmi typing/datarepr.cmi typing/ctype.cmi \ + parsing/builtin_attributes.cmi typing/btype.cmi toplevel/genprintval.cmi toplevel/genprintval.cmx : typing/types.cmx typing/printtyp.cmx \ typing/predef.cmx typing/path.cmx typing/outcometree.cmi \ typing/oprint.cmx utils/misc.cmx parsing/longident.cmx typing/ident.cmx \ - typing/env.cmx typing/datarepr.cmx typing/ctype.cmx typing/btype.cmx \ - toplevel/genprintval.cmi + typing/env.cmx typing/datarepr.cmx typing/ctype.cmx \ + parsing/builtin_attributes.cmx typing/btype.cmx toplevel/genprintval.cmi toplevel/genprintval.cmi : typing/types.cmi typing/path.cmi \ typing/outcometree.cmi typing/env.cmi toplevel/opttopdirs.cmo : utils/warnings.cmi typing/types.cmi \ @@ -2160,7 +2158,7 @@ toplevel/toploop.cmo : utils/warnings.cmi typing/typetexp.cmi \ parsing/location.cmi parsing/lexer.cmi typing/includemod.cmi \ typing/ident.cmi toplevel/genprintval.cmi typing/env.cmi \ bytecomp/emitcode.cmi bytecomp/dll.cmi utils/consistbl.cmi \ - utils/config.cmi driver/compmisc.cmi driver/compenv.cmi utils/clflags.cmi \ + utils/config.cmi driver/compmisc.cmi utils/clflags.cmi \ bytecomp/bytegen.cmi typing/btype.cmi parsing/asttypes.cmi \ parsing/ast_helper.cmi toplevel/toploop.cmi toplevel/toploop.cmx : utils/warnings.cmx typing/typetexp.cmx \ @@ -2174,7 +2172,7 @@ toplevel/toploop.cmx : utils/warnings.cmx typing/typetexp.cmx \ parsing/location.cmx parsing/lexer.cmx typing/includemod.cmx \ typing/ident.cmx toplevel/genprintval.cmx typing/env.cmx \ bytecomp/emitcode.cmx bytecomp/dll.cmx utils/consistbl.cmx \ - utils/config.cmx driver/compmisc.cmx driver/compenv.cmx utils/clflags.cmx \ + utils/config.cmx driver/compmisc.cmx utils/clflags.cmx \ bytecomp/bytegen.cmx typing/btype.cmx parsing/asttypes.cmi \ parsing/ast_helper.cmx toplevel/toploop.cmi toplevel/toploop.cmi : utils/warnings.cmi typing/types.cmi typing/path.cmi \ @@ -14,6 +14,11 @@ OCaml 4.04.0: - GPR#508: Allow shortcut for extension on semicolons: ;%foo (Jeremie Dimino) +- GPR#606: optimized representation for immutable records with a single + field, and concrete types with a single constructor with a single argument. + This is triggered with a [@@unboxed] attribute on the type definition. + (Damien Doligez) + - PR#7233: Support GADT equations on non-local abstract types (Jacques Garrigue) diff --git a/asmcomp/cmmgen.ml b/asmcomp/cmmgen.ml index 7c907ffaf1..d278ba8996 100644 --- a/asmcomp/cmmgen.ml +++ b/asmcomp/cmmgen.ml @@ -708,6 +708,8 @@ let rec expr_size env = function RHS_floatblock (List.length args) | Uprim (Pduprecord ((Record_regular | Record_inlined _), sz), _, _) -> RHS_block sz + | Uprim (Pduprecord (Record_unboxed _, _), _, _) -> + assert false | Uprim (Pduprecord (Record_extension, sz), _, _) -> RHS_block (sz + 1) | Uprim (Pduprecord (Record_float, sz), _, _) -> diff --git a/boot/ocamlc b/boot/ocamlc Binary files differindex 71a53c14c1..ddfed73cad 100755 --- a/boot/ocamlc +++ b/boot/ocamlc diff --git a/boot/ocamldep b/boot/ocamldep Binary files differindex 5d0fe22698..5bef2cebee 100755 --- a/boot/ocamldep +++ b/boot/ocamldep diff --git a/boot/ocamllex b/boot/ocamllex Binary files differindex aa242e1a3c..c6905e5d44 100755 --- a/boot/ocamllex +++ b/boot/ocamllex diff --git a/bytecomp/bytegen.ml b/bytecomp/bytegen.ml index 3e5c947255..96fdb5702b 100644 --- a/bytecomp/bytegen.ml +++ b/bytecomp/bytegen.ml @@ -150,6 +150,7 @@ let rec size_of_lambda = function when check_recordwith_updates id body -> begin match kind with | Record_regular | Record_inlined _ -> RHS_block size + | Record_unboxed _ -> assert false | Record_float -> RHS_floatblock size | Record_extension -> RHS_block (size + 1) end @@ -163,6 +164,8 @@ let rec size_of_lambda = function | Lprim (Pmakearray (Pgenarray, _), _, _) -> assert false | Lprim (Pduprecord ((Record_regular | Record_inlined _), size), _, _) -> RHS_block size + | Lprim (Pduprecord (Record_unboxed _, _), _, _) -> + assert false | Lprim (Pduprecord (Record_extension, size), _, _) -> RHS_block (size + 1) | Lprim (Pduprecord (Record_float, size), _, _) -> RHS_floatblock size diff --git a/bytecomp/matching.ml b/bytecomp/matching.ml index c352abaf44..51f299f49e 100644 --- a/bytecomp/matching.ml +++ b/bytecomp/matching.ml @@ -1355,6 +1355,7 @@ let make_constr_matching p def ctx = function else match cstr.cstr_tag with Cstr_constant _ | Cstr_block _ -> make_field_args p.pat_loc Alias arg 0 (cstr.cstr_arity - 1) argl + | Cstr_unboxed -> (arg, Alias) :: argl | Cstr_extension _ -> make_field_args p.pat_loc Alias arg 1 cstr.cstr_arity argl in {pm= @@ -1637,15 +1638,17 @@ let make_record_matching loc all_labels def = function let lbl = all_labels.(pos) in let access = match lbl.lbl_repres with - Record_regular | Record_inlined _ -> Pfield lbl.lbl_pos - | Record_float -> Pfloatfield lbl.lbl_pos - | Record_extension -> Pfield (lbl.lbl_pos + 1) + | Record_regular | Record_inlined _ -> + Lprim (Pfield lbl.lbl_pos, [arg], loc) + | Record_unboxed _ -> arg + | Record_float -> Lprim (Pfloatfield lbl.lbl_pos, [arg], loc) + | Record_extension -> Lprim (Pfield (lbl.lbl_pos + 1), [arg], loc) in let str = match lbl.lbl_mut with Immutable -> Alias | Mutable -> StrictOpt in - (Lprim(access, [arg], loc), str) :: make_args(pos + 1) + (access, str) :: make_args(pos + 1) end in let nfields = Array.length all_labels in let def= make_default (matcher_record nfields) def in @@ -2288,7 +2291,8 @@ let split_cases tag_lambda_list = match cstr with Cstr_constant n -> ((n, act) :: consts, nonconsts) | Cstr_block n -> (consts, (n, act) :: nonconsts) - | _ -> assert false in + | Cstr_unboxed -> (consts, (0, act) :: nonconsts) + | Cstr_extension _ -> assert false in let const, nonconst = split_rec tag_lambda_list in sort_int_lambda_list const, sort_int_lambda_list nonconst diff --git a/bytecomp/printlambda.ml b/bytecomp/printlambda.ml index 1797cdb6af..4ac9c2505a 100644 --- a/bytecomp/printlambda.ml +++ b/bytecomp/printlambda.ml @@ -103,6 +103,8 @@ let record_rep ppf r = match r with | Record_regular -> fprintf ppf "regular" | Record_inlined i -> fprintf ppf "inlined(%i)" i + | Record_unboxed false -> fprintf ppf "unboxed" + | Record_unboxed true -> fprintf ppf "inlined(unboxed)" | Record_float -> fprintf ppf "float" | Record_extension -> fprintf ppf "ext" ;; diff --git a/bytecomp/translcore.ml b/bytecomp/translcore.ml index ae293ba709..a505a01842 100644 --- a/bytecomp/translcore.ml +++ b/bytecomp/translcore.ml @@ -836,6 +836,8 @@ and transl_exp0 e = end else begin match cstr.cstr_tag with Cstr_constant n -> Lconst(Const_pointer n) + | Cstr_unboxed -> + (match ll with [v] -> v | _ -> assert false) | Cstr_block n -> begin try Lconst(Const_block(n, List.map extract_constant ll)) @@ -868,19 +870,22 @@ and transl_exp0 e = transl_record e.exp_loc e.exp_env fields representation extended_expression | Texp_field(arg, _, lbl) -> - let access = - match lbl.lbl_repres with - Record_regular | Record_inlined _ -> Pfield lbl.lbl_pos - | Record_float -> Pfloatfield lbl.lbl_pos - | Record_extension -> Pfield (lbl.lbl_pos + 1) - in - Lprim(access, [transl_exp arg], e.exp_loc) + let targ = transl_exp arg in + begin match lbl.lbl_repres with + Record_regular | Record_inlined _ -> + Lprim (Pfield lbl.lbl_pos, [targ], e.exp_loc) + | Record_unboxed _ -> targ + | Record_float -> Lprim (Pfloatfield lbl.lbl_pos, [targ], e.exp_loc) + | Record_extension -> + Lprim (Pfield (lbl.lbl_pos + 1), [targ], e.exp_loc) + end | Texp_setfield(arg, _, lbl, newval) -> let access = match lbl.lbl_repres with Record_regular | Record_inlined _ -> Psetfield(lbl.lbl_pos, maybe_pointer newval, Assignment) + | Record_unboxed _ -> assert false | Record_float -> Psetfloatfield (lbl.lbl_pos, Assignment) | Record_extension -> Psetfield (lbl.lbl_pos + 1, maybe_pointer newval, Assignment) @@ -1278,6 +1283,7 @@ and transl_record loc env fields repres opt_init_expr = let access = match repres with Record_regular | Record_inlined _ -> Pfield i + | Record_unboxed _ -> assert false | Record_extension -> Pfield (i + 1) | Record_float -> Pfloatfield i in Lprim(access, [Lvar init_id], loc), field_kind @@ -1298,6 +1304,7 @@ and transl_record loc env fields repres opt_init_expr = match repres with | Record_regular -> Lconst(Const_block(0, cl)) | Record_inlined tag -> Lconst(Const_block(tag, cl)) + | Record_unboxed _ -> Lconst(match cl with [v] -> v | _ -> assert false) | Record_float -> Lconst(Const_float_array(List.map extract_float cl)) | Record_extension -> @@ -1308,6 +1315,7 @@ and transl_record loc env fields repres opt_init_expr = Lprim(Pmakeblock(0, mut, Some shape), ll, loc) | Record_inlined tag -> Lprim(Pmakeblock(tag, mut, Some shape), ll, loc) + | Record_unboxed _ -> (match ll with [v] -> v | _ -> assert false) | Record_float -> Lprim(Pmakearray (Pfloatarray, mut), ll, loc) | Record_extension -> @@ -1340,6 +1348,7 @@ and transl_record loc env fields repres opt_init_expr = Record_regular | Record_inlined _ -> Psetfield(lbl.lbl_pos, maybe_pointer expr, Assignment) + | Record_unboxed _ -> assert false | Record_float -> Psetfloatfield (lbl.lbl_pos, Assignment) | Record_extension -> Psetfield(lbl.lbl_pos + 1, maybe_pointer expr, Assignment) diff --git a/bytecomp/typeopt.ml b/bytecomp/typeopt.ml index bd42def19e..3aa05bbf85 100644 --- a/bytecomp/typeopt.ml +++ b/bytecomp/typeopt.ml @@ -21,7 +21,20 @@ open Typedtree open Lambda let scrape env ty = - (Ctype.repr (Ctype.expand_head_opt env (Ctype.correct_levels ty))).desc + match + (Ctype.repr (Ctype.expand_head_opt env (Ctype.correct_levels ty))).desc + with + | Tconstr (p, _, _) as desc -> + begin match Env.find_type p env with + | {type_unboxed = {unboxed = true; _}; _} -> + begin match Typedecl.get_unboxed_type_representation env ty with + | None -> desc + | Some ty2 -> ty2.desc + end + | _ -> desc + | exception Not_found -> desc + end + | desc -> desc let is_function_type env ty = match scrape env ty with diff --git a/byterun/caml/alloc.h b/byterun/caml/alloc.h index 6942cf409e..48a2fbce45 100644 --- a/byterun/caml/alloc.h +++ b/byterun/caml/alloc.h @@ -50,6 +50,21 @@ CAMLextern value caml_alloc_final (mlsize_t wosize, CAMLextern int caml_convert_flag_list (value, int *); +/* Convenience functions to deal with unboxable types. */ +static inline value caml_alloc_unboxed (value arg) { return arg; } +static inline value caml_alloc_boxed (value arg) { + value result = caml_alloc_small (1, 0); + Field (result, 0) = arg; + return result; +} +static inline value caml_field_unboxed (value arg) { return arg; } +static inline value caml_field_boxed (value arg) { return Field (arg, 0); } + +/* Unannotated unboxable types are boxed by default. (may change in the + future) */ +#define caml_alloc_unboxable caml_alloc_boxed +#define caml_field_unboxable caml_field_boxed + #ifdef __cplusplus } #endif diff --git a/driver/compenv.ml b/driver/compenv.ml index 338d4c36a1..e3f7812163 100644 --- a/driver/compenv.ml +++ b/driver/compenv.ml @@ -205,6 +205,7 @@ let read_one_param ppf position name v = | "strict-sequence" -> set "strict-sequence" [ strict_sequence ] v | "strict-formats" -> set "strict-formats" [ strict_formats ] v | "thread" -> set "thread" [ use_threads ] v + | "unboxed-types" -> set "unboxed-types" [ unboxed_types ] v | "unsafe" -> set "unsafe" [ fast ] v | "verbose" -> set "verbose" [ verbose ] v | "nopervasives" -> set "nopervasives" [ nopervasives ] v diff --git a/driver/main.ml b/driver/main.ml index 87086c10c9..dc8b9dff97 100644 --- a/driver/main.ml +++ b/driver/main.ml @@ -145,6 +145,8 @@ module Options = Main_args.Make_bytecomp_options (struct let _no_strict_formats = unset strict_formats let _thread = set use_threads let _vmthread = set use_vmthreads + let _unboxed_types = set unboxed_types + let _no_unboxed_types = unset unboxed_types let _unsafe = set fast let _unsafe_string = set unsafe_string let _use_prims s = use_prims := s diff --git a/driver/main_args.ml b/driver/main_args.ml index c4f2bad06d..55e6f5c219 100644 --- a/driver/main_args.ml +++ b/driver/main_args.ml @@ -472,6 +472,16 @@ let mk_unbox_closures_factor f = Clflags.default_unbox_closures_factor ;; +let mk_unboxed_types f = + "-unboxed-types", Arg.Unit f, + " unannotated unboxable types will be unboxed" +;; + +let mk_no_unboxed_types f = + "-no-unboxed-types", Arg.Unit f, + " unannotated unboxable types will not be unboxed (default)" +;; + let mk_unsafe f = "-unsafe", Arg.Unit f, " Do not compile bounds checking on array and string access" @@ -742,6 +752,8 @@ module type Common_options = sig val _no_strict_sequence : unit -> unit val _strict_formats : unit -> unit val _no_strict_formats : unit -> unit + val _unboxed_types : unit -> unit + val _no_unboxed_types : unit -> unit val _unsafe : unit -> unit val _unsafe_string : unit -> unit val _version : unit -> unit @@ -991,6 +1003,8 @@ struct mk_strict_formats F._strict_formats; mk_no_strict_formats F._no_strict_formats; mk_thread F._thread; + mk_unboxed_types F._unboxed_types; + mk_no_unboxed_types F._no_unboxed_types; mk_unsafe F._unsafe; mk_unsafe_string F._unsafe_string; mk_use_runtime F._use_runtime; @@ -1050,6 +1064,8 @@ struct mk_no_strict_sequence F._no_strict_sequence; mk_strict_formats F._strict_formats; mk_no_strict_formats F._no_strict_formats; + mk_unboxed_types F._unboxed_types; + mk_no_unboxed_types F._no_unboxed_types; mk_unsafe F._unsafe; mk_unsafe_string F._unsafe_string; mk_version F._version; @@ -1154,6 +1170,8 @@ struct mk_unbox_closures F._unbox_closures; mk_unbox_closures_factor F._unbox_closures_factor; mk_inline_max_unroll F._inline_max_unroll; + mk_unboxed_types F._unboxed_types; + mk_no_unboxed_types F._no_unboxed_types; mk_unsafe F._unsafe; mk_unsafe_string F._unsafe_string; mk_v F._v; @@ -1251,6 +1269,8 @@ module Make_opttop_options (F : Opttop_options) = struct mk_no_strict_formats F._no_strict_formats; mk_unbox_closures F._unbox_closures; mk_unbox_closures_factor F._unbox_closures_factor; + mk_unboxed_types F._unboxed_types; + mk_no_unboxed_types F._no_unboxed_types; mk_unsafe F._unsafe; mk_unsafe_string F._unsafe_string; mk_verbose F._verbose; @@ -1321,6 +1341,8 @@ struct mk_strict_formats F._strict_formats; mk_no_strict_formats F._no_strict_formats; mk_thread F._thread; + mk_unboxed_types F._unboxed_types; + mk_no_unboxed_types F._no_unboxed_types; mk_unsafe_string F._unsafe_string; mk_v F._v; mk_verbose F._verbose; diff --git a/driver/main_args.mli b/driver/main_args.mli index 5e146e25d7..b5b0eaaedb 100644 --- a/driver/main_args.mli +++ b/driver/main_args.mli @@ -39,6 +39,8 @@ module type Common_options = sig val _no_strict_sequence : unit -> unit val _strict_formats : unit -> unit val _no_strict_formats : unit -> unit + val _unboxed_types : unit -> unit + val _no_unboxed_types : unit -> unit val _unsafe : unit -> unit val _unsafe_string : unit -> unit val _version : unit -> unit diff --git a/driver/optmain.ml b/driver/optmain.ml index e9ae7fd6a6..6a8ea204d8 100644 --- a/driver/optmain.ml +++ b/driver/optmain.ml @@ -231,6 +231,8 @@ module Options = Main_args.Make_optcomp_options (struct let _thread = set use_threads let _unbox_closures = set unbox_closures let _unbox_closures_factor f = unbox_closures_factor := f + let _unboxed_types = set unboxed_types + let _no_unboxed_types = clear unboxed_types let _unsafe = set fast let _unsafe_string = set unsafe_string let _v () = print_version_and_library "native-code compiler" diff --git a/man/ocaml.m b/man/ocaml.m index 0214bdf5ec..1d32002296 100644 --- a/man/ocaml.m +++ b/man/ocaml.m @@ -190,6 +190,17 @@ interactive session. .B \-strict\-sequence Force the left-hand part of each sequence to have type unit. .TP +.B \-unboxed\-types +When a type is unboxable (i.e. a record with a single argument or a +concrete datatype with a single constructor of one argument) it will +be unboxed unless annotated with +.BR [@@ocaml.boxed] . +.TP +.B \-no-unboxed\-types +When a type is unboxable it will be boxed unless annotated with +.BR [@@ocaml.unboxed] . +This is the default. +.TP .B \-unsafe Turn bound checking off on array and string accesses (the .BR v.(i) and s.[i] diff --git a/man/ocamlc.m b/man/ocamlc.m index ca064a89d8..23c98170bf 100644 --- a/man/ocamlc.m +++ b/man/ocamlc.m @@ -602,6 +602,17 @@ Compile or link multithreaded programs, in combination with the system "threads" library described in .IR The\ OCaml\ user's\ manual . .TP +.B \-unboxed\-types +When a type is unboxable (i.e. a record with a single argument or a +concrete datatype with a single constructor of one argument) it will +be unboxed unless annotated with +.BR [@@ocaml.boxed] . +.TP +.B \-no-unboxed\-types +When a type is unboxable it will be boxed unless annotated with +.BR [@@ocaml.unboxed] . +This is the default. +.TP .B \-unsafe Turn bound checking off for array and string accesses (the .BR v.(i) and s.[i] @@ -894,6 +905,9 @@ mutually recursive types. 60 \ \ Unused module declaration. +61 +\ \ Unannotated unboxable type in primitive declaration. + The letters stand for the following sets of warnings. Any letter not mentioned here corresponds to the empty set. @@ -977,7 +991,7 @@ warnings or modify existing warnings. The default setting is .B \-warn\-error \-a+31 -(all warnings are non-fatal except 31). +(only warning 31 is fatal). .TP .B \-warn\-help Show the description of all available warning numbers. diff --git a/man/ocamlopt.m b/man/ocamlopt.m index a44c09e340..f3fb3470c4 100644 --- a/man/ocamlopt.m +++ b/man/ocamlopt.m @@ -548,6 +548,17 @@ Compile or link multithreaded programs, in combination with the system threads library described in .IR "The OCaml user's manual" . .TP +.B \-unboxed\-types +When a type is unboxable (i.e. a record with a single argument or a +concrete datatype with a single constructor of one argument) it will +be unboxed unless annotated with +.BR [@@ocaml.boxed] . +.TP +.B \-no-unboxed\-types +When a type is unboxable it will be boxed unless annotated with +.BR [@@ocaml.unboxed] . +This is the default. +.TP .B \-unsafe Turn bound checking off for array and string accesses (the .BR v.(i) and s.[i] @@ -615,8 +626,8 @@ compiling your program with later versions of OCaml when they add new warnings or modify existing warnings. The default setting is -.B \-warn\-error \-a -(all warnings are non-fatal). +.B \-warn\-error \-a+31 +(only warning 31 is fatal). .TP .B \-warn\-help Show the description of all available warning numbers. diff --git a/manual/manual/cmds/comp.etex b/manual/manual/cmds/comp.etex index 6ee5ce8d98..cf1f51abdf 100644 --- a/manual/manual/cmds/comp.etex +++ b/manual/manual/cmds/comp.etex @@ -429,6 +429,15 @@ invalid formats, as they will be rejected by future OCaml versions. Compile or link multithreaded programs, in combination with the system "threads" library described in chapter~\ref{c:threads}. +\item["-unboxed-types"] +When a type is unboxable (i.e. a record with a single argument or a +concrete datatype with a single constructor of one argument) it will +be unboxed unless annotated with "[@@ocaml.boxed]". + +\item["-no-unboxed-types"] +When a type is unboxable it will be boxed unless annotated with +"[@@ocaml.unboxed]". This is the default. + \item["-unsafe"] Turn bound checking off for array and string accesses (the "v.(i)" and "s.[i]" constructs). Programs compiled with "-unsafe" are therefore @@ -507,7 +516,7 @@ that are currently defined are ignored. The warnings are as follows. \end{options} Some warnings are described in more detail in section~\ref{s:comp-warnings}. -The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45". +The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45-48-50". It is displayed by "ocamlc -help". Note that warnings 5 and 10 are not always triggered, depending on the internals of the type checker. @@ -526,7 +535,7 @@ arguments to "-warn-error" in production code, because this can break your build when future versions of OCaml add some new warnings. -The default setting is "-warn-error -a" (all warnings are non-fatal). +The default setting is "-warn-error -a+31" (only warning 31 is fatal). \item["-warn-help"] Show the description of all available warning numbers. diff --git a/manual/manual/cmds/intf-c.etex b/manual/manual/cmds/intf-c.etex index cab842f078..a9ec807800 100644 --- a/manual/manual/cmds/intf-c.etex +++ b/manual/manual/cmds/intf-c.etex @@ -522,6 +522,7 @@ This section describes how OCaml data types are encoded in the \end{tableau} \subsection{Tuples and records} +\label{ss:tuples-and-records} Tuples are represented by pointers to blocks, with tag~0. @@ -535,6 +536,23 @@ As an optimization, records whose fields all have static type "float" are represented as arrays of floating-point numbers, with tag "Double_array_tag". (See the section below on arrays.) +As another optimization, unboxable record types are represented +specially; unboxable record types are the immutable record types that +have only one field. An unboxable type will be represented in one of +two ways: boxed or unboxed. Boxed record types are represented as +described above (by a block with tag 0 or "Double_array_tag"). An +unboxed record type is represented directly by the value of its field +(i.e. there is no block to represent the record itself). + +The representation is chosen according to the following, in decreasing +order of priority: +\begin{itemize} +\item An attribute ("[\@\@boxed]" or "[\@\@unboxed]") on the type declaration. +\item A compiler option ("-unboxed-types" or "-no-unboxed-types"). +\item The default representation. In the present version of OCaml, the +default is the boxed representation. +\end{itemize} + \subsection{Arrays} Arrays of integers and pointers are represented like tuples, @@ -583,6 +601,14 @@ type t = | E of t * t (* Third non-constant constructor -> block with tag 2 *) \end{verbatim} + +As an optimization, unboxable concrete data types are represented +specially; a concrete data type is unboxable if it has exactly one +constructor and this constructor has exactly one argument. Unboxable +concrete data types are represented in the same ways as unboxable +record types: see the description in +section~\ref{ss:tuples-and-records}. + \subsection{Objects} Objects are represented as blocks with tag "Object_tag". The first @@ -700,6 +726,13 @@ in the "int32" \var{v}. in the "int64" \var{v}. \item "Nativeint_val("\var{v}")" returns the long integer contained in the "nativeint" \var{v}. +\item "caml_field_unboxed("\var{v}")" returns the value of the field +of a value \var{v} of any unboxed type (record or concrete data type). +\item "caml_field_boxed("\var{v}")" returns the value of the field +of a value \var{v} of any boxed type (record or concrete data type). +\item "caml_field_unboxable("\var{v}")" calls either +"caml_field_unboxed" or "caml_field_boxed" according to the default +representation of unboxable types in the current version of OCaml. \end{itemize} The expressions "Field("\var{v}", "\var{n}")", "Byte("\var{v}", "\var{n}")" and @@ -757,6 +790,13 @@ sequences, copied from the pointer to a string array \var{p} (a "char **"). \var{p} must be NULL-terminated. \item "caml_alloc_float_array("\var{n}")" allocates an array of floating point numbers of size \var{n}. The array initially contains uninitialized values. +\item "caml_alloc_unboxed("\var{v}")" returns the value (of any unboxed +type) whose field is the value \var{v}. +\item "caml_alloc_boxed("\var{v}")" allocates and returns a value (of +any boxed type) whose field is the value \var{v}. +\item "caml_alloc_unboxable("\var{v}")" calls either +"caml_alloc_unboxed" or "caml_alloc_boxed" according to the default +representation of unboxable types in the current version of OCaml. \end{itemize} \subsubsection{Low-level interface} diff --git a/manual/manual/cmds/native.etex b/manual/manual/cmds/native.etex index 4033b598e3..4c3c4be9f7 100644 --- a/manual/manual/cmds/native.etex +++ b/manual/manual/cmds/native.etex @@ -408,6 +408,15 @@ invalid formats, as they will be rejected by future OCaml versions. Compile or link multithreaded programs, in combination with the system "threads" library described in chapter~\ref{c:threads}. +\item["-unboxed-types"] +When a type is unboxable (i.e. a record with a single argument or a +concrete datatype with a single constructor of one argument) it will +be unboxed unless annotated with "[@@ocaml.boxed]". + +\item["-no-unboxed-types"] +When a type is unboxable it will be boxed unless annotated with +"[@@ocaml.unboxed]". This is the default. + \item["-unsafe"] Turn bound checking off for array and string accesses (the "v.(i)" and "s.[i]" constructs). Programs compiled with "-unsafe" are therefore @@ -478,7 +487,7 @@ that are currently defined are ignored. The warning are as follows. \input{warnings-help.tex} \end{options} -The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45". +The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45-48-50". It is displayed by "ocamlopt -help". Note that warnings 5 and 10 are not always triggered, depending on the internals of the type checker. @@ -498,7 +507,7 @@ arguments to "-warn-error" in production code, because this can break your build when future versions of OCaml add some new warnings. -The default setting is "-warn-error -a" (all warnings are non-fatal). +The default setting is "-warn-error -a+31" (only warning 31 is fatal). \item["-warn-help"] Show the description of all available warning numbers. diff --git a/manual/manual/refman/exten.etex b/manual/manual/refman/exten.etex index f454b4c738..46a34ab615 100644 --- a/manual/manual/refman/exten.etex +++ b/manual/manual/refman/exten.etex @@ -1758,6 +1758,22 @@ Some attributes are understood by the type-checker: enumerated types). Mutation of these immediate types does not activate the garbage collector's write barrier, which can significantly boost performance in programs relying heavily on mutable state. +\item + "ocaml.unboxed" or "unboxed" can be used on a type definition if the + type is a single-field record or a concrete type with a single + constructor that has a single argument. It tells the compiler to + optimize the representation of the type by removing the block that + represents the record or the constructor (i.e. a value of this type + is physically equal to its argument). In the case of GADTs, an + additional restriction applies: the argument must not be an + existential variable, represented by an existential type variable, + or an abstract type constructor applied to an existential type + variable. +\item + "ocaml.boxed" or "boxed" can be used on type definitions to mean + the opposite of "ocaml.unboxed": keep the unoptimized + representation of the type. When there is no annotation, the + default is currently "boxed" but it may change in the future. \end{itemize} \begin{verbatim} diff --git a/ocamldoc/odoc_args.ml b/ocamldoc/odoc_args.ml index 32028947d9..039c8d7000 100644 --- a/ocamldoc/odoc_args.ml +++ b/ocamldoc/odoc_args.ml @@ -222,6 +222,8 @@ module Options = Main_args.Make_ocamldoc_options(struct let _no_strict_formats = unset Clflags.strict_formats let _thread = set Clflags.use_threads let _vmthread = set Clflags.use_vmthreads + let _unboxed_types = set Clflags.unboxed_types + let _no_unboxed_types = unset Clflags.unboxed_types let _unsafe () = assert false let _unsafe_string = set Clflags.unsafe_string let _v () = Compenv.print_version_and_library "documentation generator" diff --git a/parsing/builtin_attributes.ml b/parsing/builtin_attributes.ml index a295d7dddb..bdbefcdf5e 100755 --- a/parsing/builtin_attributes.ml +++ b/parsing/builtin_attributes.ml @@ -195,3 +195,19 @@ let immediate = | ({txt="ocaml.immediate"|"immediate"; _}, _) -> true | _ -> false ) + +(* The "ocaml.boxed (default)" and "ocaml.unboxed (default)" + attributes cannot be input by the user, they are added by the + compiler when applying the default setting. This is done to record + in the .cmi the default used by the compiler when compiling the + source file because the default can change between compiler + invocations. *) + +let check l (x, _) = List.mem x.txt l + +let has_unboxed attr = + List.exists (check ["ocaml.unboxed"; "unboxed"]) + attr + +let has_boxed attr = + List.exists (check ["ocaml.boxed"; "boxed"]) attr diff --git a/parsing/builtin_attributes.mli b/parsing/builtin_attributes.mli index 7c9b294999..9add63733f 100755 --- a/parsing/builtin_attributes.mli +++ b/parsing/builtin_attributes.mli @@ -24,6 +24,7 @@ ocaml.warn_on_literal_pattern ocaml.deprecated_mutable ocaml.immediate + ocaml.boxed / ocaml.unboxed *) @@ -49,3 +50,6 @@ val explicit_arity: Parsetree.attributes -> bool val immediate: Parsetree.attributes -> bool + +val has_unboxed: Parsetree.attributes -> bool +val has_boxed: Parsetree.attributes -> bool diff --git a/testsuite/tests/typing-unboxed-types/Makefile b/testsuite/tests/typing-unboxed-types/Makefile new file mode 100644 index 0000000000..9625a3fbc3 --- /dev/null +++ b/testsuite/tests/typing-unboxed-types/Makefile @@ -0,0 +1,3 @@ +BASEDIR=../.. +include $(BASEDIR)/makefiles/Makefile.toplevel +include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-unboxed-types/test.ml b/testsuite/tests/typing-unboxed-types/test.ml new file mode 100644 index 0000000000..f187b76d81 --- /dev/null +++ b/testsuite/tests/typing-unboxed-types/test.ml @@ -0,0 +1,121 @@ +(* Check the unboxing *) + +(* For concrete types *) +type t1 = A of string [@@ocaml.unboxed];; + +let x = A "foo" in +Obj.repr x == Obj.repr (match x with A s -> s) +;; + +(* For records *) +type t2 = { f : string } [@@ocaml.unboxed];; + +let x = { f = "foo" } in +Obj.repr x == Obj.repr x.f +;; + +(* For inline records *) +type t3 = B of { g : string } [@@ocaml.unboxed];; + +let x = B { g = "foo" } in +Obj.repr x == Obj.repr (match x with B {g} -> g) +;; + +(* Check unboxable types *) +type t4 = C [@@ocaml.unboxed];; (* no argument *) +type t5 = D of int * string [@@ocaml.unboxed];; (* more than one argument *) +type t5 = E | F [@@ocaml.unboxed];; (* more than one constructor *) +type t6 = G of int | H [@@ocaml.unboxed];; +type t7 = I of string | J of bool [@@ocaml.unboxed];; + +type t8 = { h : bool; i : int } [@@ocaml.unboxed];; (* more than one field *) +type t9 = K of { j : string; l : int } [@@ocaml.unboxed];; + +(* let rec must be rejected *) +type t10 = A of t10 [@@ocaml.unboxed];; +let rec x = A x;; + +(* Representation mismatch between module and signature must be rejected *) +module M : sig + type t = A of string +end = struct + type t = A of string [@@ocaml.unboxed] +end;; + +module N : sig + type t = A of string [@@ocaml.unboxed] +end = struct + type t = A of string +end;; + +module O : sig + type t = { f : string } +end = struct + type t = { f : string } [@@ocaml.unboxed] +end;; + +module P : sig + type t = { f : string } [@@ocaml.unboxed] +end = struct + type t = { f : string } +end;; + +module Q : sig + type t = A of { f : string } +end = struct + type t = A of { f : string } [@@ocaml.unboxed] +end;; + +module R : sig + type t = A of { f : string } [@@ocaml.unboxed] +end = struct + type t = A of { f : string } +end;; + + +(* Check interference with representation of float arrays. *) +type t11 = L of float [@@ocaml.unboxed];; +let x = Array.make 10 (L 3.14) (* represented as a flat array *) +and f (a : t11 array) = a.(0) (* might wrongly assume an array of pointers *) +in assert (f x = L 3.14);; + + +(* Check for a potential infinite loop in the typing algorithm. *) +type 'a t12 = M of 'a t12 [@@ocaml.unboxed];; +let f (a : int t12 array) = a.(0);; + +(* Check for another possible loop *) +type t13 = A : _ t12 -> t13 [@@ocaml.unboxed];; + + + +(* should work *) +type t14;; +type t15 = A of t14 [@@ocaml.unboxed];; + +(* should fail *) +type 'a abs;; +type t16 = A : _ abs -> t16 [@@ocaml.unboxed];; + +(* should work *) +type t18 = A : _ list abs -> t18 [@@ocaml.unboxed];; + +(* should fail because the compiler knows that t is actually float and + optimizes the record's representation *) +module S : sig + type t + type u = { f1 : t; f2 : t } +end = struct + type t = A of float [@@ocaml.unboxed] + type u = { f1 : t; f2 : t } +end;; + + +(* implementing [@@immediate] with [@@ocaml.unboxed]: this works because the + representation of [t] is [int] + *) +module T : sig + type t [@@immediate] +end = struct + type t = A of int [@@ocaml.unboxed] +end;; diff --git a/testsuite/tests/typing-unboxed-types/test.ml.reference b/testsuite/tests/typing-unboxed-types/test.ml.reference new file mode 100644 index 0000000000..b555db8d12 --- /dev/null +++ b/testsuite/tests/typing-unboxed-types/test.ml.reference @@ -0,0 +1,162 @@ + +# type t1 = A of string [@@unboxed] +# - : bool = true +# type t2 = { f : string; } [@@unboxed] +# - : bool = true +# type t3 = B of { g : string; } [@@unboxed] +# - : bool = true +# Characters 29-58: + type t4 = C [@@ocaml.unboxed];; (* no argument *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because its constructor has no argument. +# Characters 0-45: + type t5 = D of int * string [@@ocaml.unboxed];; (* more than one argument *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because + its constructor has more than one argument. +# Characters 0-33: + type t5 = E | F [@@ocaml.unboxed];; (* more than one constructor *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because it has more than one constructor. +# Characters 0-40: + type t6 = G of int | H [@@ocaml.unboxed];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because it has more than one constructor. +# Characters 0-51: + type t7 = I of string | J of bool [@@ocaml.unboxed];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because it has more than one constructor. +# Characters 1-50: + type t8 = { h : bool; i : int } [@@ocaml.unboxed];; (* more than one field *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because it has more than one field. +# Characters 0-56: + type t9 = K of { j : string; l : int } [@@ocaml.unboxed];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because + its constructor has more than one argument. +# type t10 = A of t10 [@@unboxed] +# Characters 12-15: + let rec x = A x;; + ^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +# Characters 121-172: + ......struct + type t = A of string [@@ocaml.unboxed] + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = A of string [@@unboxed] end + is not included in + sig type t = A of string end + Type declarations do not match: + type t = A of string [@@unboxed] + is not included in + type t = A of string + Their internal representations differ: + the first declaration uses unboxed representation. +# Characters 63-96: + ......struct + type t = A of string + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = A of string end + is not included in + sig type t = A of string [@@unboxed] end + Type declarations do not match: + type t = A of string + is not included in + type t = A of string [@@unboxed] + Their internal representations differ: + the second declaration uses unboxed representation. +# Characters 48-102: + ......struct + type t = { f : string } [@@ocaml.unboxed] + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = { f : string; } [@@unboxed] end + is not included in + sig type t = { f : string; } end + Type declarations do not match: + type t = { f : string; } [@@unboxed] + is not included in + type t = { f : string; } + Their internal representations differ: + the first declaration uses unboxed representation. +# Characters 66-102: + ......struct + type t = { f : string } + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = { f : string; } end + is not included in + sig type t = { f : string; } [@@unboxed] end + Type declarations do not match: + type t = { f : string; } + is not included in + type t = { f : string; } [@@unboxed] + Their internal representations differ: + the second declaration uses unboxed representation. +# Characters 53-112: + ......struct + type t = A of { f : string } [@@ocaml.unboxed] + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = A of { f : string; } [@@unboxed] end + is not included in + sig type t = A of { f : string; } end + Type declarations do not match: + type t = A of { f : string; } [@@unboxed] + is not included in + type t = A of { f : string; } + Their internal representations differ: + the first declaration uses unboxed representation. +# Characters 71-112: + ......struct + type t = A of { f : string } + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = A of { f : string; } end + is not included in + sig type t = A of { f : string; } [@@unboxed] end + Type declarations do not match: + type t = A of { f : string; } + is not included in + type t = A of { f : string; } [@@unboxed] + Their internal representations differ: + the second declaration uses unboxed representation. +# type t11 = L of float [@@unboxed] +# - : unit = () +# type 'a t12 = M of 'a t12 [@@unboxed] +# val f : int t12 array -> int t12 = <fun> +# type t13 = A : 'a t12 -> t13 [@@unboxed] +# type t14 +# type t15 = A of t14 [@@unboxed] +# type 'a abs +# Characters 0-45: + type t16 = A : _ abs -> t16 [@@ocaml.unboxed];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This type cannot be unboxed because + it might contain both float and non-float values. + You should annotate it with [@@ocaml.boxed]. +# type t18 = A : 'a list abs -> t18 [@@unboxed] +# * Characters 176-256: + ......struct + type t = A of float [@@ocaml.unboxed] + type u = { f1 : t; f2 : t } + end.. +Error: Signature mismatch: + ... + Type declarations do not match: + type u = { f1 : t; f2 : t; } + is not included in + type u = { f1 : t; f2 : t; } + Their internal representations differ: + the first declaration uses unboxed float representation. +# * * module T : sig type t [@@immediate] end +# diff --git a/tools/ocamlcp.ml b/tools/ocamlcp.ml index 5879ee602a..22d1e29aae 100644 --- a/tools/ocamlcp.ml +++ b/tools/ocamlcp.ml @@ -102,6 +102,8 @@ module Options = Main_args.Make_bytecomp_options (struct let _no_strict_formats = option "-no-strict-formats" let _thread () = option "-thread" () let _vmthread () = option "-vmthread" () + let _unboxed_types = option "-unboxed-types" + let _no_unboxed_types = option "-no-unboxed-types" let _unsafe = option "-unsafe" let _unsafe_string = option "-unsafe-string" let _use_prims s = option_with_arg "-use-prims" s diff --git a/tools/ocamloptp.ml b/tools/ocamloptp.ml index b903f390e2..188674af4e 100644 --- a/tools/ocamloptp.ml +++ b/tools/ocamloptp.ml @@ -128,6 +128,8 @@ module Options = Main_args.Make_optcomp_options (struct let _thread = option "-thread" let _unbox_closures = option "-unbox-closures" let _unbox_closures_factor = option_with_int "-unbox-closures" + let _unboxed_types = option "-unboxed-types" + let _no_unboxed_types = option "-no-unboxed-types" let _unsafe = option "-unsafe" let _unsafe_string = option "-unsafe-string" let _v = option "-v" diff --git a/toplevel/genprintval.ml b/toplevel/genprintval.ml index 2c9d8a0cb4..28682a9d09 100644 --- a/toplevel/genprintval.ml +++ b/toplevel/genprintval.ml @@ -365,9 +365,11 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct tree_of_val depth obj (try Ctype.apply env decl.type_params body ty_list with Ctype.Cannot_apply -> abstract_type) - | {type_kind = Type_variant constr_list} -> + | {type_kind = Type_variant constr_list; type_unboxed} -> + let unbx = type_unboxed.unboxed in let tag = - if O.is_block obj + if unbx then Cstr_unboxed + else if O.is_block obj then Cstr_block(O.tag obj) else Cstr_constant(O.obj obj) in let {cd_id;cd_args;cd_res} = @@ -393,12 +395,12 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct in tree_of_constr_with_args (tree_of_constr env path) (Ident.name cd_id) false 0 depth obj - ty_args + ty_args unbx | Cstr_record lbls -> let r = tree_of_record_fields depth env path type_params ty_list - lbls 0 obj + lbls 0 obj unbx in Oval_constr(tree_of_constr env path (Ident.name cd_id), @@ -413,9 +415,12 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct | Record_extension -> 1 | _ -> 0 in + let unbx = + match rep with Record_unboxed _ -> true | _ -> false + in tree_of_record_fields depth env path decl.type_params ty_list - lbl_list pos obj + lbl_list pos obj unbx end | {type_kind = Type_open} -> tree_of_extension path depth obj @@ -464,7 +469,7 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct end and tree_of_record_fields depth env path type_params ty_list - lbl_list pos obj = + lbl_list pos obj unboxed = let rec tree_of_fields pos = function | [] -> [] | {ld_id; ld_type} :: remainder -> @@ -481,8 +486,9 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct if pos = 0 then tree_of_label env path name else Oide_ident name and v = - nest tree_of_val (depth - 1) (O.field obj pos) - ty_arg + if unboxed + then tree_of_val (depth - 1) obj ty_arg + else nest tree_of_val (depth - 1) (O.field obj pos) ty_arg in (lid, v) :: tree_of_fields (pos + 1) remainder in @@ -497,10 +503,10 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct tree_list start ty_list and tree_of_constr_with_args - tree_of_cstr cstr_name inlined start depth obj ty_args = + tree_of_cstr cstr_name inlined start depth obj ty_args unboxed = let lid = tree_of_cstr cstr_name in let args = - if inlined then + if inlined || unboxed then match ty_args with | [ty] -> [ tree_of_val (depth - 1) obj ty ] | _ -> assert false @@ -533,7 +539,7 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct tree_of_constr_with_args (fun x -> Oide_ident x) name (cstr.cstr_inlined <> None) 1 depth bucket - cstr.cstr_args + cstr.cstr_args false with Not_found | EVP.Error -> match check_depth depth bucket ty with Some x -> x diff --git a/toplevel/opttopmain.ml b/toplevel/opttopmain.ml index 7832a48656..3f5c5c005a 100644 --- a/toplevel/opttopmain.ml +++ b/toplevel/opttopmain.ml @@ -167,6 +167,8 @@ module Options = Main_args.Make_opttop_options (struct let _S = set keep_asm_file let _short_paths = clear real_paths let _stdin () = file_argument "" + let _unboxed_types = set unboxed_types + let _no_unboxed_types = clear unboxed_types let _unsafe = set fast let _verbose = set verbose let _version () = print_version () diff --git a/toplevel/topmain.ml b/toplevel/topmain.ml index 42f0623cc3..16f0c76b8a 100644 --- a/toplevel/topmain.ml +++ b/toplevel/topmain.ml @@ -98,6 +98,8 @@ module Options = Main_args.Make_bytetop_options (struct let _no_strict_sequence = clear strict_sequence let _strict_formats = set strict_formats let _no_strict_formats = clear strict_formats + let _unboxed_types = set unboxed_types + let _no_unboxed_types = clear unboxed_types let _unsafe = set fast let _unsafe_string = set unsafe_string let _version () = print_version () diff --git a/typing/ctype.ml b/typing/ctype.ml index a9d04555b8..7a576276fe 100644 --- a/typing/ctype.ml +++ b/typing/ctype.ml @@ -1100,6 +1100,7 @@ let new_declaration newtype manifest = type_loc = Location.none; type_attributes = []; type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } let instance_constructor ?in_pattern cstr = @@ -4355,6 +4356,7 @@ let nondep_type_decl env mid id is_covariant decl = type_loc = decl.type_loc; type_attributes = decl.type_attributes; type_immediate = decl.type_immediate; + type_unboxed = decl.type_unboxed; } with Not_found -> clear_hash (); diff --git a/typing/datarepr.ml b/typing/datarepr.ml index c9be80ac5d..178af39665 100644 --- a/typing/datarepr.ml +++ b/typing/datarepr.ml @@ -49,7 +49,7 @@ let free_vars ?(param=false) ty = let newgenconstr path tyl = newgenty (Tconstr (path, tyl, ref Mnil)) -let constructor_args priv cd_args cd_res path rep = +let constructor_existentials cd_args cd_res = let tyl = match cd_args with | Cstr_tuple l -> l @@ -63,11 +63,20 @@ let constructor_args priv cd_args cd_res path rep = let res_vars = free_vars type_ret in TypeSet.elements (TypeSet.diff arg_vars_set res_vars) in + (tyl, existentials) + +let constructor_args priv cd_args cd_res path rep = + let tyl, existentials = constructor_existentials cd_args cd_res in match cd_args with | Cstr_tuple l -> existentials, l, None | Cstr_record lbls -> let arg_vars_set = free_vars ~param:true (newgenty (Ttuple tyl)) in let type_params = TypeSet.elements arg_vars_set in + let type_unboxed = + match rep with + | Record_unboxed _ -> { unboxed = true; default = false } + | _ -> { unboxed = false; default = false } + in let tdecl = { type_params; @@ -80,6 +89,7 @@ let constructor_args priv cd_args cd_res path rep = type_loc = Location.none; type_attributes = []; type_immediate = false; + type_unboxed; } in existentials, @@ -104,16 +114,22 @@ let constructor_descrs ty_path decl cstrs = in let (tag, descr_rem) = match cd_args with - Cstr_tuple [] -> (Cstr_constant idx_const, + | _ when decl.type_unboxed.unboxed -> + assert (rem = []); + (Cstr_unboxed, []) + | Cstr_tuple [] -> (Cstr_constant idx_const, describe_constructors (idx_const+1) idx_nonconst rem) | _ -> (Cstr_block idx_nonconst, describe_constructors idx_const (idx_nonconst+1) rem) in - let cstr_name = Ident.name cd_id in let existentials, cstr_args, cstr_inlined = + let representation = + if decl.type_unboxed.unboxed + then Record_unboxed true + else Record_inlined idx_nonconst + in constructor_args decl.type_private cd_args cd_res - (Path.Pdot (ty_path, cstr_name, Path.nopos)) - (Record_inlined idx_nonconst) + (Path.Pdot (ty_path, cstr_name, Path.nopos)) representation in let cstr = { cstr_name; @@ -201,7 +217,7 @@ let rec find_constr tag num_const num_nonconst = function then c else find_constr tag (num_const + 1) num_nonconst rem | c :: rem -> - if tag = Cstr_block num_nonconst + if tag = Cstr_block num_nonconst || tag = Cstr_unboxed then c else find_constr tag num_const (num_nonconst + 1) rem diff --git a/typing/datarepr.mli b/typing/datarepr.mli index de8a8c2858..8a85282add 100644 --- a/typing/datarepr.mli +++ b/typing/datarepr.mli @@ -34,3 +34,11 @@ exception Constr_not_found val find_constr_by_tag: constructor_tag -> constructor_declaration list -> constructor_declaration + +val constructor_existentials : + constructor_arguments -> type_expr option -> type_expr list * type_expr list +(** Takes [cd_args] and [cd_res] from a [constructor_declaration] and + returns: + - the types of the constructor's arguments + - the existential variables introduced by the constructor + *) diff --git a/typing/includecore.ml b/typing/includecore.ml index c367640b74..e94035c111 100644 --- a/typing/includecore.ml +++ b/typing/includecore.ml @@ -126,7 +126,8 @@ type type_mismatch = | Field_arity of Ident.t | Field_names of int * Ident.t * Ident.t | Field_missing of bool * Ident.t - | Record_representation of bool + | Record_representation of bool (* true means second one is unboxed float *) + | Unboxed_representation of bool (* true means second one is unboxed *) | Immediate let report_type_mismatch0 first second decl ppf err = @@ -154,6 +155,10 @@ let report_type_mismatch0 first second decl ppf err = pr "Their internal representations differ:@ %s %s %s" (if b then second else first) decl "uses unboxed float representation" + | Unboxed_representation b -> + pr "Their internal representations differ:@ %s %s %s" + (if b then second else first) decl + "uses unboxed representation" | Immediate -> pr "%s is not an immediate type" first let report_type_mismatch first second decl ppf = @@ -236,6 +241,15 @@ let type_declarations ?(equality = false) env name decl1 id decl2 = else [Constraint] in if err <> [] then err else + let err = + match (decl2.type_kind, decl1.type_unboxed.unboxed, + decl2.type_unboxed.unboxed) with + | Type_abstract, _, _ -> [] + | _, true, false -> [Unboxed_representation false] + | _, false, true -> [Unboxed_representation true] + | _ -> [] + in + if err <> [] then err else let err = match (decl1.type_kind, decl2.type_kind) with (_, Type_abstract) -> [] | (Type_variant cstrs1, Type_variant cstrs2) -> diff --git a/typing/includecore.mli b/typing/includecore.mli index 17278a4aff..8ddd59cddc 100644 --- a/typing/includecore.mli +++ b/typing/includecore.mli @@ -33,6 +33,7 @@ type type_mismatch = | Field_names of int * Ident.t * Ident.t | Field_missing of bool * Ident.t | Record_representation of bool + | Unboxed_representation of bool | Immediate val value_descriptions: diff --git a/typing/oprint.ml b/typing/oprint.ml index 6531c1e309..02f236ccb7 100644 --- a/typing/oprint.ml +++ b/typing/oprint.ml @@ -506,6 +506,9 @@ and print_out_type_decl kwd ppf td = let print_immediate ppf = if td.otype_immediate then fprintf ppf " [%@%@immediate]" else () in + let print_unboxed ppf = + if td.otype_unboxed then fprintf ppf " [%@%@unboxed]" else () + in let print_out_tkind ppf = function | Otyp_abstract -> () | Otyp_record lbls -> @@ -523,11 +526,12 @@ and print_out_type_decl kwd ppf td = print_private td.otype_private !out_type ty in - fprintf ppf "@[<2>@[<hv 2>%t%a@]%t%t@]" + fprintf ppf "@[<2>@[<hv 2>%t%a@]%t%t%t@]" print_name_params print_out_tkind ty print_constraints print_immediate + print_unboxed and print_out_constr ppf (name, tyl,ret_type_opt) = let name = diff --git a/typing/outcometree.mli b/typing/outcometree.mli index 7d4cb5b6e1..b926c920a3 100644 --- a/typing/outcometree.mli +++ b/typing/outcometree.mli @@ -106,6 +106,7 @@ and out_type_decl = otype_type: out_type; otype_private: Asttypes.private_flag; otype_immediate: bool; + otype_unboxed: bool; otype_cstrs: (out_type * out_type) list } and out_extension_constructor = { oext_name: string; diff --git a/typing/parmatch.ml b/typing/parmatch.ml index 57d470d1a5..b78227d794 100644 --- a/typing/parmatch.ml +++ b/typing/parmatch.ml @@ -1848,7 +1848,8 @@ let extendable_path path = Path.same path Predef.path_option) let rec collect_paths_from_pat r p = match p.pat_desc with -| Tpat_construct(_, {cstr_tag=(Cstr_constant _|Cstr_block _)},ps) -> +| Tpat_construct(_, {cstr_tag=(Cstr_constant _|Cstr_block _|Cstr_unboxed)},ps) + -> let path = get_type_path p.pat_type p.pat_env in List.fold_left collect_paths_from_pat diff --git a/typing/predef.ml b/typing/predef.ml index db3d714caa..be90b46009 100644 --- a/typing/predef.ml +++ b/typing/predef.ml @@ -125,6 +125,7 @@ let decl_abstr = type_newtype_level = None; type_attributes = []; type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } let decl_abstr_imm = {decl_abstr with type_immediate = true} diff --git a/typing/printtyp.ml b/typing/printtyp.ml index b9c3badd38..f99d80abcd 100644 --- a/typing/printtyp.ml +++ b/typing/printtyp.ml @@ -863,6 +863,7 @@ let rec tree_of_type_decl id decl = otype_type = ty; otype_private = priv; otype_immediate = immediate; + otype_unboxed = decl.type_unboxed.unboxed; otype_cstrs = constraints } and tree_of_constructor_arguments = function @@ -1157,6 +1158,7 @@ let dummy = type_newtype_level = None; type_loc = Location.none; type_attributes = []; type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } let hide_rec_items = function diff --git a/typing/subst.ml b/typing/subst.ml index 6b05651782..85a529f80b 100644 --- a/typing/subst.ml +++ b/typing/subst.ml @@ -262,6 +262,7 @@ let type_declaration s decl = type_loc = loc s decl.type_loc; type_attributes = attrs s decl.type_attributes; type_immediate = decl.type_immediate; + type_unboxed = decl.type_unboxed; } in cleanup_types (); diff --git a/typing/typeclass.ml b/typing/typeclass.ml index f71adb974a..97a400c51c 100644 --- a/typing/typeclass.ml +++ b/typing/typeclass.ml @@ -1243,6 +1243,7 @@ let temp_abbrev loc env id arity = type_loc = loc; type_attributes = []; (* or keep attrs from the class decl? *) type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } env in @@ -1490,6 +1491,7 @@ let class_infos define_class kind type_loc = cl.pci_loc; type_attributes = []; (* or keep attrs from cl? *) type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } in let (cl_params, cl_ty) = @@ -1508,6 +1510,7 @@ let class_infos define_class kind type_loc = cl.pci_loc; type_attributes = []; (* or keep attrs from cl? *) type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } in ((cl, id, clty, ty_id, cltydef, obj_id, obj_abbr, cl_id, cl_abbr, ci_params, diff --git a/typing/typecore.ml b/typing/typecore.ml index 4cb5bf28d4..c17fc85238 100644 --- a/typing/typecore.ml +++ b/typing/typecore.ml @@ -772,8 +772,8 @@ module Label = NameChoice (struct let unbound_name_error = Typetexp.unbound_label_error let in_env lbl = match lbl.lbl_repres with - | Record_regular | Record_float -> true - | Record_inlined _ | Record_extension -> false + | Record_regular | Record_float | Record_unboxed false -> true + | Record_unboxed true | Record_inlined _ | Record_extension -> false end) let disambiguate_label_by_ids keep closed ids labels = @@ -2896,6 +2896,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = type_loc = loc; type_attributes = []; type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } in Ident.set_current_time ty.level; diff --git a/typing/typedecl.ml b/typing/typedecl.ml index 12a54b23f2..11e32edbef 100644 --- a/typing/typedecl.ml +++ b/typing/typedecl.ml @@ -55,11 +55,27 @@ type error = | Cannot_unbox_or_untag_type of native_repr_kind | Deep_unbox_or_untag_attribute of native_repr_kind | Bad_immediate_attribute + | Bad_unboxed_attribute of string + | Wrong_unboxed_type_float + | Boxed_and_unboxed open Typedtree exception Error of Location.t * error +(* Note: do not factor the branches in the following pattern-matching: + the records must be constants for the compiler to do sharing on them. +*) +let get_unboxed_from_attributes sdecl = + let unboxed = Builtin_attributes.has_unboxed sdecl.ptype_attributes in + let boxed = Builtin_attributes.has_boxed sdecl.ptype_attributes in + match boxed, unboxed, !Clflags.unboxed_types with + | true, true, _ -> raise (Error(sdecl.ptype_loc, Boxed_and_unboxed)) + | true, false, _ -> { unboxed = false; default = false } + | false, true, _ -> { unboxed = true; default = false } + | false, false, false -> { unboxed = false; default = true } + | false, false, true -> { unboxed = true; default = true } + (* Enter all declared types in the environment as abstract types *) let enter_type env sdecl id = @@ -77,6 +93,7 @@ let enter_type env sdecl id = type_loc = sdecl.ptype_loc; type_attributes = sdecl.ptype_attributes; type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } in Env.add_type ~check:true id decl env @@ -91,12 +108,37 @@ let update_type temp_env env id loc = with Ctype.Unify trace -> raise (Error(loc, Type_clash (env, trace))) -(* Determine if a type is (an abbreviation for) the type "float" *) (* We use the Ctype.expand_head_opt version of expand_head to get access to the manifest type of private abbreviations. *) +let rec get_unboxed_type_representation env ty fuel = + if fuel < 0 then None else + let ty = Ctype.repr (Ctype.expand_head_opt env ty) in + match ty.desc with + | Tconstr (p, args, _) -> + let tydecl = Env.find_type p env in + if tydecl.type_unboxed.unboxed then begin + match tydecl.type_kind with + | Type_record ([{ld_type = ty2; _}], _) + | Type_variant [{cd_args = Cstr_tuple [ty2]; _}] + | Type_variant [{cd_args = Cstr_record [{ld_type = ty2; _}]; _}] + -> get_unboxed_type_representation env + (Ctype.apply env tydecl.type_params ty2 args) (fuel - 1) + | Type_abstract -> None + (* This case can occur when checking a recursive unboxed type + declaration. *) + | _ -> assert false (* only the above can be unboxed *) + end else + Some ty + | _ -> Some ty + +let get_unboxed_type_representation env ty = + get_unboxed_type_representation env ty 100000 +;; + +(* Determine if a type's values are represented by floats at run-time. *) let is_float env ty = - match Ctype.repr (Ctype.expand_head_opt env ty) with - {desc = Tconstr(p, _, _)} -> Path.same p Predef.path_float + match get_unboxed_type_representation env ty with + Some {desc = Tconstr(p, _, _); _} -> Path.same p Predef.path_float | _ -> false (* Determine if a type definition defines a fixed type. (PW) *) @@ -226,6 +268,31 @@ let make_constructor env type_path type_params sargs sret_type = widen z; targs, Some tret_type, args, Some ret_type +(* Check that the argument to a GADT constructor is compatible with unboxing + the type, given the existential variables introduced by this constructor. *) +let rec check_unboxed_gadt_arg loc ex env ty = + match get_unboxed_type_representation env ty with + | Some {desc = Tvar _; id} -> + let f t = (Btype.repr t).id = id in + if List.exists f ex then raise(Error(loc, Wrong_unboxed_type_float)) + | Some {desc = Tarrow _ | Ttuple _ | Tpackage _ | Tobject _ | Tnil + | Tvariant _; _} -> + () + (* A comment in [Translcore.transl_exp0] claims the above cannot be + represented by floats. *) + | Some {desc = Tconstr (p, args, _); _} -> + let tydecl = Env.find_type p env in + assert (not tydecl.type_unboxed.unboxed); + if tydecl.type_kind = Type_abstract then + List.iter (check_unboxed_gadt_arg loc ex env) args + | Some {desc = Tfield _ | Tlink _ | Tsubst _; _} -> assert false + | Some {desc = Tunivar _; _} -> () + | Some {desc = Tpoly (t2, _); _} -> check_unboxed_gadt_arg loc ex env t2 + | None -> () + (* This case is tricky: the argument is another (or the same) type + in the same recursive definition. In this case we don't have to + check because we will also check that other type for correctness. *) + let transl_declaration env sdecl id = (* Bind type parameters *) reset_type_variables(); @@ -238,9 +305,54 @@ let transl_declaration env sdecl id = transl_simple_type env false sty', loc) sdecl.ptype_cstrs in + let raw_status = get_unboxed_from_attributes sdecl in + if raw_status.unboxed && not raw_status.default then begin + match sdecl.ptype_kind with + | Ptype_abstract -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "it is abstract")) + | Ptype_variant [{pcd_args = Pcstr_tuple []; _}] -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "its constructor has no argument")) + | Ptype_variant [{pcd_args = Pcstr_tuple [_]; _}] -> () + | Ptype_variant [{pcd_args = Pcstr_tuple _; _}] -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "its constructor has more than one argument")) + | Ptype_variant [{pcd_args = Pcstr_record + [{pld_mutable=Immutable; _}]; _}] -> () + | Ptype_variant [{pcd_args = Pcstr_record [{pld_mutable=Mutable; _}]; _}] -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute "it is mutable")) + | Ptype_variant [{pcd_args = Pcstr_record _; _}] -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "its constructor has more than one argument")) + | Ptype_variant _ -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "it has more than one constructor")) + | Ptype_record [{pld_mutable=Immutable; _}] -> () + | Ptype_record [{pld_mutable=Mutable; _}] -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "it is mutable")) + | Ptype_record _ -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "it has more than one field")) + | Ptype_open -> + raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute + "extensible variant types cannot be unboxed")) + end; + let unboxed_status = + match sdecl.ptype_kind with + | Ptype_variant [{pcd_args = Pcstr_tuple [_]; _}] + | Ptype_variant [{pcd_args = Pcstr_record + [{pld_mutable = Immutable; _}]; _}] + | Ptype_record [{pld_mutable = Immutable; _}] -> + raw_status + | _ -> (* The type is not unboxable, mark it as boxed *) + { unboxed = false; default = false } + in + let unbox = unboxed_status.unboxed in let (tkind, kind) = match sdecl.ptype_kind with - Ptype_abstract -> Ttype_abstract, Type_abstract + | Ptype_abstract -> Ttype_abstract, Type_abstract | Ptype_variant scstrs -> assert (scstrs <> []); let all_constrs = ref StringSet.empty in @@ -251,8 +363,8 @@ let transl_declaration env sdecl id = all_constrs := StringSet.add name !all_constrs) scstrs; if List.length - (List.filter (fun cd -> cd.pcd_args <> Pcstr_tuple []) scstrs) - > (Config.max_tag + 1) then + (List.filter (fun cd -> cd.pcd_args <> Pcstr_tuple []) scstrs) + > (Config.max_tag + 1) then raise(Error(sdecl.ptype_loc, Too_many_constructors)); let make_cstr scstr = let name = Ident.create scstr.pcd_name.txt in @@ -260,6 +372,20 @@ let transl_declaration env sdecl id = make_constructor env (Path.Pident id) params scstr.pcd_args scstr.pcd_res in + if unbox then begin + (* Cannot unbox a type when the argument can be both float and + non-float because it interferes with the dynamic float array + optimization. This can only happen when the type is a GADT + and the argument is an existential type variable or an + unboxed (or abstract) type constructor applied to some + existential type variable. Of course we also have to rule + out any abstract type constructor applied to anything that + might be an existential type variable. *) + match Datarepr.constructor_existentials args ret_type with + | _, [] -> () + | [argty], ex -> check_unboxed_gadt_arg sdecl.ptype_loc ex env argty + | _ -> assert false + end; let tcstr = { cd_id = name; cd_name = scstr.pcd_name; @@ -282,7 +408,8 @@ let transl_declaration env sdecl id = | Ptype_record lbls -> let lbls, lbls' = transl_labels env true lbls in let rep = - if List.for_all (fun l -> is_float env l.Types.ld_type) lbls' + if unbox then Record_unboxed false + else if List.for_all (fun l -> is_float env l.Types.ld_type) lbls' then Record_float else Record_regular in @@ -307,6 +434,7 @@ let transl_declaration env sdecl id = type_loc = sdecl.ptype_loc; type_attributes = sdecl.ptype_attributes; type_immediate = false; + type_unboxed = unboxed_status; } in (* Check constraints *) @@ -902,6 +1030,14 @@ let marked_as_immediate decl = let compute_immediacy env tdecl = match (tdecl.type_kind, tdecl.type_manifest) with + | (Type_variant [{cd_args = Cstr_tuple [arg]; _}], _) + | (Type_variant [{cd_args = Cstr_record [{ld_type = arg; _}]; _}], _) + | (Type_record ([{ld_type = arg; _}], _), _) + when tdecl.type_unboxed.unboxed -> + begin match get_unboxed_type_representation env arg with + | Some argrepr -> not (Ctype.maybe_pointer_type env argrepr) + | None -> false + end | (Type_variant (_ :: _ as cstrs), _) -> not (List.exists (fun c -> c.Types.cd_args <> Types.Cstr_tuple []) cstrs) | (Type_abstract, Some(typ)) -> @@ -1485,6 +1621,17 @@ let rec parse_native_repr_attributes env core_type ty ~global_repr = | Ptyp_arrow _, _, _ | _, Tarrow _, _ -> assert false | _ -> ([], make_native_repr env core_type ty ~global_repr) + +let check_unboxable env loc ty = + let ty = Ctype.repr (Ctype.expand_head_opt env ty) in + match ty.desc with + | Tconstr (p, _, _) -> + let tydecl = Env.find_type p env in + if tydecl.type_unboxed.unboxed then + Location.prerr_warning loc + (Warnings.Unboxable_type_in_prim_decl (Path.name p)) + | _ -> () + (* Translate a value declaration *) let transl_value_decl env loc valdecl = let cty = Typetexp.transl_type_scheme env valdecl.pval_type in @@ -1519,6 +1666,7 @@ let transl_value_decl env loc valdecl = && prim.prim_arity > 5 && prim.prim_native_name = "" then raise(Error(valdecl.pval_type.ptyp_loc, Missing_native_external)); + Btype.iter_type_expr (check_unboxable env loc) ty; { val_type = ty; val_kind = Val_prim prim; Types.val_loc = loc; val_attributes = valdecl.pval_attributes } in @@ -1579,11 +1727,16 @@ let transl_with_constraint env id row_path orig_decl sdecl = && sdecl.ptype_private = Private then Location.prerr_warning sdecl.ptype_loc (Warnings.Deprecated "spurious use of private"); + let type_kind, type_unboxed = + if arity_ok && man <> None then + orig_decl.type_kind, orig_decl.type_unboxed + else + Type_abstract, {unboxed = false; default = false} + in let decl = { type_params = params; type_arity = List.length params; - type_kind = - if arity_ok && man <> None then orig_decl.type_kind else Type_abstract; + type_kind; type_private = priv; type_manifest = man; type_variance = []; @@ -1591,6 +1744,7 @@ let transl_with_constraint env id row_path orig_decl sdecl = type_loc = sdecl.ptype_loc; type_attributes = sdecl.ptype_attributes; type_immediate = false; + type_unboxed; } in begin match row_path with None -> () @@ -1638,6 +1792,7 @@ let abstract_type_decl arity = type_loc = Location.none; type_attributes = []; type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } in Ctype.end_def(); generalize_decl decl; @@ -1883,6 +2038,14 @@ let report_error ppf = function fprintf ppf "@[%s@ %s@]" "Types marked with the immediate attribute must be" "non-pointer types like int or bool" + | Bad_unboxed_attribute msg -> + fprintf ppf "@[This type cannot be unboxed because@ %s.@]" msg + | Wrong_unboxed_type_float -> + fprintf ppf "@[This type cannot be unboxed because@ \ + it might contain both float and non-float values.@ \ + You should annotate it with [%@%@ocaml.boxed].@]" + | Boxed_and_unboxed -> + fprintf ppf "@[A type cannot be boxed and unboxed at the same time.@]" let () = Location.register_error_of_exn diff --git a/typing/typedecl.mli b/typing/typedecl.mli index ef46c9d7a5..db4875f96f 100644 --- a/typing/typedecl.mli +++ b/typing/typedecl.mli @@ -59,6 +59,10 @@ val compute_variance_decls: (Types.type_declaration * Types.type_declaration * Types.class_declaration * Types.class_type_declaration) list +(* for typeopt.ml *) +val get_unboxed_type_representation: Env.t -> type_expr -> type_expr option + + type native_repr_kind = Unboxed | Untagged type error = @@ -92,6 +96,9 @@ type error = | Cannot_unbox_or_untag_type of native_repr_kind | Deep_unbox_or_untag_attribute of native_repr_kind | Bad_immediate_attribute + | Bad_unboxed_attribute of string + | Wrong_unboxed_type_float + | Boxed_and_unboxed exception Error of Location.t * error diff --git a/typing/typemod.ml b/typing/typemod.ml index c86e7930ac..defe7aad9d 100644 --- a/typing/typemod.ml +++ b/typing/typemod.ml @@ -188,6 +188,7 @@ let merge_constraint initial_env loc sg constr = type_newtype_level = None; type_attributes = []; type_immediate = false; + type_unboxed = { unboxed = false; default = false }; } and id_row = Ident.create (s^"#row") in let initial_env = diff --git a/typing/types.ml b/typing/types.ml index c90838104f..ad4e64c00d 100644 --- a/typing/types.ml +++ b/typing/types.ml @@ -149,6 +149,7 @@ type type_declaration = type_loc: Location.t; type_attributes: Parsetree.attributes; type_immediate: bool; + type_unboxed: unboxed_status; } and type_kind = @@ -160,6 +161,7 @@ and type_kind = and record_representation = Record_regular (* All fields are boxed / tagged *) | Record_float (* All fields are floats *) + | Record_unboxed of bool (* Unboxed single-field record, inlined or not *) | Record_inlined of int (* Inlined record *) | Record_extension (* Inlined record under extension *) @@ -185,6 +187,12 @@ and constructor_arguments = | Cstr_tuple of type_expr list | Cstr_record of label_declaration list +and unboxed_status = + { + unboxed: bool; + default: bool; (* False if the unboxed field was set from an attribute. *) + } + type extension_constructor = { ext_type_path: Path.t; ext_type_params: type_expr list; @@ -301,6 +309,7 @@ type constructor_description = and constructor_tag = Cstr_constant of int (* Constant constructor (an int) *) | Cstr_block of int (* Regular constructor (a block) *) + | Cstr_unboxed (* Constructor of an unboxed type *) | Cstr_extension of Path.t * bool (* Extension constructor true if a constant false if a block*) diff --git a/typing/types.mli b/typing/types.mli index 45c9ddc6af..a9601d88b0 100644 --- a/typing/types.mli +++ b/typing/types.mli @@ -295,6 +295,7 @@ type type_declaration = type_loc: Location.t; type_attributes: Parsetree.attributes; type_immediate: bool; (* true iff type should not be a pointer *) + type_unboxed: unboxed_status; } and type_kind = @@ -306,6 +307,7 @@ and type_kind = and record_representation = Record_regular (* All fields are boxed / tagged *) | Record_float (* All fields are floats *) + | Record_unboxed of bool (* Unboxed single-field record, inlined or not *) | Record_inlined of int (* Inlined record *) | Record_extension (* Inlined record under extension *) @@ -331,6 +333,12 @@ and constructor_arguments = | Cstr_tuple of type_expr list | Cstr_record of label_declaration list +and unboxed_status = + { + unboxed: bool; + default: bool; (* True for unannotated unboxable types. *) + } + type extension_constructor = { ext_type_path: Path.t; @@ -449,6 +457,7 @@ type constructor_description = and constructor_tag = Cstr_constant of int (* Constant constructor (an int) *) | Cstr_block of int (* Regular constructor (a block) *) + | Cstr_unboxed (* Constructor of an unboxed type *) | Cstr_extension of Path.t * bool (* Extension constructor true if a constant false if a block*) diff --git a/utils/clflags.ml b/utils/clflags.ml index b43c52e0da..c44d73ad9e 100644 --- a/utils/clflags.ml +++ b/utils/clflags.ml @@ -355,3 +355,5 @@ let parse_color_setting = function | "never" -> Some Misc.Color.Never | _ -> None let color = ref Misc.Color.Auto ;; (* -color *) + +let unboxed_types = ref false diff --git a/utils/clflags.mli b/utils/clflags.mli index 49326fe69c..f7939eb6e9 100644 --- a/utils/clflags.mli +++ b/utils/clflags.mli @@ -200,3 +200,5 @@ val set_dumped_pass : string -> bool -> unit val parse_color_setting : string -> Misc.Color.setting option val color : Misc.Color.setting ref + +val unboxed_types : bool ref diff --git a/utils/config.mlp b/utils/config.mlp index 1f918fe221..8459a5354d 100644 --- a/utils/config.mlp +++ b/utils/config.mlp @@ -71,7 +71,7 @@ let flambda = %%FLAMBDA%% let safe_string = %%SAFE_STRING%% let exec_magic_number = "Caml1999X011" -and cmi_magic_number = "Caml1999I020" +and cmi_magic_number = "Caml1999I021" and cmo_magic_number = "Caml1999O011" and cma_magic_number = "Caml1999A012" and cmx_magic_number = @@ -87,7 +87,7 @@ and cmxa_magic_number = and ast_impl_magic_number = "Caml1999M019" and ast_intf_magic_number = "Caml1999N018" and cmxs_magic_number = "Caml2007D002" -and cmt_magic_number = "Caml2012T007" +and cmt_magic_number = "Caml2012T008" let load_path = ref ([] : string list) diff --git a/utils/warnings.ml b/utils/warnings.ml index 488cef8417..70c4759d94 100644 --- a/utils/warnings.ml +++ b/utils/warnings.ml @@ -14,10 +14,10 @@ (**************************************************************************) (* When you change this, you need to update the documentation: - - man/ocamlc.m in ocaml - - man/ocamlopt.m in ocaml - - manual/cmds/comp.etex in the doc sources - - manual/cmds/native.etex in the doc sources + - man/ocamlc.m + - man/ocamlopt.m + - manual/manual/cmds/comp.etex + - manual/manual/cmds/native.etex *) type t = @@ -81,6 +81,7 @@ type t = | No_cmx_file of string (* 58 *) | Assignment_to_non_mutable_value (* 59 *) | Unused_module of string (* 60 *) + | Unboxable_type_in_prim_decl of string (* 61 *) ;; (* If you remove a warning, leave a hole in the numbering. NEVER change @@ -150,6 +151,7 @@ let number = function | No_cmx_file _ -> 58 | Assignment_to_non_mutable_value -> 59 | Unused_module _ -> 60 + | Unboxable_type_in_prim_decl _ -> 61 ;; let last_warning_number = 60 @@ -475,6 +477,12 @@ let message = function in this source file. Such assignments may generate incorrect code \n\ when using Flambda." | Unused_module s -> "unused module " ^ s ^ "." + | Unboxable_type_in_prim_decl t -> + Printf.sprintf + "This primitive declaration uses type %s, which is unannotated and\n\ + unboxable. The representation of such types may change in future\n\ + versions. You should annotate the declaration of %s with [@@boxed]\n\ + or [@@unboxed]." t t ;; let nerrors = ref 0;; diff --git a/utils/warnings.mli b/utils/warnings.mli index 7734aa4654..fb03935b8f 100644 --- a/utils/warnings.mli +++ b/utils/warnings.mli @@ -76,6 +76,7 @@ type t = | No_cmx_file of string (* 58 *) | Assignment_to_non_mutable_value (* 59 *) | Unused_module of string (* 60 *) + | Unboxable_type_in_prim_decl of string (* 61 *) ;; val parse_options : bool -> string -> unit;; |