From 30a0163302a31214dff91ab14492530a60d80307 Mon Sep 17 00:00:00 2001 From: Simon Krajewski Date: Thu, 8 Feb 2024 13:28:16 +0100 Subject: [PATCH] [hxb] Add OFD and OBD chunks (#11564) * [hxb] add OFD * rename AFR to OFR * [hxb] add OBD --- src/compiler/hxb/hxbData.ml | 18 ++++-- src/compiler/hxb/hxbReader.ml | 32 +++++++--- src/compiler/hxb/hxbWriter.ml | 109 +++++++++++++++++++++++++++------- 3 files changed, 125 insertions(+), 34 deletions(-) diff --git a/src/compiler/hxb/hxbData.ml b/src/compiler/hxb/hxbData.ml index 5bc8499a802..dce1543afa4 100644 --- a/src/compiler/hxb/hxbData.ml +++ b/src/compiler/hxb/hxbData.ml @@ -10,10 +10,10 @@ exception HxbFailure of string EN = enum AB = abstract TD = typedef - AN = anon + OB = anonymous object CF = class field EF = enum field - AF = anon field + OF = object field EX = expression EO = end of (Types | Fields | Module) ..F = forward definition @@ -32,8 +32,10 @@ type chunk_kind = | ENR (* enum references *) | ABR (* abstract references *) | TDR (* typedef references *) - (* Field references *) - | AFR (* anon field references *) + (* Anonymous objects *) + | OFR (* object field references *) + | OFD (* object field definitions *) + | OBD (* object definitions *) (* Own module type definitions *) | CLD (* class definition *) | END (* enum definition *) @@ -71,7 +73,9 @@ let string_of_chunk_kind = function | ENR -> "ENR" | ABR -> "ABR" | TDR -> "TDR" - | AFR -> "AFR" + | OFR -> "OFR" + | OFD -> "OFD" + | OBD -> "OBD" | EFR -> "EFR" | CFR -> "CFR" | CLD -> "CLD" @@ -96,7 +100,9 @@ let chunk_kind_of_string = function | "ENR" -> ENR | "ABR" -> ABR | "TDR" -> TDR - | "AFR" -> AFR + | "OFR" -> OFR + | "OFD" -> OFD + | "OBD" -> OBD | "EFR" -> EFR | "CFR" -> CFR | "CLD" -> CLD diff --git a/src/compiler/hxb/hxbReader.ml b/src/compiler/hxb/hxbReader.ml index a8cd5651d16..c51a824beb9 100644 --- a/src/compiler/hxb/hxbReader.ml +++ b/src/compiler/hxb/hxbReader.ml @@ -301,7 +301,8 @@ class hxb_reader anons.(read_uleb128 ch) | 1 -> let an = anons.(read_uleb128 ch) in - self#read_anon an + self#read_anon an; + an | _ -> assert false @@ -1587,11 +1588,26 @@ class hxb_reader ) in enum_fields <- a - method read_afr = + method read_ofr = let l = read_uleb128 ch in let a = Array.init l (fun _ -> self#read_class_field_forward) in anon_fields <- a + method read_ofd = + let l = read_uleb128 ch in + for i = 0 to l - 1 do + let index = read_uleb128 ch in + let cf = anon_fields.(index) in + self#read_class_field_and_overloads_data cf; + done + + method read_obd = + let l = read_uleb128 ch in + for i = 0 to l - 1 do + let index = read_uleb128 ch in + self#read_anon anons.(index) + done + method read_cfr = let l = read_uleb128 ch in let a = Array.init l (fun i -> @@ -1748,9 +1764,7 @@ class hxb_reader an.a_status := Extend self#read_types; read_fields () | _ -> assert false - end; - - an + end method read_tdd = let l = read_uleb128 ch in @@ -1926,8 +1940,12 @@ class hxb_reader self#read_abr; | TDR -> self#read_tdr; - | AFR -> - self#read_afr; + | OFR -> + self#read_ofr; + | OFD -> + self#read_ofd; + | OBD -> + self#read_obd | CLD -> self#read_cld; | END -> diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index cc2d1c1065c..32b2b1e82fd 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -453,8 +453,8 @@ type hxb_writer = { enums : (path,tenum) Pool.t; typedefs : (path,tdef) Pool.t; abstracts : (path,tabstract) Pool.t; - anons : (path,tanon) Pool.t; - anon_fields : (string,tclass_field,unit) HashedIdentityPool.t; + anons : (path,bytes option) Pool.t; + anon_fields : (string,tclass_field,bytes option) HashedIdentityPool.t; tmonos : (tmono,unit) IdentityPool.t; own_classes : (path,tclass) Pool.t; @@ -468,6 +468,7 @@ type hxb_writer = { mutable field_type_parameters : (typed_type_param,unit) IdentityPool.t; mutable local_type_parameters : (typed_type_param,unit) IdentityPool.t; mutable field_stack : unit list; + mutable wrote_local_type_param : bool; unbound_ttp : (typed_type_param,unit) IdentityPool.t; t_instance_chunk : Chunk.t; } @@ -485,7 +486,7 @@ module HxbWriter = struct | EOT | EOF | EOM -> 0 | MDF -> 16 | MTF | MDR | CLR | END | ABD | ENR | ABR | TDR | EFR | CFR | AFD -> 64 - | AFR | CLD | TDD | EFD -> 128 + | OFR | OFD | OBD | CLD | TDD | EFD -> 128 | STR | DOC -> 256 | CFD | EXD -> 512 in @@ -1002,12 +1003,13 @@ module HxbWriter = struct write_metadata writer v.v_meta; write_pos writer v.v_pos - let rec write_anon writer (an : tanon) (ttp : type_params) = + let rec write_anon writer (an : tanon) = + let needs_local_context = ref false in let write_fields () = let restore = start_temporary_chunk writer 256 in let i = ref 0 in PMap.iter (fun _ cf -> - write_anon_field_ref writer cf; + write_anon_field_ref writer needs_local_context cf; incr i; ) an.a_fields; let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in @@ -1031,30 +1033,56 @@ module HxbWriter = struct assert false | AbstractStatics _ -> assert false - end + end; + !needs_local_context - and write_anon_ref writer (an : tanon) (ttp : type_params) = + and write_anon_ref writer (an : tanon) = let pfm = Option.get (writer.anon_id#identify_anon ~strict:true an) in try let index = Pool.get writer.anons pfm.pfm_path in Chunk.write_u8 writer.chunk 0; Chunk.write_uleb128 writer.chunk index with Not_found -> - let index = Pool.add writer.anons pfm.pfm_path an in - Chunk.write_u8 writer.chunk 1; - Chunk.write_uleb128 writer.chunk index; - write_anon writer an ttp + let restore = start_temporary_chunk writer 256 in + let needs_local_context = write_anon writer an in + let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in + if needs_local_context then begin + let index = Pool.add writer.anons pfm.pfm_path None in + Chunk.write_u8 writer.chunk 1; + Chunk.write_uleb128 writer.chunk index; + Chunk.write_bytes writer.chunk bytes + end else begin + let index = Pool.add writer.anons pfm.pfm_path (Some bytes) in + Chunk.write_u8 writer.chunk 0; + Chunk.write_uleb128 writer.chunk index; + end - and write_anon_field_ref writer cf = + and write_anon_field_ref writer needs_local_context cf = try let index = HashedIdentityPool.get writer.anon_fields cf.cf_name cf in Chunk.write_u8 writer.chunk 0; Chunk.write_uleb128 writer.chunk index with Not_found -> - let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf () in - Chunk.write_u8 writer.chunk 1; - Chunk.write_uleb128 writer.chunk index; - ignore(write_class_field_and_overloads_data writer true cf) + let restore = start_temporary_chunk writer 256 in + let old = writer.wrote_local_type_param in + writer.wrote_local_type_param <- false; + ignore(write_class_field_and_overloads_data writer true cf); + let wrote_local_type_param = writer.wrote_local_type_param in + writer.wrote_local_type_param <- old; + let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in + if wrote_local_type_param then begin + (* If we access something from the method scope, we have to write the anon field immediately. + This should be fine because in such cases the field cannot be referenced elsewhere. *) + let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf None in + needs_local_context := true; + Chunk.write_u8 writer.chunk 1; + Chunk.write_uleb128 writer.chunk index; + Chunk.write_bytes writer.chunk bytes + end else begin + let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf (Some bytes) in + Chunk.write_u8 writer.chunk 0; + Chunk.write_uleb128 writer.chunk index; + end (* Type instances *) @@ -1063,14 +1091,18 @@ module HxbWriter = struct begin match ttp.ttp_host with | TPHType -> let i = Pool.get writer.type_type_parameters ttp.ttp_name in + (* TODO: this isn't correct, but if we don't do this we'll have to communicate the current class *) + writer.wrote_local_type_param <- true; Chunk.write_u8 writer.chunk 1; Chunk.write_uleb128 writer.chunk i | TPHMethod | TPHEnumConstructor | TPHAnonField | TPHConstructor -> let i = IdentityPool.get writer.field_type_parameters ttp in + writer.wrote_local_type_param <- true; Chunk.write_u8 writer.chunk 2; Chunk.write_uleb128 writer.chunk i; | TPHLocal -> let index = IdentityPool.get writer.local_type_parameters ttp in + writer.wrote_local_type_param <- true; Chunk.write_u8 writer.chunk 3; Chunk.write_uleb128 writer.chunk index; end with Not_found -> @@ -1239,7 +1271,7 @@ module HxbWriter = struct Chunk.write_u8 writer.chunk 80; | TAnon an -> Chunk.write_u8 writer.chunk 81; - write_anon_ref writer an [] + write_anon_ref writer an | TDynamic (Some t) -> Chunk.write_u8 writer.chunk 89; write_type_instance writer t @@ -1532,7 +1564,7 @@ module HxbWriter = struct | TField(e1,FAnon cf) -> Chunk.write_u8 writer.chunk 104; loop e1; - write_anon_field_ref writer cf; + write_anon_field_ref writer (ref false) cf; true; | TField(e1,FClosure(Some(c,tl),cf)) -> Chunk.write_u8 writer.chunk 105; @@ -1544,7 +1576,7 @@ module HxbWriter = struct | TField(e1,FClosure(None,cf)) -> Chunk.write_u8 writer.chunk 106; loop e1; - write_anon_field_ref writer cf; + write_anon_field_ref writer (ref false) cf; true; | TField(e1,FEnum(en,ef)) -> Chunk.write_u8 writer.chunk 107; @@ -2121,11 +2153,28 @@ module HxbWriter = struct let items = HashedIdentityPool.finalize writer.anon_fields in if DynArray.length items > 0 then begin - start_chunk writer AFR; + start_chunk writer OFR; Chunk.write_uleb128 writer.chunk (DynArray.length items); DynArray.iter (fun (cf,_) -> write_class_field_forward writer cf ) items; + + let anon_fields_with_expr = DynArray.create () in + DynArray.iteri (fun i (_,bytes) -> match bytes with + | None -> + () + | Some bytes -> + DynArray.add anon_fields_with_expr (i,bytes) + ) items; + if DynArray.length anon_fields_with_expr > 0 then begin + start_chunk writer OFD; + Chunk.write_uleb128 writer.chunk (DynArray.length anon_fields_with_expr); + DynArray.iter (fun (index,bytes) -> + Chunk.write_uleb128 writer.chunk index; + Chunk.write_bytes writer.chunk bytes + ) anon_fields_with_expr + end; + end; let items = Pool.finalize writer.classes in @@ -2164,9 +2213,26 @@ module HxbWriter = struct start_chunk writer MDF; write_path writer m.m_path; Chunk.write_string writer.chunk (Path.UniqueKey.lazy_path m.m_extra.m_file); - Chunk.write_uleb128 writer.chunk (DynArray.length (Pool.finalize writer.anons)); + let anons = Pool.finalize writer.anons in + Chunk.write_uleb128 writer.chunk (DynArray.length anons); Chunk.write_uleb128 writer.chunk (DynArray.length (IdentityPool.finalize writer.tmonos)); + let anons_without_context = DynArray.create () in + DynArray.iteri (fun i bytes -> match bytes with + | None -> + () + | Some bytes -> + DynArray.add anons_without_context (i,bytes) + ) anons; + if DynArray.length anons_without_context > 0 then begin + start_chunk writer OBD; + Chunk.write_uleb128 writer.chunk (DynArray.length anons_without_context); + DynArray.iter (fun (i,bytes) -> + Chunk.write_uleb128 writer.chunk i; + Chunk.write_bytes writer.chunk bytes + ) anons_without_context + end; + begin let deps = DynArray.create () in PMap.iter (fun _ mdep -> @@ -2244,6 +2310,7 @@ let create config warn anon_id = field_type_parameters = IdentityPool.create (); local_type_parameters = IdentityPool.create (); field_stack = []; + wrote_local_type_param = false; unbound_ttp = IdentityPool.create (); t_instance_chunk = Chunk.create EOM cp 32; }