Skip to content

Commit 202e226

Browse files
committed
Fix method lookup cache with separate compilation
1 parent a53bd09 commit 202e226

File tree

5 files changed

+121
-46
lines changed

5 files changed

+121
-46
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
* Runtime: fix caml_string_concat when not using JS strings (#1874)
6060
* Runtime: consistent bigarray hashing across all architectures (#1977)
6161
* Runtime: fix caml_utf8_of_utf16 bug in high surrogate case (#2008)
62-
* Runtime/wasm: fix method lookup (#2034, #2038)
62+
* Runtime/wasm/js: fix method lookup (#2034, #2038, #2039)
6363
* Tools: fix jsoo_mktop and jsoo_mkcmis (#1877)
6464
* Toplevel: fix for when use-js-strings is disabled (#1997)
6565

compiler/lib/parse_bytecode.ml

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ type globals =
532532
; mutable is_const : bool array
533533
; mutable is_exported : bool array
534534
; mutable named_value : string option array
535+
; mutable cache_ids : Var.t list
535536
; constants : Code.constant array
536537
; primitives : string array
537538
}
@@ -541,6 +542,7 @@ let make_globals size constants primitives =
541542
; is_const = Array.make size false
542543
; is_exported = Array.make size false
543544
; named_value = Array.make size None
545+
; cache_ids = []
544546
; constants
545547
; primitives
546548
}
@@ -818,8 +820,6 @@ let tagged_blocks = ref Addr.Map.empty
818820

819821
let compiled_blocks : (_ * instr list * last) Addr.Map.t ref = ref Addr.Map.empty
820822

821-
let method_cache_id = ref 1
822-
823823
let clo_offset_3 = 3
824824

825825
type compile_info =
@@ -2353,24 +2353,20 @@ and compile infos pc state (instrs : instr list) =
23532353
(Let (x, Prim (Ult, [ Pv z; Pv y ])) :: instrs)
23542354
| GETPUBMET ->
23552355
let n = gets32 code (pc + 1) in
2356-
let cache = !method_cache_id in
2357-
incr method_cache_id;
23582356
let obj = State.accu state in
23592357
let state = State.push state in
2360-
let tag, state = State.fresh_var state in
2358+
let cache_id = Var.fresh_n "cache_id" in
2359+
state.globals.cache_ids <- cache_id :: state.globals.cache_ids;
23612360
let m, state = State.fresh_var state in
2362-
2363-
if debug_parser () then Format.printf "%a = %ld@." Var.print tag n;
23642361
if debug_parser ()
23652362
then
23662363
Format.printf
2367-
"%a = caml_get_public_method(%a, %a)@."
2364+
"%a = caml_get_public_method(%a, %ld)@."
23682365
Var.print
23692366
m
23702367
Var.print
23712368
obj
2372-
Var.print
2373-
tag;
2369+
n;
23742370
compile
23752371
infos
23762372
(pc + 3)
@@ -2379,8 +2375,7 @@ and compile infos pc state (instrs : instr list) =
23792375
( m
23802376
, Prim
23812377
( Extern "caml_get_public_method"
2382-
, [ Pv obj; Pv tag; Pc (Int (Targetint.of_int_exn cache)) ] ) )
2383-
:: Let (tag, const32 n)
2378+
, [ Pv obj; Pc (Int (Targetint.of_int32_exn n)); Pv cache_id ] ) )
23842379
:: instrs)
23852380
| GETDYNMET ->
23862381
let tag = State.accu state in
@@ -2390,7 +2385,7 @@ and compile infos pc state (instrs : instr list) =
23902385
if debug_parser ()
23912386
then
23922387
Format.printf
2393-
"%a = caml_get_public_method(%a, %a)@."
2388+
"%a = caml_get_dyn_method(%a, %a)@."
23942389
Var.print
23952390
m
23962391
Var.print
@@ -2401,12 +2396,7 @@ and compile infos pc state (instrs : instr list) =
24012396
infos
24022397
(pc + 1)
24032398
state
2404-
(Let
2405-
( m
2406-
, Prim
2407-
( Extern "caml_get_public_method"
2408-
, [ Pv obj; Pv tag; Pc (Int Targetint.zero) ] ) )
2409-
:: instrs)
2399+
(Let (m, Prim (Extern "caml_get_dyn_method", [ Pv obj; Pv tag ])) :: instrs)
24102400
| GETMETHOD ->
24112401
let lab = State.accu state in
24122402
let obj = State.peek 0 state in
@@ -2537,7 +2527,12 @@ let parse_bytecode code globals debug_data =
25372527
in
25382528
compiled_blocks := Addr.Map.empty;
25392529
tagged_blocks := Addr.Map.empty;
2540-
Code.compact p
2530+
let p = Code.compact p in
2531+
let body =
2532+
List.fold_left globals.cache_ids ~init:[] ~f:(fun body cache_id ->
2533+
Let (cache_id, Prim (Extern "caml_oo_cache_id", [])) :: body)
2534+
in
2535+
Code.prepend p body
25412536

25422537
module Toc : sig
25432538
type t

compiler/tests-full/stdlib.cma.expected.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30802,7 +30802,7 @@
3080230802
caml_array_make = runtime.caml_array_make,
3080330803
caml_check_bound = runtime.caml_check_bound,
3080430804
caml_div = runtime.caml_div,
30805-
caml_get_public_method = runtime.caml_get_public_method,
30805+
caml_get_dyn_method = runtime.caml_get_dyn_method,
3080630806
caml_maybe_attach_backtrace = runtime.caml_maybe_attach_backtrace,
3080730807
caml_obj_block = runtime.caml_obj_block,
3080830808
caml_set_oo_id = runtime.caml_set_oo_id,
@@ -31666,15 +31666,15 @@
3166631666
/*<<camlinternalOO.ml:587:57>>*/ new_cache(table);
3166731667
/*<<camlinternalOO.ml:492:2>>*/ return function(obj){
3166831668
/*<<camlinternalOO.ml:492:18>>*/ return caml_call1
31669-
(caml_get_public_method(x$9, m$2, 0), x$9) /*<<camlinternalOO.ml:492:58>>*/ ;} /*<<camlinternalOO.ml:492:2>>*/ ;
31669+
(caml_get_dyn_method(x$9, m$2), x$9) /*<<camlinternalOO.ml:492:58>>*/ ;} /*<<camlinternalOO.ml:492:2>>*/ ;
3167031670
case 21:
3167131671
var
3167231672
m$3 = /*<<camlinternalOO.ml:589:14>>*/ next(0),
3167331673
n$16 = /*<<camlinternalOO.ml:589:32>>*/ next(0);
3167431674
/*<<camlinternalOO.ml:589:56>>*/ new_cache(table);
3167531675
/*<<camlinternalOO.ml:494:2>>*/ return function(obj){
3167631676
var _g_ = /*<<camlinternalOO.ml:495:4>>*/ obj[n$16 + 1];
31677-
return caml_call1(caml_get_public_method(_g_, m$3, 0), _g_) /*<<camlinternalOO.ml:496:32>>*/ ;} /*<<camlinternalOO.ml:494:2>>*/ ;
31677+
return caml_call1(caml_get_dyn_method(_g_, m$3), _g_) /*<<camlinternalOO.ml:496:32>>*/ ;} /*<<camlinternalOO.ml:494:2>>*/ ;
3167831678
case 22:
3167931679
var
3168031680
m$4 = /*<<camlinternalOO.ml:591:14>>*/ next(0),
@@ -31683,7 +31683,7 @@
3168331683
/*<<camlinternalOO.ml:592:21>>*/ new_cache(table);
3168431684
/*<<camlinternalOO.ml:498:2>>*/ return function(obj){
3168531685
var _g_ = /*<<camlinternalOO.ml:499:4>>*/ obj[e$4 + 1][n$17 + 1];
31686-
return caml_call1(caml_get_public_method(_g_, m$4, 0), _g_) /*<<camlinternalOO.ml:502:34>>*/ ;} /*<<camlinternalOO.ml:498:2>>*/ ;
31686+
return caml_call1(caml_get_dyn_method(_g_, m$4), _g_) /*<<camlinternalOO.ml:502:34>>*/ ;} /*<<camlinternalOO.ml:498:2>>*/ ;
3168731687
default:
3168831688
var
3168931689
m$5 = /*<<camlinternalOO.ml:594:14>>*/ next(0),
@@ -31695,7 +31695,7 @@
3169531695
/*<<camlinternalOO.ml:505:14>>*/ caml_call1
3169631696
(obj[1][n$18 + 1], obj);
3169731697
/*<<camlinternalOO.ml:505:30>>*/ return caml_call1
31698-
(caml_get_public_method(_g_, m$5, 0), _g_) /*<<camlinternalOO.ml:505:59>>*/ ;} /*<<camlinternalOO.ml:504:2>>*/ ;
31698+
(caml_get_dyn_method(_g_, m$5), _g_) /*<<camlinternalOO.ml:505:59>>*/ ;} /*<<camlinternalOO.ml:504:2>>*/ ;
3169931699
}
3170031700
/*<<camlinternalOO.ml:595:24>>*/ return clo;
3170131701
/*<<camlinternalOO.ml:595:37>>*/ }

runtime/js/obj.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,19 +142,42 @@ function caml_lazy_make_forward(v) {
142142
return [250, v];
143143
}
144144

145+
//Provides: caml_method_cache
146+
var caml_method_cache = [];
147+
148+
//Provides: caml_oo_cache_id const
149+
//Requires: caml_method_cache
150+
function caml_oo_cache_id() {
151+
var cacheid = caml_method_cache.length;
152+
caml_method_cache[cacheid] = 0;
153+
cacheid;
154+
}
155+
145156
///////////// CamlinternalOO
146157
//Provides: caml_get_public_method const
147-
var caml_method_cache = [];
158+
//Requires: caml_method_cache
148159
function caml_get_public_method(obj, tag, cacheid) {
149160
var meths = obj[1];
150161
var ofs = caml_method_cache[cacheid];
151-
if (ofs === undefined) {
152-
// Make sure the array is not sparse
153-
for (var i = caml_method_cache.length; i < cacheid; i++)
154-
caml_method_cache[i] = 0;
155-
} else if (meths[ofs] === tag) {
156-
return meths[ofs - 1];
162+
if (meths[ofs + 4] === tag) {
163+
return meths[ofs + 3];
164+
}
165+
var li = 3,
166+
hi = meths[1] * 2 + 1,
167+
mi;
168+
while (li < hi) {
169+
mi = ((li + hi) >> 1) | 1;
170+
if (tag < meths[mi + 1]) hi = mi - 2;
171+
else li = mi;
157172
}
173+
caml_method_cache[cacheid] = li - 3;
174+
/* return 0 if tag is not there */
175+
return tag === meths[li + 1] ? meths[li] : 0;
176+
}
177+
178+
//Provides: caml_get_dyn_method const
179+
function caml_get_dyn_method(obj, tag) {
180+
var meths = obj[1];
158181
var li = 3,
159182
hi = meths[1] * 2 + 1,
160183
mi;
@@ -163,7 +186,6 @@ function caml_get_public_method(obj, tag, cacheid) {
163186
if (tag < meths[mi + 1]) hi = mi - 2;
164187
else li = mi;
165188
}
166-
caml_method_cache[cacheid] = li + 1;
167189
/* return 0 if tag is not there */
168190
return tag === meths[li + 1] ? meths[li] : 0;
169191
}

runtime/wasm/obj.wat

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -381,18 +381,15 @@
381381
(global $method_cache (mut (ref $int_array))
382382
(array.new $int_array (i32.const 4) (i32.const 8)))
383383

384-
(func (export "caml_get_public_method")
385-
(param $obj (ref eq)) (param $vtag (ref eq)) (param (ref eq))
386-
(result (ref eq))
387-
(local $meths (ref $block))
388-
(local $tag i32) (local $cacheid i32) (local $ofs i32)
389-
(local $li i32) (local $mi i32) (local $hi i32)
390-
(local $a (ref $int_array)) (local $len i32)
391-
(local.set $meths
392-
(ref.cast (ref $block)
393-
(array.get $block
394-
(ref.cast (ref $block) (local.get $obj)) (i32.const 1))))
395-
(local.set $cacheid (i31.get_u (ref.cast (ref i31) (local.get 2))))
384+
385+
(global $caml_oo_cache_id_last (mut i32) (i32.const 0))
386+
387+
(func (export "caml_oo_cache_id") (result (ref eq))
388+
(local $cacheid i32)
389+
(local $a (ref $int_array))
390+
(local $len i32)
391+
(local.set $cacheid (global.get $caml_oo_cache_id_last))
392+
(global.set $caml_oo_cache_id_last (i32.add (local.get $cacheid) (i32.const 1)))
396393
(local.set $len (array.len (global.get $method_cache)))
397394
(if (i32.ge_s (local.get $cacheid) (local.get $len))
398395
(then
@@ -405,6 +402,19 @@
405402
(global.get $method_cache) (i32.const 0)
406403
(array.len (global.get $method_cache)))
407404
(global.set $method_cache (local.get $a))))
405+
(ref.i31 (local.get $cacheid)))
406+
407+
(func (export "caml_get_public_method")
408+
(param $obj (ref eq)) (param $vtag (ref eq)) (param (ref eq))
409+
(result (ref eq))
410+
(local $meths (ref $block))
411+
(local $tag i32) (local $cacheid i32) (local $ofs i32)
412+
(local $li i32) (local $mi i32) (local $hi i32)
413+
(local.set $meths
414+
(ref.cast (ref $block)
415+
(array.get $block
416+
(ref.cast (ref $block) (local.get $obj)) (i32.const 1))))
417+
(local.set $cacheid (i31.get_u (ref.cast (ref i31) (local.get 2))))
408418
(local.set $ofs
409419
(array.get $int_array (global.get $method_cache) (local.get $cacheid)))
410420
(if (i32.lt_u (local.get $ofs) (array.len (local.get $meths)))
@@ -456,6 +466,54 @@
456466
(else
457467
(ref.i31 (i32.const 0)))))
458468

469+
(func (export "caml_get_dyn_method")
470+
(param $obj (ref eq)) (param $vtag (ref eq))
471+
(result (ref eq))
472+
(local $meths (ref $block))
473+
(local $tag i32) (local $ofs i32)
474+
(local $li i32) (local $mi i32) (local $hi i32)
475+
(local.set $meths
476+
(ref.cast (ref $block)
477+
(array.get $block
478+
(ref.cast (ref $block) (local.get $obj)) (i32.const 1))))
479+
(local.set $tag (i31.get_s (ref.cast (ref i31) (local.get $vtag))))
480+
(local.set $li (i32.const 3))
481+
(local.set $hi
482+
(i32.add
483+
(i32.shl
484+
(i31.get_u
485+
(ref.cast (ref i31)
486+
(array.get $block (local.get $meths) (i32.const 1))))
487+
(i32.const 1))
488+
(i32.const 1)))
489+
(loop $loop
490+
(if (i32.lt_u (local.get $li) (local.get $hi))
491+
(then
492+
(local.set $mi
493+
(i32.or (i32.shr_u (i32.add (local.get $li) (local.get $hi))
494+
(i32.const 1))
495+
(i32.const 1)))
496+
(if (i32.lt_s
497+
(local.get $tag)
498+
(i31.get_s
499+
(ref.cast (ref i31)
500+
(array.get $block
501+
(local.get $meths)
502+
(i32.add (local.get $mi) (i32.const 1))))))
503+
(then
504+
(local.set $hi (i32.sub (local.get $mi) (i32.const 2))))
505+
(else
506+
(local.set $li (local.get $mi))))
507+
(br $loop))))
508+
(if (result (ref eq))
509+
(ref.eq (local.get $vtag)
510+
(array.get $block (local.get $meths)
511+
(i32.add (local.get $li) (i32.const 1))))
512+
(then
513+
(array.get $block (local.get $meths) (local.get $li)))
514+
(else
515+
(ref.i31 (i32.const 0)))))
516+
459517
(global $caml_oo_last_id (mut i32) (i32.const 0))
460518

461519
(func (export "caml_set_oo_id") (param (ref eq)) (result (ref eq))

0 commit comments

Comments
 (0)