Skip to content

Commit f94baea

Browse files
committed
OxCaml: null support
1 parent 28d7029 commit f94baea

File tree

21 files changed

+399
-36
lines changed

21 files changed

+399
-36
lines changed

compiler/lib-wasm/gc_target.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,11 @@ module Constant = struct
10601060
| NativeInt i ->
10611061
let* e = Memory.make_int32 ~kind:`Nativeint (return (W.Const (I32 i))) in
10621062
return (Const, e)
1063+
| Null_ ->
1064+
let* var =
1065+
register_import ~name:"null" (Global { mut = false; typ = Type.value })
1066+
in
1067+
return (Const, W.GlobalGet var)
10631068

10641069
let translate ~unboxed c =
10651070
match c with

compiler/lib-wasm/generate.ml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ module Generate (Target : Target_sig.S) = struct
235235
(if negate then Value.phys_neq else Value.phys_eq)
236236
(transl_prim_arg ctx ~typ:Top x)
237237
(transl_prim_arg ctx ~typ:Top y)
238-
| (Int _ | Number _ | Tuple _ | Bigarray _), _
239-
| _, (Int _ | Number _ | Tuple _ | Bigarray _) ->
238+
| (Int _ | Number _ | Tuple _ | Bigarray _ | Null), _
239+
| _, (Int _ | Number _ | Tuple _ | Bigarray _ | Null) ->
240240
(* Only Top may contain JavaScript values *)
241241
(if negate then Value.phys_neq else Value.phys_eq)
242242
(transl_prim_arg ctx ~typ:Top x)
@@ -1132,7 +1132,13 @@ module Generate (Target : Target_sig.S) = struct
11321132
let* indices' = transl_prim_arg ctx indices in
11331133
let* v' = transl_prim_arg ctx v in
11341134
return (W.Call (f, [ ta'; indices'; v' ])))
1135-
| _ -> invalid_arity "caml_ba_set_generic" l ~expected:3)
1135+
| _ -> invalid_arity "caml_ba_set_generic" l ~expected:3);
1136+
register_un_prim "caml_is_null" `Pure ~ret_typ:int_n (fun x ->
1137+
let* x = x in
1138+
let* null =
1139+
register_import ~name:"null" (Global { mut = false; typ = Type.value })
1140+
in
1141+
return (W.RefEq (x, GlobalGet null)))
11361142

11371143
let unboxed_type ty : W.value_type option =
11381144
match ty with

compiler/lib-wasm/typing.ml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ type typ =
129129
overapproximation of the possible values of each of its
130130
fields is given by the array of types *)
131131
| Bigarray of Bigarray.t
132+
| Null
132133
| Bot
133134

134135
module Domain = struct
@@ -156,11 +157,12 @@ module Domain = struct
156157
else
157158
Array.init (max l l') ~f:(fun i ->
158159
if i < l then if i < l' then join t.(i) t'.(i) else t.(i) else t'.(i)))
159-
| Int _, Tuple _ -> t'
160-
| Tuple _, Int _ -> t
160+
| (Int _ | Null), Tuple _ -> t'
161+
| Tuple _, (Int _ | Null) -> t
161162
| Bigarray b, Bigarray b' when Bigarray.equal b b' -> t
163+
| Null, Null -> Null
162164
| Top, _ | _, Top -> Top
163-
| (Int _ | Number _ | Tuple _ | Bigarray _), _ -> Top
165+
| (Int _ | Number _ | Tuple _ | Bigarray _ | Null), _ -> Top
164166

165167
let join_set ?(others = false) f s =
166168
if others then Top else Var.Set.fold (fun x a -> join (f x) a) s Bot
@@ -173,20 +175,21 @@ module Domain = struct
173175
| Tuple t, Tuple t' ->
174176
Array.length t = Array.length t' && Array.for_all2 ~f:equal t t'
175177
| Bigarray b, Bigarray b' -> Bigarray.equal b b'
176-
| (Top | Tuple _ | Int _ | Number _ | Bigarray _ | Bot), _ -> false
178+
| Null, Null -> true
179+
| (Top | Tuple _ | Int _ | Number _ | Bigarray _ | Null | Bot), _ -> false
177180

178181
let bot = Bot
179182

180183
let depth_treshold = 4
181184

182185
let rec depth t =
183186
match t with
184-
| Top | Bot | Number _ | Int _ | Bigarray _ -> 0
187+
| Top | Bot | Number _ | Int _ | Bigarray _ | Null -> 0
185188
| Tuple l -> 1 + Array.fold_left ~f:(fun acc t' -> max (depth t') acc) l ~init:0
186189

187190
let rec truncate depth t =
188191
match t with
189-
| Top | Bot | Number _ | Int _ | Bigarray _ -> t
192+
| Top | Bot | Number _ | Int _ | Bigarray _ | Null -> t
190193
| Tuple l ->
191194
if depth = 0
192195
then Top
@@ -225,6 +228,7 @@ module Domain = struct
225228
| Boxed -> "boxed"
226229
| Unboxed -> "unboxed")
227230
| Bigarray b -> Bigarray.print f b
231+
| Null -> Format.fprintf f "null"
228232
| Tuple t ->
229233
Format.fprintf
230234
f
@@ -290,6 +294,7 @@ let rec constant_type (c : constant) =
290294
| NativeInt _ -> Number (Nativeint, Unboxed)
291295
| Float _ -> Number (Float, Unboxed)
292296
| Tuple (_, a, _) -> Tuple (Array.map ~f:(fun c' -> Domain.box (constant_type c')) a)
297+
| Null_ -> Null
293298
| _ -> Top
294299

295300
let arg_type ~approx arg =
@@ -540,7 +545,7 @@ let box_numbers p st types =
540545
Var.Set.iter box s)
541546
| Expr _ -> ()
542547
| Phi { known; _ } -> Var.Set.iter box known)
543-
| Number (_, Boxed) | Int _ | Tuple _ | Bigarray _ | Bot -> ())
548+
| Number (_, Boxed) | Int _ | Tuple _ | Bigarray _ | Null | Bot -> ())
544549
in
545550
Code.fold_closures
546551
p

compiler/lib-wasm/typing.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type typ =
4747
| Number of boxed_number * boxed_status
4848
| Tuple of typ array
4949
| Bigarray of Bigarray.t
50+
| Null
5051
| Bot
5152

5253
val constant_type : Code.constant -> typ

compiler/lib/code.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ type constant =
328328
| Int64 of Int64.t
329329
| NativeInt of Int32.t (* Native int are 32bit on all known backend *)
330330
| Tuple of int * constant array * array_or_not
331+
| Null_
331332

332333
module Constant = struct
333334
type t = constant
@@ -360,6 +361,7 @@ module Constant = struct
360361
b)
361362
| Float a, Float b ->
362363
Some (Float.ieee_equal (Int64.float_of_bits a) (Int64.float_of_bits b))
364+
| Null_, Null_ -> Some true
363365
| String _, NativeString _ | NativeString _, String _ -> None
364366
| Int _, Float _ | Float _, Int _ -> None
365367
| Tuple ((0 | 254), _, _), Float_array _ -> None
@@ -402,6 +404,7 @@ module Constant = struct
402404
| ( (Int _ | Int32 _ | NativeInt _)
403405
, (String _ | NativeString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) ) ->
404406
Some false
407+
| Null_, _ | _, Null_ -> Some false
405408
(* Note: the following cases should not occur when compiling to Javascript *)
406409
| Int _, (Int32 _ | NativeInt _)
407410
| Int32 _, (Int _ | NativeInt _)
@@ -521,6 +524,7 @@ module Print = struct
521524
constant f a.(i)
522525
done;
523526
Format.fprintf f ")")
527+
| Null_ -> Format.fprintf f "null"
524528

525529
let arg f a =
526530
match a with

compiler/lib/code.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ type constant =
150150
| Int64 of Int64.t
151151
| NativeInt of Int32.t (** Only produced when compiling to WebAssembly. *)
152152
| Tuple of int * constant array * array_or_not
153+
| Null_
153154

154155
module Constant : sig
155156
type t = constant

compiler/lib/eval.ml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ let constant_js_equal a b =
477477
Some (Float.ieee_equal (Int64.float_of_bits a) (Int64.float_of_bits b))
478478
| NativeString a, NativeString b -> Some (Native_string.equal a b)
479479
| String a, String b when Config.Flag.use_js_string () -> Some (String.equal a b)
480+
| Null_, Null_ -> Some true
480481
| Int _, Float _ | Float _, Int _ -> None
481482
(* All other values may be distinct objects and thus different by [caml_js_equals]. *)
482483
| String _, _
@@ -492,7 +493,9 @@ let constant_js_equal a b =
492493
| NativeInt _, _
493494
| _, NativeInt _
494495
| Tuple _, _
495-
| _, Tuple _ -> None
496+
| _, Tuple _
497+
| Null_, _
498+
| _, Null_ -> None
496499

497500
(* [eval_prim] does not distinguish the two constants *)
498501
let constant_equal a b =
@@ -504,10 +507,11 @@ let constant_equal a b =
504507
| Int32 a, Int32 b -> Int32.equal a b
505508
| NativeInt a, NativeInt b -> Int32.equal a b
506509
| Int64 a, Int64 b -> Int64.equal a b
510+
| Null_, Null_ -> true
507511
(* We don't need to compare other constants, so let's just return false. *)
508512
| Tuple _, Tuple _ -> false
509513
| Float_array _, Float_array _ -> false
510-
| (Int _ | Float _ | Int64 _ | Int32 _ | NativeInt _), _ -> false
514+
| (Int _ | Float _ | Int64 _ | Int32 _ | NativeInt _ | Null_), _ -> false
511515
| (String _ | NativeString _), _ -> false
512516
| (Float_array _ | Tuple _), _ -> false
513517

@@ -712,6 +716,7 @@ let the_cond_of info x =
712716
(fun x ->
713717
match Flow.Info.def info x with
714718
| Some (Constant (Int x)) -> if Targetint.is_zero x then Zero else Non_zero
719+
| Some (Constant Null_) -> Zero
715720
| Some
716721
(Constant
717722
( Int32 _

compiler/lib/generate.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ let rec constant_rec ~ctx x level instrs =
536536
Mlvalue.Block.make ~tag ~args:l, instrs)
537537
| Int i -> targetint i, instrs
538538
| Int32 i | NativeInt i -> targetint (Targetint.of_int32_exn i), instrs
539+
| Null_ -> s_var "null", instrs
539540

540541
let constant ~ctx x level =
541542
let expr, instr = constant_rec ~ctx x level [] in
@@ -1392,7 +1393,8 @@ let _ =
13921393
bool (J.EBin (J.EqEqEq, cx, cy)));
13931394
register_bin_prim "caml_js_instanceof" `Mutator (fun cx cy _ ->
13941395
bool (J.EBin (J.InstanceOf, cx, cy)));
1395-
register_un_prim "caml_js_typeof" `Mutator (fun cx _ -> J.EUn (J.Typeof, cx))
1396+
register_un_prim "caml_js_typeof" `Mutator (fun cx _ -> J.EUn (J.Typeof, cx));
1397+
register_un_prim "caml_is_null" `Pure (fun cx _ -> J.EBin (EqEqEq, cx, s_var "null"))
13961398

13971399
(****)
13981400
(* when raising ocaml exception and [improved_stacktrace] is enabled,

compiler/lib/ocaml_compiler.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ let rec constant_of_const c : Code.constant =
5959
Tuple (tag, l, Unknown)
6060
| ((Const_base (Const_float32 _ | Const_unboxed_float32 _)) [@if oxcaml]) ->
6161
failwith "Float32 unsupported"
62-
| (Const_null [@if oxcaml]) -> failwith "Null unsupported"
62+
| (Const_null [@if oxcaml]) -> Null_
6363

6464
type module_or_not =
6565
| Module

compiler/lib/parse_bytecode.ml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,16 @@ end = struct
479479

480480
let ident_native = ident_of_custom (Obj.repr 0n)
481481

482+
external is_null : Obj.t -> bool = "%is_null" [@@if oxcaml]
483+
484+
let is_null obj = is_null (Sys.opaque_identity obj) [@@if oxcaml]
485+
486+
let is_null _ = false [@@if not oxcaml]
487+
482488
let rec parse x =
483-
if Obj.is_block x
489+
if is_null x
490+
then Null_
491+
else if Obj.is_block x
484492
then
485493
let tag = Obj.tag x in
486494
if tag = Obj.string_tag
@@ -528,6 +536,7 @@ end = struct
528536
match target with
529537
| `JavaScript -> true
530538
| `Wasm -> false)
539+
| Null_ -> true
531540
end
532541

533542
let const32 i = Constant (Int (Targetint.of_int32_exn i))

0 commit comments

Comments
 (0)