diff --git a/CHANGES.md b/CHANGES.md index 555075a235..ec5a514e24 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ * Compiler: speedup emitting js files (#1174) * Compiler: simplify (a | 0) >>> 0 into (a >>> 0) (#1177) * Compiler: improve static evaluation of cond (#1178) +* Compiler: be more consistent dealing with js vs ocaml strings (#984) * Lib: add messageEvent to Dom_html (#1164) * Lib: add PerformanceObserver API (#1164) * Lib: add CSSStyleDeclaration.{setProperty, getPropertyValue, getPropertyPriority, removeProperty} (#1170) diff --git a/compiler/bin-js_of_ocaml/build_fs.ml b/compiler/bin-js_of_ocaml/build_fs.ml index 663506ec94..453541e8af 100644 --- a/compiler/bin-js_of_ocaml/build_fs.ml +++ b/compiler/bin-js_of_ocaml/build_fs.ml @@ -49,10 +49,10 @@ let options = let f { files; output_file; include_dirs } = let code = {| -//Provides: caml_create_file_extern -function caml_create_file_extern(name,content){ - if(joo_global_object.caml_create_file) - joo_global_object.caml_create_file(name,content); +//Provides: jsoo_create_file_extern +function jsoo_create_file_extern(name,content){ + if(joo_global_object.jsoo_create_file) + joo_global_object.jsoo_create_file(name,content); else { if(!joo_global_object.caml_fs_tmp) joo_global_object.caml_fs_tmp = []; joo_global_object.caml_fs_tmp.push({name:name,content:content}); @@ -64,11 +64,7 @@ function caml_create_file_extern(name,content){ let fragments = Linker.parse_string code in Linker.load_fragments ~target_env:Isomorphic ~filename:"" fragments; let instr = - Pseudo_fs.f - ~prim:`caml_create_file_extern - ~cmis:StringSet.empty - ~files - ~paths:include_dirs + Pseudo_fs.f ~prim:`create_file_extern ~cmis:StringSet.empty ~files ~paths:include_dirs in let code = Code.prepend Code.empty instr in Filename.gen_file output_file (fun chan -> diff --git a/compiler/bin-js_of_ocaml/compile.ml b/compiler/bin-js_of_ocaml/compile.ml index a15d840c95..a60ad02bcf 100644 --- a/compiler/bin-js_of_ocaml/compile.ml +++ b/compiler/bin-js_of_ocaml/compile.ml @@ -137,10 +137,15 @@ let run Pseudo_fs.f ~prim ~cmis ~files:fs_files ~paths in let env_instr () = - List.map static_env ~f:(fun (k, v) -> + List.concat_map static_env ~f:(fun (k, v) -> Primitive.add_external "caml_set_static_env"; - let args = [ Code.Pc (IString k); Code.Pc (IString v) ] in - Code.(Let (Var.fresh (), Prim (Extern "caml_set_static_env", args)))) + let var_k = Code.Var.fresh () in + let var_v = Code.Var.fresh () in + Code. + [ Let (var_k, Prim (Extern "caml_jsstring_of_string", [ Pc (String k) ])) + ; Let (var_v, Prim (Extern "caml_jsstring_of_string", [ Pc (String v) ])) + ; Let (Var.fresh (), Prim (Extern "caml_set_static_env", [ Pv var_k; Pv var_v ])) + ]) in let output (one : Parse_bytecode.one) ~standalone output_file = check_debug one; @@ -149,7 +154,7 @@ let run | `Stdout -> let instr = List.concat - [ pseudo_fs_instr `caml_create_file one.debug one.cmis + [ pseudo_fs_instr `create_file one.debug one.cmis ; (if init_pseudo_fs then [ Pseudo_fs.init () ] else []) ; env_instr () ] @@ -170,8 +175,8 @@ let run | `Name file -> let fs_instr1, fs_instr2 = match fs_output with - | None -> pseudo_fs_instr `caml_create_file one.debug one.cmis, [] - | Some _ -> [], pseudo_fs_instr `caml_create_file_extern one.debug one.cmis + | None -> pseudo_fs_instr `create_file one.debug one.cmis, [] + | Some _ -> [], pseudo_fs_instr `create_file_extern one.debug one.cmis in Filename.gen_file file (fun chan -> let instr = diff --git a/compiler/bin-jsoo_fs/jsoo_fs.ml b/compiler/bin-jsoo_fs/jsoo_fs.ml index cf7c8911d2..1ca803e6fe 100644 --- a/compiler/bin-jsoo_fs/jsoo_fs.ml +++ b/compiler/bin-jsoo_fs/jsoo_fs.ml @@ -76,8 +76,8 @@ let info = let f { files; output_file; include_dirs } = let code = {| -//Provides: caml_create_file_extern -function caml_create_file_extern(name,content){ +//Provides: jsoo_create_file_extern +function jsoo_create_file_extern(name,content){ if(joo_global_object.caml_create_file) joo_global_object.caml_create_file(name,content); else { @@ -91,11 +91,7 @@ function caml_create_file_extern(name,content){ let fragments = Linker.parse_string code in Linker.load_fragments ~target_env:Isomorphic ~filename:"" fragments; let instr = - Pseudo_fs.f - ~prim:`caml_create_file_extern - ~cmis:StringSet.empty - ~files - ~paths:include_dirs + Pseudo_fs.f ~prim:`create_file_extern ~cmis:StringSet.empty ~files ~paths:include_dirs in let code = Code.prepend Code.empty instr in Filename.gen_file output_file (fun chan -> diff --git a/compiler/lib/code.ml b/compiler/lib/code.ml index 5fc151ead2..6d31ddfac0 100644 --- a/compiler/lib/code.ml +++ b/compiler/lib/code.ml @@ -259,7 +259,7 @@ type array_or_not = type constant = | String of string - | IString of string + | NativeString of string | Float of float | Float_array of float array | Int64 of int64 @@ -269,7 +269,7 @@ type constant = let rec constant_equal a b = match a, b with | String a, String b -> Some (String.equal a b) - | IString a, IString b -> Some (String.equal a b) + | NativeString a, NativeString b -> Some (String.equal a b) | Tuple (ta, a, _), Tuple (tb, b, _) -> if ta <> tb || Array.length a <> Array.length b then Some false @@ -286,21 +286,21 @@ let rec constant_equal a b = | Float_array a, Float_array b -> Some (Array.equal Float.equal a b) | Int a, Int b -> Some (Int32.equal a b) | Float a, Float b -> Some (Float.equal a b) - | String _, IString _ | IString _, String _ -> None + | String _, NativeString _ | NativeString _, String _ -> None | Int _, Float _ | Float _, Int _ -> None | Tuple ((0 | 254), _, _), Float_array _ -> None | Float_array _, Tuple ((0 | 254), _, _) -> None - | Tuple _, (String _ | IString _ | Int64 _ | Int _ | Float _ | Float_array _) -> + | Tuple _, (String _ | NativeString _ | Int64 _ | Int _ | Float _ | Float_array _) -> Some false - | Float_array _, (String _ | IString _ | Int64 _ | Int _ | Float _ | Tuple _) -> + | Float_array _, (String _ | NativeString _ | Int64 _ | Int _ | Float _ | Tuple _) -> Some false | String _, (Int64 _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false - | IString _, (Int64 _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false - | Int64 _, (String _ | IString _ | Int _ | Float _ | Tuple _ | Float_array _) -> + | NativeString _, (Int64 _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false + | Int64 _, (String _ | NativeString _ | Int _ | Float _ | Tuple _ | Float_array _) -> Some false - | Float _, (String _ | IString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) -> + | Float _, (String _ | NativeString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) -> Some false - | Int _, (String _ | IString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) -> + | Int _, (String _ | NativeString _ | Float_array _ | Int64 _ | Tuple (_, _, _)) -> Some false type prim_arg = @@ -360,7 +360,7 @@ module Print = struct let rec constant f x = match x with | String s -> Format.fprintf f "%S" s - | IString s -> Format.fprintf f "%S" s + | NativeString s -> Format.fprintf f "%Sj" s | Float fl -> Format.fprintf f "%.12g" fl | Float_array a -> Format.fprintf f "[|"; diff --git a/compiler/lib/code.mli b/compiler/lib/code.mli index aee5f91385..779f59cd8f 100644 --- a/compiler/lib/code.mli +++ b/compiler/lib/code.mli @@ -142,7 +142,7 @@ type array_or_not = type constant = | String of string - | IString of string + | NativeString of string | Float of float | Float_array of float array | Int64 of int64 diff --git a/compiler/lib/eval.ml b/compiler/lib/eval.ml index 5bd421eb0c..427aa0d390 100644 --- a/compiler/lib/eval.ml +++ b/compiler/lib/eval.ml @@ -129,8 +129,7 @@ let eval_prim x = | "caml_sin_float", _ -> float_unop l sin | "caml_sqrt_float", _ -> float_unop l sqrt | "caml_tan_float", _ -> float_unop l tan - | ( ("caml_string_get" | "caml_string_unsafe_get") - , [ (String s | IString s); Int pos ] ) -> + | ("caml_string_get" | "caml_string_unsafe_get"), [ String s; Int pos ] -> let pos = Int.to_int pos in if Config.Flag.safe_string () && pos >= 0 && pos < String.length s then Some (Int (Int.of_int (Char.code s.[pos]))) @@ -153,8 +152,7 @@ let the_length_of info x = info (fun x -> match info.info_defs.(Var.idx x) with - | Expr (Constant (String s)) | Expr (Constant (IString s)) -> - Some (Int32.of_int (String.length s)) + | Expr (Constant (String s)) -> Some (Int32.of_int (String.length s)) | Expr (Prim (Extern "caml_create_string", [ arg ])) | Expr (Prim (Extern "caml_create_bytes", [ arg ])) -> the_int info arg @@ -207,7 +205,7 @@ let eval_instr info i = | Let (x, Prim (Extern "caml_ml_string_length", [ s ])) -> ( let c = match s with - | Pc (String s) | Pc (IString s) -> Some (Int32.of_int (String.length s)) + | Pc (String s) -> Some (Int32.of_int (String.length s)) | Pv v -> the_length_of info v | _ -> None in @@ -261,7 +259,7 @@ let eval_instr info i = ( prim , List.map2 prim_args prim_args' ~f:(fun arg c -> match c with - | Some ((Int _ | Float _ | IString _) as c) -> Pc c + | Some ((Int _ | Float _ | NativeString _) as c) -> Pc c | Some (String _ as c) when Config.Flag.use_js_string () -> Pc c | Some _ (* do not be duplicated other constant as @@ -312,8 +310,8 @@ let the_cond_of info x = | Expr (Constant (Int 0l)) -> Zero | Expr (Constant - (Int _ | Float _ | Tuple _ | String _ | IString _ | Float_array _ | Int64 _)) - -> + ( Int _ | Float _ | Tuple _ | String _ | NativeString _ | Float_array _ + | Int64 _ )) -> Non_zero | Expr (Block (_, _, _)) -> Non_zero | Expr (Field _ | Closure _ | Prim _ | Apply _) -> Unknown diff --git a/compiler/lib/flow.ml b/compiler/lib/flow.ml index 0373aec6e0..fb97458356 100644 --- a/compiler/lib/flow.ml +++ b/compiler/lib/flow.ml @@ -306,7 +306,7 @@ let the_def_of info x = info (fun x -> match info.info_defs.(Var.idx x) with - | Expr (Constant (Float _ | Int _ | IString _) as e) -> Some e + | Expr (Constant (Float _ | Int _ | NativeString _) as e) -> Some e | Expr (Constant (String _) as e) when Config.Flag.safe_string () -> Some e | Expr e -> if info.info_possibly_mutable.(Var.idx x) then None else Some e | _ -> None) @@ -322,7 +322,7 @@ let the_const_of info x = info (fun x -> match info.info_defs.(Var.idx x) with - | Expr (Constant ((Float _ | Int _ | IString _) as c)) -> Some c + | Expr (Constant ((Float _ | Int _ | NativeString _) as c)) -> Some c | Expr (Constant (String _ as c)) when Config.Flag.safe_string () -> Some c | Expr (Constant c) -> if info.info_possibly_mutable.(Var.idx x) then None else Some c @@ -342,7 +342,12 @@ let the_int info x = let the_string_of info x = match the_const_of info x with - | Some (String i | IString i) -> Some i + | Some (String i) -> Some i + | _ -> None + +let the_native_string_of info x = + match the_const_of info x with + | Some (NativeString i) -> Some i | _ -> None (*XXX Maybe we could iterate? *) diff --git a/compiler/lib/flow.mli b/compiler/lib/flow.mli index dcf027dbed..1aa435f311 100644 --- a/compiler/lib/flow.mli +++ b/compiler/lib/flow.mli @@ -58,6 +58,8 @@ val the_const_of : info -> Code.prim_arg -> Code.constant option val the_string_of : info -> Code.prim_arg -> string option +val the_native_string_of : info -> Code.prim_arg -> string option + val the_int : info -> Code.prim_arg -> int32 option val update_def : info -> Code.Var.t -> Code.expr -> unit diff --git a/compiler/lib/generate.ml b/compiler/lib/generate.ml index d05537881f..71b9d00db9 100644 --- a/compiler/lib/generate.ml +++ b/compiler/lib/generate.ml @@ -111,12 +111,12 @@ module Share = struct then share else add_prim "caml_string_of_jsbytes" share - let add_code_istring s share = add_string s share + let add_code_native_string s share = add_string s share let rec get_constant c t = match c with | String s -> add_code_string s t - | IString s -> add_code_istring s t + | NativeString s -> add_code_native_string s t | Tuple (_, args, _) -> Array.fold_left args ~init:t ~f:(fun t c -> get_constant c t) | _ -> t @@ -139,7 +139,7 @@ module Share = struct match i with | Let (_, Constant c) -> get_constant c share | Let (_, Apply (_, args, false)) -> add_apply (List.length args) share - | Let (_, Prim (Extern "%closure", [ Pc (IString name | String name) ])) -> + | Let (_, Prim (Extern "%closure", [ Pc (NativeString name) ])) -> let name = Primitive.resolve name in let share = if Primitive.exists name then add_prim name share else share @@ -332,7 +332,7 @@ let rec constant_rec ~ctx x level instrs = let e = Share.get_string str_js s ctx.Ctx.share in let e = ocaml_string ~ctx ~loc:J.N e in e, instrs - | IString s -> Share.get_string str_js s ctx.Ctx.share, instrs + | NativeString s -> Share.get_string str_js s ctx.Ctx.share, instrs | Float f -> float_const f, instrs | Float_array a -> ( Mlvalue.Array.make @@ -1048,9 +1048,8 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = let (px, cx), queue = access_queue' ~ctx queue x in let (py, cy), queue = access_queue' ~ctx queue y in Mlvalue.Array.field cx cy, or_p mutable_p (or_p px py), queue - | Extern "caml_js_var", [ Pc (String nm | IString nm) ] - | Extern ("caml_js_expr" | "caml_pure_js_expr"), [ Pc (String nm | IString nm) ] - -> ( + | Extern "caml_js_var", [ Pc (String nm) ] + | Extern ("caml_js_expr" | "caml_pure_js_expr"), [ Pc (String nm) ] -> ( try let lexbuf = Lexing.from_string nm in let lexbuf = @@ -1095,9 +1094,10 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = ~init:([], const_p, queue) in J.EArr (List.map args ~f:(fun x -> Some x)), prop, queue - | Extern "%closure", [ Pc (IString name | String name) ] -> + | Extern "%closure", [ Pc (NativeString name) ] -> let prim = Share.get_prim (runtime_fun ctx) name ctx.Ctx.share in prim, const_p, queue + | Extern "%closure", _ -> assert false | Extern "%caml_js_opt_call", f :: o :: l -> let (pf, cf), queue = access_queue' ~ctx queue f in let (po, co), queue = access_queue' ~ctx queue o in @@ -1121,7 +1121,7 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = ~init:([], mutator_p, queue) in ecall cf args loc, or_p pf prop, queue - | Extern "%caml_js_opt_meth_call", o :: Pc (String m | IString m) :: l -> + | Extern "%caml_js_opt_meth_call", o :: Pc (NativeString m) :: l -> let (po, co), queue = access_queue' ~ctx queue o in let args, prop, queue = List.fold_right @@ -1132,6 +1132,7 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = ~init:([], mutator_p, queue) in ecall (J.EDot (co, m)) args loc, or_p po prop, queue + | Extern "%caml_js_opt_meth_call", _ :: Pc (String _) :: _ -> assert false | Extern "%caml_js_opt_new", c :: l -> let (pc, cc), queue = access_queue' ~ctx queue c in let args, prop, queue = @@ -1145,27 +1146,32 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = ( J.ENew (cc, if List.is_empty args then None else Some args) , or_p pc prop , queue ) - | Extern "caml_js_get", [ Pv o; Pc (String f | IString f) ] when J.is_ident f -> + | Extern "caml_js_get", [ Pv o; Pc (NativeString f) ] when J.is_ident f -> let (po, co), queue = access_queue queue o in J.EDot (co, f), or_p po mutable_p, queue - | Extern "caml_js_set", [ Pv o; Pc (String f | IString f); v ] when J.is_ident f - -> + | Extern "caml_js_set", [ Pv o; Pc (NativeString f); v ] when J.is_ident f -> let (po, co), queue = access_queue queue o in let (pv, cv), queue = access_queue' ~ctx queue v in J.EBin (J.Eq, J.EDot (co, f), cv), or_p (or_p po pv) mutator_p, queue - | Extern "caml_js_delete", [ Pv o; Pc (String f | IString f) ] when J.is_ident f - -> + | Extern "caml_js_delete", [ Pv o; Pc (NativeString f) ] when J.is_ident f -> let (po, co), queue = access_queue queue o in J.EUn (J.Delete, J.EDot (co, f)), or_p po mutator_p, queue - | Extern "%overrideMod", [ Pc (String m | IString m); Pc (String f | IString f) ] - -> + (* + This is only useful for debugging: + {[ + | Extern "caml_js_get", [ _; Pc (String _) ] -> assert false + | Extern "caml_js_set", [ _; Pc (String s); _ ] -> assert false + | Extern "caml_js_delete", [ _; Pc (String _) ] -> assert false + ]} + *) + | Extern "%overrideMod", [ Pc (NativeString m); Pc (NativeString f) ] -> runtime_fun ctx (Printf.sprintf "caml_%s_%s" m f), const_p, queue | Extern "%overrideMod", _ -> assert false | Extern "%caml_js_opt_object", fields -> let rec build_fields queue l = match l with | [] -> const_p, [], queue - | Pc (String nm | IString nm) :: x :: r -> + | Pc (NativeString nm) :: x :: r -> let (prop, cx), queue = access_queue' ~ctx queue x in let prop', r', queue = build_fields queue r in or_p prop prop', (J.PNS nm, cx) :: r', queue diff --git a/compiler/lib/inline.ml b/compiler/lib/inline.ml index 8f95b3861d..8ebb9ae6fd 100644 --- a/compiler/lib/inline.ml +++ b/compiler/lib/inline.ml @@ -152,7 +152,7 @@ let simple blocks cont mapping = | `Ok (x, exp), Return ret when Code.Var.compare x (find_mapping mapping ret) = 0 -> ( match exp with - | Constant (Float _ | Int64 _ | Int _ | IString _) -> `Exp exp + | Constant (Float _ | Int64 _ | Int _ | NativeString _) -> `Exp exp | Apply (f, args, true) -> `Exp (Apply (map_var mapping f, List.map args ~f:(map_var mapping), true)) | Prim (prim, args) -> @@ -257,7 +257,8 @@ let inline closures live_vars outer_optimizable pc (blocks, free_pc) = && Primitive.has_arity prim len && args_equal l args then - Let (x, Prim (Extern "%closure", [ Pc (IString prim) ])) :: rem, state + ( Let (x, Prim (Extern "%closure", [ Pc (NativeString prim) ])) :: rem + , state ) else i :: rem, state | _ -> i :: rem, state) | _ -> i :: rem, state) diff --git a/compiler/lib/parse_bytecode.ml b/compiler/lib/parse_bytecode.ml index 31b919bce4..e2d6edaf2c 100644 --- a/compiler/lib/parse_bytecode.ml +++ b/compiler/lib/parse_bytecode.ml @@ -442,7 +442,7 @@ end = struct Int (Int32.of_int_warning_on_overflow i) let inlined = function - | String _ | IString _ -> false + | String _ | NativeString _ -> false | Float _ -> true | Float_array _ -> false | Int64 _ -> false @@ -712,8 +712,11 @@ let register_global ?(force = false) g i rem = match g.named_value.(i) with | None -> [] | Some name -> - Code.Var.name (access_global g i) name; - [ Pc (IString name) ] + if String.is_ascii name + then ( + Code.Var.name (access_global g i) name; + [ Pc (NativeString name) ]) + else [] in Let ( Var.fresh () @@ -2132,7 +2135,7 @@ let override_global = | `V4_13 -> [] | `V4_04 | `V4_06 | `V4_07 | `V4_08 | `V4_09 | `V4_10 | `V4_11 | `V4_12 -> let jsmodule name func = - Prim (Extern "%overrideMod", [ Pc (String name); Pc (String func) ]) + Prim (Extern "%overrideMod", [ Pc (NativeString name); Pc (NativeString func) ]) in [ ( "CamlinternalMod" , fun _orig instrs -> @@ -2332,12 +2335,14 @@ let from_exe in let body = List.fold_left infos ~init:body ~f:(fun rem (name, const) -> + assert (String.is_ascii name); need_gdata := true; let c = Var.fresh () in Let (c, Constant const) :: Let ( Var.fresh () - , Prim (Extern "caml_js_set", [ Pv gdata; Pc (String name); Pv c ]) ) + , Prim (Extern "caml_js_set", [ Pv gdata; Pc (NativeString name); Pv c ]) + ) :: rem) in if !need_gdata @@ -2528,15 +2533,24 @@ let from_compilation_units ~includes:_ ~toplevel ~debug_data l = let l = register_global globals i l in let cst = globals.constants.(i) in (match cst, Code.Var.get_name x with - | (String str | IString str), None -> - Code.Var.name x (Printf.sprintf "cst_%s" str) + | String str, None -> Code.Var.name x (Printf.sprintf "cst_%s" str) | _ -> ()); Let (x, Constant cst) :: l | Some name -> Var.name x name; need_gdata := true; - Let (x, Prim (Extern "caml_js_get", [ Pv gdata; Pc (IString name) ])) :: l - ) + if String.is_ascii name + then + Let + (x, Prim (Extern "caml_js_get", [ Pv gdata; Pc (NativeString name) ])) + :: l + else + let name_js = Var.fresh () in + Let + ( name_js + , Prim (Extern "caml_jsstring_of_string", [ Pc (String name) ]) ) + :: Let (x, Prim (Extern "caml_js_get", [ Pv gdata; Pv name_js ])) + :: l) | _ -> l) in let body = @@ -2632,12 +2646,13 @@ let predefined_exceptions () = let body = let open Code in List.map predefined_exceptions ~f:(fun (index, name) -> + assert (String.is_ascii name); let exn = Var.fresh () in let v_name = Var.fresh () in let v_name_js = Var.fresh () in let v_index = Var.fresh () in [ Let (v_name, Constant (String name)) - ; Let (v_name_js, Constant (IString name)) + ; Let (v_name_js, Constant (NativeString name)) ; Let ( v_index , Constant diff --git a/compiler/lib/pseudo_fs.ml b/compiler/lib/pseudo_fs.ml index 296dbb61a5..aafac61e73 100644 --- a/compiler/lib/pseudo_fs.ml +++ b/compiler/lib/pseudo_fs.ml @@ -85,19 +85,21 @@ let find_cmi paths base = let instr_of_name_content prim ~name ~content = let open Code in - Let (Var.fresh (), Prim (Extern prim, [ Pc (IString name); Pc (IString content) ])) + let prim = + match prim with + | `create_file -> "jsoo_create_file" + | `create_file_extern -> "jsoo_create_file_extern" + in + Let + ( Var.fresh () + , Prim (Extern prim, [ Pc (NativeString name); Pc (NativeString content) ]) ) let embed_file ~name ~filename = - instr_of_name_content "caml_create_file_extern" ~name ~content:(Fs.read_file filename) + instr_of_name_content `create_file_extern ~name ~content:(Fs.read_file filename) let init () = Code.(Let (Var.fresh (), Prim (Extern "caml_fs_init", []))) let f ~prim ~cmis ~files ~paths = - let prim = - match prim with - | `caml_create_file -> "caml_create_file" - | `caml_create_file_extern -> "caml_create_file_extern" - in let cmi_files, missing_cmis = StringSet.fold (fun s (acc, missing) -> diff --git a/compiler/lib/pseudo_fs.mli b/compiler/lib/pseudo_fs.mli index 5b095270a6..009096675d 100644 --- a/compiler/lib/pseudo_fs.mli +++ b/compiler/lib/pseudo_fs.mli @@ -20,7 +20,7 @@ open Stdlib val f : - prim:[ `caml_create_file | `caml_create_file_extern ] + prim:[ `create_file | `create_file_extern ] -> cmis:StringSet.t -> files:string list -> paths:string list diff --git a/compiler/lib/specialize.ml b/compiler/lib/specialize.ml index 928e8b56f7..424cff772e 100644 --- a/compiler/lib/specialize.ml +++ b/compiler/lib/specialize.ml @@ -27,7 +27,7 @@ let rec function_cardinality info x acc = (fun x -> match info.info_defs.(Var.idx x) with | Expr (Closure (l, _)) -> Some (List.length l) - | Expr (Prim (Extern "%closure", [ Pc (IString prim) ])) -> ( + | Expr (Prim (Extern "%closure", [ Pc (NativeString prim) ])) -> ( try Some (Primitive.arity prim) with Not_found -> None) | Expr (Apply (f, l, _)) -> ( if List.mem f ~set:acc diff --git a/compiler/lib/specialize_js.ml b/compiler/lib/specialize_js.ml index d133c7e6e1..c9dfe11f96 100644 --- a/compiler/lib/specialize_js.ml +++ b/compiler/lib/specialize_js.ml @@ -37,11 +37,13 @@ let specialize_instr info i rem = | Some i -> Let (x, Constant (String (Int32.to_string i))) | None -> i) :: rem + (* inline the String constant argument so that generate.ml can attempt to parse it *) | Let ( x , Prim - (Extern (("caml_js_var" | "caml_js_expr" | "caml_pure_js_expr") as prim), [ y ]) - ) -> + ( Extern (("caml_js_var" | "caml_js_expr" | "caml_pure_js_expr") as prim) + , [ (Pv _ as y) ] ) ) + when Config.Flag.safe_string () -> (match the_string_of info y with | Some s -> Let (x, Prim (Extern prim, [ Pc (String s) ])) | _ -> i) @@ -69,7 +71,7 @@ let specialize_instr info i rem = :: rem | Let (x, Prim (Extern "caml_js_meth_call", [ o; m; a ])) -> (match the_string_of info m with - | Some m -> ( + | Some m when String.is_ascii m -> ( match the_def_of info a with | Some (Block (_, a, _)) -> let a = Array.map a ~f:(fun x -> Pv x) in @@ -77,7 +79,7 @@ let specialize_instr info i rem = ( x , Prim ( Extern "%caml_js_opt_meth_call" - , o :: Pc (String m) :: Array.to_list a ) ) + , o :: Pc (NativeString m) :: Array.to_list a ) ) | _ -> i) | _ -> i) :: rem @@ -101,7 +103,7 @@ let specialize_instr info i rem = | Some (Block (_, [| k; v |], _)) -> let k = match the_string_of info (Pv k) with - | Some s -> Pc (String s) + | Some s when String.is_ascii s -> Pc (NativeString s) | _ -> raise Exit in [ k; Pv v ] @@ -110,24 +112,24 @@ let specialize_instr info i rem = Let (x, Prim (Extern "%caml_js_opt_object", List.flatten (Array.to_list a))) with Exit -> i) :: rem - | Let (x, Prim (Extern "caml_js_get", [ o; f ])) -> - (match the_string_of info f with - | Some s -> Let (x, Prim (Extern "caml_js_get", [ o; Pc (String s) ])) + | Let (x, Prim (Extern "caml_js_get", [ o; (Pv _ as f) ])) -> + (match the_native_string_of info f with + | Some s -> Let (x, Prim (Extern "caml_js_get", [ o; Pc (NativeString s) ])) | _ -> i) :: rem - | Let (x, Prim (Extern "caml_js_set", [ o; f; v ])) -> - (match the_string_of info f with - | Some s -> Let (x, Prim (Extern "caml_js_set", [ o; Pc (String s); v ])) + | Let (x, Prim (Extern "caml_js_set", [ o; (Pv _ as f); v ])) -> + (match the_native_string_of info f with + | Some s -> Let (x, Prim (Extern "caml_js_set", [ o; Pc (NativeString s); v ])) | _ -> i) :: rem - | Let (x, Prim (Extern "caml_js_delete", [ o; f ])) -> - (match the_string_of info f with - | Some s -> Let (x, Prim (Extern "caml_js_delete", [ o; Pc (String s) ])) + | Let (x, Prim (Extern "caml_js_delete", [ o; (Pv _ as f) ])) -> + (match the_native_string_of info f with + | Some s -> Let (x, Prim (Extern "caml_js_delete", [ o; Pc (NativeString s) ])) | _ -> i) :: rem | Let (x, Prim (Extern ("caml_jsstring_of_string" | "caml_js_from_string"), [ y ])) -> (match the_string_of info y with - | Some s when String.is_ascii s -> Let (x, Constant (IString s)) + | Some s when String.is_ascii s -> Let (x, Constant (NativeString s)) | _ -> i) :: rem | Let (x, Prim (Extern "%int_mul", [ y; z ])) -> diff --git a/compiler/tests-check-prim/output b/compiler/tests-check-prim/output index d3401cb777..7311087f00 100644 --- a/compiler/tests-check-prim/output +++ b/compiler/tests-check-prim/output @@ -60,8 +60,9 @@ caml_return_exn_constant From +fs.js: caml_ba_map_file caml_ba_map_file_bytecode -caml_create_file_extern caml_fs_init +jsoo_create_file +jsoo_create_file_extern From +gc.js: caml_memprof_set diff --git a/lib/js_of_ocaml/js.ml b/lib/js_of_ocaml/js.ml index ba7673df18..e95c2c1b3f 100644 --- a/lib/js_of_ocaml/js.ml +++ b/lib/js_of_ocaml/js.ml @@ -214,105 +214,111 @@ module Js = struct external wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback = "caml_js_wrap_meth_callback" -end -include Js + (****) -(****) + let _true = Unsafe.pure_js_expr "true" -let _true = Unsafe.pure_js_expr "true" + let _false = Unsafe.pure_js_expr "false" -let _false = Unsafe.pure_js_expr "false" + type match_result_handle -type match_result_handle + type string_array -type string_array + class type js_string = + object + method toString : js_string t meth -class type js_string = - object - method toString : js_string t meth + method valueOf : js_string t meth - method valueOf : js_string t meth + method charAt : int -> js_string t meth - method charAt : int -> js_string t meth + method charCodeAt : int -> float meth - method charCodeAt : int -> float meth + (* This may return NaN... *) + method concat : js_string t -> js_string t meth - (* This may return NaN... *) - method concat : js_string t -> js_string t meth + method concat_2 : js_string t -> js_string t -> js_string t meth - method concat_2 : js_string t -> js_string t -> js_string t meth + method concat_3 : js_string t -> js_string t -> js_string t -> js_string t meth - method concat_3 : js_string t -> js_string t -> js_string t -> js_string t meth + method concat_4 : + js_string t -> js_string t -> js_string t -> js_string t -> js_string t meth - method concat_4 : - js_string t -> js_string t -> js_string t -> js_string t -> js_string t meth + method indexOf : js_string t -> int meth - method indexOf : js_string t -> int meth + method indexOf_from : js_string t -> int -> int meth - method indexOf_from : js_string t -> int -> int meth + method lastIndexOf : js_string t -> int meth - method lastIndexOf : js_string t -> int meth + method lastIndexOf_from : js_string t -> int -> int meth - method lastIndexOf_from : js_string t -> int -> int meth + method localeCompare : js_string t -> float meth - method localeCompare : js_string t -> float meth + method _match : regExp t -> match_result_handle t opt meth - method _match : regExp t -> match_result_handle t opt meth + method replace : regExp t -> js_string t -> js_string t meth - method replace : regExp t -> js_string t -> js_string t meth + method replace_string : js_string t -> js_string t -> js_string t meth - method replace_string : js_string t -> js_string t -> js_string t meth + method search : regExp t -> int meth - method search : regExp t -> int meth + method slice : int -> int -> js_string t meth - method slice : int -> int -> js_string t meth + method slice_end : int -> js_string t meth - method slice_end : int -> js_string t meth + method split : js_string t -> string_array t meth - method split : js_string t -> string_array t meth + method split_limited : js_string t -> int -> string_array t meth - method split_limited : js_string t -> int -> string_array t meth + method split_regExp : regExp t -> string_array t meth - method split_regExp : regExp t -> string_array t meth + method split_regExpLimited : regExp t -> int -> string_array t meth - method split_regExpLimited : regExp t -> int -> string_array t meth + method substring : int -> int -> js_string t meth - method substring : int -> int -> js_string t meth + method substring_toEnd : int -> js_string t meth - method substring_toEnd : int -> js_string t meth + method toLowerCase : js_string t meth - method toLowerCase : js_string t meth + method toLocaleLowerCase : js_string t meth - method toLocaleLowerCase : js_string t meth + method toUpperCase : js_string t meth - method toUpperCase : js_string t meth + method toLocaleUpperCase : js_string t meth - method toLocaleUpperCase : js_string t meth + method trim : js_string t meth - method trim : js_string t meth + method length : int readonly_prop + end - method length : int readonly_prop - end + and regExp = + object + method exec : js_string t -> match_result_handle t opt meth -and regExp = - object - method exec : js_string t -> match_result_handle t opt meth + method test : js_string t -> bool t meth - method test : js_string t -> bool t meth + method toString : js_string t meth - method toString : js_string t meth + method source : js_string t readonly_prop - method source : js_string t readonly_prop + method global : bool t readonly_prop - method global : bool t readonly_prop + method ignoreCase : bool t readonly_prop - method ignoreCase : bool t readonly_prop + method multiline : bool t readonly_prop - method multiline : bool t readonly_prop + method lastIndex : int prop + end - method lastIndex : int prop - end + (* string is used by ppx_js, it needs to come before any use of the + new syntax in this file *) + external string : string -> js_string t = "caml_jsstring_of_string" + + external to_string : js_string t -> string = "caml_string_of_jsstring" +end + +include Js class type string_constr = object @@ -708,10 +714,6 @@ external bool : bool -> bool t = "caml_js_from_bool" external to_bool : bool t -> bool = "caml_js_to_bool" -external string : string -> js_string t = "caml_jsstring_of_string" - -external to_string : js_string t -> string = "caml_string_of_jsstring" - external array : 'a array -> 'a js_array t = "caml_js_from_array" external to_array : 'a js_array t -> 'a array = "caml_js_to_array" diff --git a/ppx/ppx_js/lib_internal/ppx_js_internal.ml b/ppx/ppx_js/lib_internal/ppx_js_internal.ml index c70be52350..98872bcd8c 100644 --- a/ppx/ppx_js/lib_internal/ppx_js_internal.ml +++ b/ppx/ppx_js/lib_internal/ppx_js_internal.ml @@ -95,7 +95,7 @@ let tuple ?loc ?attrs = function | [ x ] -> x | xs -> Exp.tuple ?loc ?attrs xs -let str ?loc ?attrs s = Exp.constant ?loc ?attrs (Const.string s) +let ocaml_str ?loc ?attrs s = Exp.constant ?loc ?attrs (Const.string s) (** Check if an expression is an identifier and returns it. Raise a Location.error if it's not. @@ -159,6 +159,8 @@ end = struct let fun_ = apply_ ~where:js_dot end +let javascript_str ?loc ?attrs s = Js.fun_ "string" ?loc [ ocaml_str ?loc ?attrs s ] + let unescape lab = if lab = "" then lab @@ -303,7 +305,7 @@ let method_call ~loc ~apply_loc obj (meth, meth_loc) args = | [] -> assert false | eobj :: eargs -> let eargs = inject_args eargs in - Js.unsafe "meth_call" [ eobj; str (unescape meth); eargs ]) + Js.unsafe "meth_call" [ eobj; ocaml_str (unescape meth); eargs ]) (Arg.make () :: List.map args ~f:(fun (label, _) -> Arg.make ~label ())) in Exp.apply @@ -347,7 +349,7 @@ let prop_get ~loc obj prop = (fun eargs -> match eargs with | [] | _ :: _ :: _ -> assert false - | [ only_arg ] -> Js.unsafe "get" [ only_arg; str (unescape prop) ]) + | [ only_arg ] -> Js.unsafe "get" [ only_arg; javascript_str (unescape prop) ]) [ Arg.make () ] in Exp.apply @@ -398,7 +400,8 @@ let prop_set ~loc ~prop_loc obj prop value = let loc = !default_loc in js_dot_t_the_first_arg args, [%type: unit]) (function - | [ obj; arg ] -> Js.unsafe "set" [ obj; str (unescape prop); inject_arg arg ] + | [ obj; arg ] -> + Js.unsafe "set" [ obj; javascript_str (unescape prop); inject_arg arg ] | _ -> assert false) [ Arg.make (); Arg.make () ] in @@ -681,7 +684,7 @@ let literal_object self_id (fields : field_desc list) = [ Exp.array (List.map2 fields args ~f:(fun f arg -> tuple - [ str (unescape (name f).txt) + [ ocaml_str (unescape (name f).txt) ; inject_arg (match f with | Val _ -> arg diff --git a/ppx/ppx_js/tests/ppx.mlt b/ppx/ppx_js/tests/ppx.mlt index 0b152f0d85..e20663af96 100644 --- a/ppx/ppx_js/tests/ppx.mlt +++ b/ppx/ppx_js/tests/ppx.mlt @@ -1,5 +1,8 @@ module Js_of_ocaml = struct module Js = struct + + class type js_string = object end + type +'a t type (-'a, +'b) meth_callback @@ -44,6 +47,8 @@ module Js_of_ocaml = struct let wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback = fun _ -> assert false + let string : string -> js_string t = fun _ -> assert false + let undefined : unit -> 'a optdef = fun () -> assert false let def : 'a -> 'a optdef = fun _ -> assert false @@ -58,6 +63,7 @@ module Js_of_ocaml : sig module Js : sig + class type js_string = object end type +'a t type (-'a, +'b) meth_callback type +'a opt @@ -81,6 +87,7 @@ module Js_of_ocaml : val obj : (string * any) array -> 'a end val wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback + val string : string -> js_string t val undefined : unit -> 'a optdef val def : 'a -> 'a optdef end diff --git a/runtime/fs.js b/runtime/fs.js index 14788573c8..2ee2a47d4d 100644 --- a/runtime/fs.js +++ b/runtime/fs.js @@ -280,10 +280,10 @@ function caml_ba_map_file_bytecode(argv,argn){ return caml_ba_map_file(argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]); } -//Provides: caml_create_file_extern -function caml_create_file_extern(name,content){ - if(joo_global_object.caml_create_file) - joo_global_object.caml_create_file(name,content); +//Provides: jsoo_create_file_extern +function jsoo_create_file_extern(name,content){ + if(joo_global_object.jsoo_create_file) + joo_global_object.jsoo_create_file(name,content); else { if(!joo_global_object.caml_fs_tmp) joo_global_object.caml_fs_tmp = []; joo_global_object.caml_fs_tmp.push({name:name,content:content}); @@ -292,30 +292,38 @@ function caml_create_file_extern(name,content){ } //Provides: caml_fs_init -//Requires: caml_create_file +//Requires: jsoo_create_file function caml_fs_init (){ var tmp=joo_global_object.caml_fs_tmp if(tmp){ for(var i = 0; i < tmp.length; i++){ - caml_create_file(tmp[i].name,tmp[i].content); + jsoo_create_file(tmp[i].name,tmp[i].content); } } - joo_global_object.caml_create_file = caml_create_file; + joo_global_object.jsoo_create_file = jsoo_create_file; joo_global_object.caml_fs_tmp = []; return 0; } //Provides: caml_create_file -//Requires: caml_failwith, resolve_fs_device, caml_string_of_jsbytes +//Requires: caml_failwith, resolve_fs_device function caml_create_file(name,content) { - var name = (typeof name == "string")?caml_string_of_jsbytes(name):name; - var content = (typeof content == "string")?caml_string_of_jsbytes(content):content; var root = resolve_fs_device(name); if(! root.device.register) caml_failwith("cannot register file"); root.device.register(root.rest,content); return 0; } + +//Provides: jsoo_create_file +//Requires: caml_create_file, caml_string_of_jsbytes +function jsoo_create_file(name,content) { + var name = caml_string_of_jsbytes(name); + var content = caml_string_of_jsbytes(content); + return caml_create_file(name, content); +} + + //Provides: caml_read_file_content //Requires: resolve_fs_device, caml_raise_no_such_file, caml_create_bytes, caml_string_of_bytes //Requires: caml_string_of_jsbytes