Skip to content

Commit e14ca86

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

File tree

4 files changed

+116
-41
lines changed

4 files changed

+116
-41
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

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)