Skip to content

Commit c349cc4

Browse files
committed
feat(compiler): Use data segments for string data
1 parent bb59bf9 commit c349cc4

File tree

4 files changed

+181
-57
lines changed

4 files changed

+181
-57
lines changed

compiler/src/codegen/compcore.re

Lines changed: 110 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ let gensym_label = s => {
2828
};
2929
let reset_labels = () => gensym_counter := 0;
3030

31+
let data_segments: ref((int, list(Memory.segment))) = ref((0, []));
32+
let push_data_segment = segment => {
33+
let (count, segments) = data_segments^;
34+
data_segments := (count + 1, [segment, ...segments]);
35+
};
36+
let get_data_segment_count = () => {
37+
let (count, _) = data_segments^;
38+
count;
39+
};
40+
let reset_data_segments = () => data_segments := (0, []);
41+
3142
/* Number of swap variables to allocate */
3243
let swap_slots_i32 = [|Type.int32, Type.int32, Type.int32|];
3344
let swap_slots_i64 = [|Type.int64|];
@@ -282,6 +293,7 @@ let init_codegen_env = name => {
282293

283294
let reset = () => {
284295
reset_labels();
296+
reset_data_segments();
285297
List.iter(
286298
imp => imp.mimp_used = imp.mimp_mod == grain_env_mod,
287299
runtime_imports,
@@ -1456,45 +1468,92 @@ let call_lambda =
14561468
};
14571469

14581470
let allocate_byte_like_from_buffer = (wasm_mod, env, buf, tag, label) => {
1459-
let ints_to_push: list(int64) = buf_to_ints(buf);
14601471
let get_swap = () => get_swap(wasm_mod, env, 0);
14611472
let tee_swap = tee_swap(wasm_mod, env, 0);
1462-
let preamble = [
1463-
store(
1464-
~offset=0,
1465-
wasm_mod,
1466-
tee_swap(
1467-
heap_allocate(wasm_mod, env, 2 + 2 * List.length(ints_to_push)),
1468-
),
1469-
Expression.Const.make(
1470-
wasm_mod,
1471-
const_int32(tag_val_of_heap_tag_type(tag)),
1472-
),
1473-
),
1474-
store(
1475-
~offset=4,
1473+
if (Config.bulk_memory^) {
1474+
let segment_offset = get_data_segment_count();
1475+
let data_size = Buffer.length(buf);
1476+
Memory.(
1477+
push_data_segment({
1478+
data: Buffer.to_bytes(buf),
1479+
kind: Passive,
1480+
size: data_size,
1481+
})
1482+
);
1483+
Expression.Block.make(
14761484
wasm_mod,
1477-
get_swap(),
1478-
Expression.Const.make(wasm_mod, const_int32 @@ Buffer.length(buf)),
1479-
),
1480-
];
1481-
let elts =
1482-
List.mapi(
1483-
(idx, i: int64) =>
1485+
gensym_label(label),
1486+
[
14841487
store(
1485-
~ty=Type.int64,
1486-
~offset=8 * (idx + 1),
1488+
~offset=0,
1489+
wasm_mod,
1490+
// compute number of words (add 3 to account for floored division)
1491+
tee_swap(heap_allocate(wasm_mod, env, 2 + (data_size + 3) / 4)),
1492+
Expression.Const.make(
1493+
wasm_mod,
1494+
const_int32(tag_val_of_heap_tag_type(tag)),
1495+
),
1496+
),
1497+
store(
1498+
~offset=4,
14871499
wasm_mod,
14881500
get_swap(),
1489-
Expression.Const.make(wasm_mod, wrap_int64(i)),
1501+
Expression.Const.make(wasm_mod, const_int32 @@ data_size),
14901502
),
1491-
ints_to_push,
1503+
Expression.Memory_init.make(
1504+
wasm_mod,
1505+
segment_offset,
1506+
Expression.Binary.make(
1507+
wasm_mod,
1508+
Op.add_int32,
1509+
get_swap(),
1510+
Expression.Const.make(wasm_mod, const_int32(8)),
1511+
),
1512+
Expression.Const.make(wasm_mod, const_int32(0)),
1513+
Expression.Const.make(wasm_mod, const_int32(data_size)),
1514+
),
1515+
get_swap(),
1516+
],
14921517
);
1493-
Expression.Block.make(
1494-
wasm_mod,
1495-
gensym_label(label),
1496-
List.concat([preamble, elts, [get_swap()]]),
1497-
);
1518+
} else {
1519+
let ints_to_push: list(int64) = buf_to_ints(buf);
1520+
let preamble = [
1521+
store(
1522+
~offset=0,
1523+
wasm_mod,
1524+
tee_swap(
1525+
heap_allocate(wasm_mod, env, 2 + 2 * List.length(ints_to_push)),
1526+
),
1527+
Expression.Const.make(
1528+
wasm_mod,
1529+
const_int32(tag_val_of_heap_tag_type(tag)),
1530+
),
1531+
),
1532+
store(
1533+
~offset=4,
1534+
wasm_mod,
1535+
get_swap(),
1536+
Expression.Const.make(wasm_mod, const_int32 @@ Buffer.length(buf)),
1537+
),
1538+
];
1539+
let elts =
1540+
List.mapi(
1541+
(idx, i: int64) =>
1542+
store(
1543+
~ty=Type.int64,
1544+
~offset=8 * (idx + 1),
1545+
wasm_mod,
1546+
get_swap(),
1547+
Expression.Const.make(wasm_mod, wrap_int64(i)),
1548+
),
1549+
ints_to_push,
1550+
);
1551+
Expression.Block.make(
1552+
wasm_mod,
1553+
gensym_label(label),
1554+
List.concat([preamble, elts, [get_swap()]]),
1555+
);
1556+
};
14981557
};
14991558

15001559
let allocate_byte_like_uninitialized = (wasm_mod, env, size, tag, label) => {
@@ -3514,20 +3573,7 @@ let compile_wasm_module = (~env=?, ~name=?, prog) => {
35143573
// This is because in many use cases in which this is specified (e.g. wasm4), users
35153574
// will expect the static region of memory below the heap base to all be available.
35163575
let _ =
3517-
Settings.set_low_memory_unused(
3518-
Option.is_none(Grain_utils.Config.memory_base^),
3519-
);
3520-
let _ =
3521-
Memory.set_memory(
3522-
wasm_mod,
3523-
0,
3524-
Memory.unlimited,
3525-
"memory",
3526-
[],
3527-
false,
3528-
false,
3529-
grain_memory,
3530-
);
3576+
Settings.set_low_memory_unused(Option.is_none(Config.memory_base^));
35313577

35323578
let compile_all = () => {
35333579
ignore @@ compile_globals(wasm_mod, env, prog);
@@ -3546,6 +3592,25 @@ let compile_wasm_module = (~env=?, ~name=?, prog) => {
35463592
compile_all();
35473593
};
35483594

3595+
let segments =
3596+
if (Config.bulk_memory^) {
3597+
let (_, segments) = data_segments^;
3598+
List.rev(segments);
3599+
} else {
3600+
[];
3601+
};
3602+
let _ =
3603+
Memory.set_memory(
3604+
wasm_mod,
3605+
0,
3606+
Memory.unlimited,
3607+
"memory",
3608+
segments,
3609+
false,
3610+
false,
3611+
grain_memory,
3612+
);
3613+
35493614
if (compiling_wasi_polyfill(name)) {
35503615
write_universal_exports(
35513616
wasm_mod,

compiler/src/linking/link.re

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,15 @@ let is_function_imported = func =>
121121
// constructing the AST (either through constructing two separate instances or by
122122
// using Expression.copy())
123123

124-
let rec globalize_names = (~function_names, ~global_names, ~label_names, expr) => {
124+
let rec globalize_names =
125+
(~function_names, ~global_names, ~label_names, ~data_offset, expr) => {
125126
let globalize_names =
126-
globalize_names(~function_names, ~global_names, ~label_names);
127+
globalize_names(
128+
~function_names,
129+
~global_names,
130+
~label_names,
131+
~data_offset,
132+
);
127133

128134
let add_label = Hashtbl.add(label_names);
129135

@@ -245,6 +251,19 @@ let rec globalize_names = (~function_names, ~global_names, ~label_names, expr) =
245251
globalize_names(Expression.Tuple_make.get_operand_at(expr, i));
246252
};
247253
| TupleExtract => globalize_names(Expression.Tuple_extract.get_tuple(expr))
254+
| MemoryInit =>
255+
Expression.Memory_init.set_segment(
256+
expr,
257+
Expression.Memory_init.get_segment(expr) + data_offset,
258+
);
259+
globalize_names(Expression.Memory_init.get_dest(expr));
260+
globalize_names(Expression.Memory_init.get_offset(expr));
261+
globalize_names(Expression.Memory_init.get_size(expr));
262+
| DataDrop =>
263+
Expression.Data_drop.set_segment(
264+
expr,
265+
Expression.Data_drop.get_segment(expr) + data_offset,
266+
)
248267
| AtomicRMW
249268
| AtomicCmpxchg
250269
| AtomicWait
@@ -257,8 +276,6 @@ let rec globalize_names = (~function_names, ~global_names, ~label_names, expr) =
257276
| SIMDShift
258277
| SIMDLoad
259278
| SIMDLoadStoreLane
260-
| MemoryInit
261-
| DataDrop
262279
| Pop
263280
| RefNull
264281
| RefIs
@@ -387,11 +404,15 @@ let table_offset = ref(0);
387404
let module_id = ref(Comp_utils.encoded_int32(0));
388405

389406
let round_to_8 = n => Int.logand(n + 7, Int.lognot(7));
407+
let data_offset = ref(0);
408+
let data_segments = ref([]);
390409

391410
let link_all = (linked_mod, dependencies, signature) => {
392411
gensym_counter := 0;
393412
table_offset := 0;
394413
module_id := Comp_utils.encoded_int32(0);
414+
data_offset := 0;
415+
data_segments := [];
395416

396417
let main = Module_resolution.current_filename^();
397418
let has_wasi_polyfill = Option.is_some(Config.wasi_polyfill^);
@@ -529,7 +550,14 @@ let link_all = (linked_mod, dependencies, signature) => {
529550
let mut = Global.is_mutable(global);
530551
let init = Global.get_init_expr(global);
531552

532-
globalize_names(~function_names, ~global_names, ~label_names, init);
553+
let data_offset = data_offset^;
554+
globalize_names(
555+
~function_names,
556+
~global_names,
557+
~label_names,
558+
~data_offset,
559+
init,
560+
);
533561
ignore @@ Global.add_global(linked_mod, new_name, ty, mut, init);
534562
};
535563
};
@@ -622,7 +650,14 @@ let link_all = (linked_mod, dependencies, signature) => {
622650
let num_locals = Function.get_num_vars(func);
623651
let locals = Array.init(num_locals, i => Function.get_var(func, i));
624652
let body = Function.get_body(func);
625-
globalize_names(~function_names, ~global_names, ~label_names, body);
653+
let data_offset = data_offset^;
654+
globalize_names(
655+
~function_names,
656+
~global_names,
657+
~label_names,
658+
~data_offset,
659+
body,
660+
);
626661
ignore @@
627662
Function.add_function(
628663
linked_mod,
@@ -663,6 +698,29 @@ let link_all = (linked_mod, dependencies, signature) => {
663698
);
664699
table_offset := table_offset^ + size;
665700
};
701+
702+
let num_data_segments = Memory.get_num_segments(wasm_mod);
703+
for (i in 0 to num_data_segments - 1) {
704+
open Memory;
705+
let data = get_segment_data(wasm_mod, i);
706+
let kind =
707+
if (get_segment_passive(wasm_mod, i)) {
708+
Passive;
709+
} else {
710+
Active({
711+
offset:
712+
Expression.Const.make(
713+
wasm_mod,
714+
Literal.int32(
715+
Int32.of_int(get_segment_byte_offset(wasm_mod, i)),
716+
),
717+
),
718+
});
719+
};
720+
let size = Bytes.length(data);
721+
data_segments := [{data, kind, size}, ...data_segments^];
722+
};
723+
data_offset := data_offset^ + num_data_segments;
666724
};
667725

668726
ignore @@
@@ -722,15 +780,16 @@ let link_all = (linked_mod, dependencies, signature) => {
722780
}),
723781
size: Bytes.length(data),
724782
},
783+
...data_segments^,
725784
]
726-
| None => []
785+
| None => data_segments^
727786
};
728787
Memory.set_memory(
729788
linked_mod,
730789
initial_memory,
731790
maximum_memory,
732791
"memory",
733-
data_segments,
792+
List.rev(data_segments),
734793
false,
735794
false,
736795
Comp_utils.grain_memory,

compiler/src/utils/wasm_utils.re

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type wasm_bin_section_type =
2222
| Element
2323
| Code
2424
| Data
25-
| DataCount;
25+
| DataCount(int);
2626

2727
[@deriving sexp]
2828
type wasm_bin_section = {
@@ -213,7 +213,7 @@ let section_type_of_int = (~pos=?, ~name=?) =>
213213
| 9 => Element
214214
| 10 => Code
215215
| 11 => Data
216-
| 12 => DataCount
216+
| 12 => DataCount(-1)
217217
| n => raise(MalformedSectionType(n, pos));
218218

219219
let int_of_section_type =
@@ -230,7 +230,7 @@ let int_of_section_type =
230230
| Element => 9
231231
| Code => 10
232232
| Data => 11
233-
| DataCount => 12;
233+
| DataCount(_) => 12;
234234

235235
let get_wasm_sections = (~reset=false, inchan) => {
236236
let orig_pos = pos_in(inchan);

compiler/src/utils/wasm_utils.rei

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type wasm_bin_section_type =
2121
| Element
2222
| Code
2323
| Data
24-
| DataCount;
24+
| DataCount(int);
2525

2626
[@deriving sexp]
2727
type wasm_bin_section = {

0 commit comments

Comments
 (0)