Skip to content

Commit

Permalink
part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
hhugo committed Apr 7, 2020
1 parent 50b8f3a commit 56d6a69
Show file tree
Hide file tree
Showing 34 changed files with 1,930 additions and 1,311 deletions.
1,412 changes: 744 additions & 668 deletions compiler/lib/annot_lexer.ml

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion compiler/lib/annot_lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ rule initial = parse
| "object_literal" {TA_Object_literal}
| "Version" {TVersion}
| "Weakdef" {TWeakdef}
| ['a'-'z''A'-'Z''$''_']['a'-'z''A'-'Z''$''_''0'-'9']* {
| "If" {TIf}
| "!" {TBang}
| ['a'-'z''A'-'Z''$''_']['a'-'z''A'-'Z''$''_''-''0'-'9']* {
let x = Lexing.lexeme lexbuf in
TIdent x}
| ['0'-'9']+ ('.' (['0'-'9']+)) * {
Expand Down
949 changes: 559 additions & 390 deletions compiler/lib/annot_parser.ml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions compiler/lib/annot_parser.mli
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ type token =
| TRequires
| TProvides
| TOTHER of (string)
| TIf
| TIdent of (string)
| TComma
| TBang
| TA_Shallow
| TA_Pure
| TA_Object_literal
Expand Down
8 changes: 6 additions & 2 deletions compiler/lib/annot_parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)

%token TProvides TRequires TVersion TWeakdef
%token TProvides TRequires TVersion TWeakdef TIf
%token TA_Pure TA_Const TA_Mutable TA_Mutator TA_Shallow TA_Object_literal
%token<string> TIdent TVNum
%token TComma TSemi EOF EOL LE LT GE GT EQ LPARENT RPARENT
%token<string> TOTHER
%token TBang

%start annot
%type <Primitive.t> annot
Expand All @@ -38,7 +39,10 @@ annot:
| TVersion TSemi l=separated_nonempty_list(TComma,version) endline
{ `Version (None,l) }
| TWeakdef { `Weakdef None }

| TIf TSemi name=TIdent endline
{ `If (None,name) }
| TIf TSemi TBang name=TIdent endline
{ `Ifnot (None,name) }
prim_annot:
| TA_Pure {`Pure}
| TA_Const {`Pure}
Expand Down
2 changes: 1 addition & 1 deletion compiler/lib/config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ module Flag = struct

let safe_string = o ~name:"safestring" ~default:true

let use_js_string = o ~name:"use-js-string" ~default:true
let use_js_string = o ~name:"use-js-string" ~default:false

let check_magic = o ~name:"check-magic-number" ~default:true

Expand Down
46 changes: 22 additions & 24 deletions compiler/lib/generate.ml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ module Share = struct

let add_code_string s share =
let share = add_string s share in
if Config.Flag.use_js_string () then share else add_prim "caml_new_string" share
if Config.Flag.use_js_string ()
then share
else add_prim "caml_string_of_jsbytes" share

let add_code_istring s share = add_string s share

Expand All @@ -124,11 +126,12 @@ module Share = struct
| Pc c -> get_constant c t
| _ -> t)

let get
?(alias_strings = false)
?(alias_prims = false)
?(alias_apply = true)
{ blocks; _ } : t =
let get ?alias_strings ?(alias_prims = false) ?(alias_apply = true) { blocks; _ } : t =
let alias_strings =
match alias_strings with
| None -> Config.Flag.use_js_string ()
| Some x -> x
in
let count =
Addr.Map.fold
(fun _ block share ->
Expand Down Expand Up @@ -176,7 +179,7 @@ module Share = struct
then (
try J.EVar (StringMap.find s t.vars.strings)
with Not_found ->
let x = Var.fresh_n "str" in
let x = Var.fresh_n (Printf.sprintf "cst_%s" s) in
let v = J.V x in
t.vars <- { t.vars with strings = StringMap.add s v t.vars.strings };
J.EVar v)
Expand Down Expand Up @@ -309,17 +312,18 @@ let kind k =
| `Mutable -> mutable_p
| `Mutator -> mutator_p

let ocaml_string ~ctx ~loc s =
if Config.Flag.use_js_string ()
then s
else
let p = Share.get_prim (runtime_fun ctx) "caml_string_of_jsbytes" ctx.Ctx.share in
ecall p [ s ] loc

let rec constant_rec ~ctx x level instrs =
match x with
| String s ->
let e = Share.get_string str_js s ctx.Ctx.share in
let e =
if Config.Flag.use_js_string ()
then e
else
let p = Share.get_prim (runtime_fun ctx) "caml_new_string" ctx.Ctx.share in
ecall p [ e ] J.N
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
| Float f -> float_const f, instrs
Expand Down Expand Up @@ -860,11 +864,7 @@ let register_bin_math_prim name prim =
let _ =
register_un_prim_ctx "%caml_format_int_special" `Pure (fun ctx cx loc ->
let s = J.EBin (J.Plus, str_js "", cx) in
if Config.Flag.use_js_string ()
then s
else
let p = Share.get_prim (runtime_fun ctx) "caml_new_string" ctx.Ctx.share in
ecall p [ s ] loc);
ocaml_string ~ctx ~loc s);
register_bin_prim "caml_array_unsafe_get" `Mutable (fun cx cy _ ->
Mlvalue.Array.field cx cy);
register_bin_prim "%int_add" `Pure (fun cx cy _ -> to_int (plus_int cx cy));
Expand Down Expand Up @@ -919,11 +919,6 @@ let _ =
J.EUn (J.Not, J.EUn (J.Not, cx)));
register_un_prim "caml_js_to_bool" `Pure (fun cx _ -> to_int cx);

(* register_un_prim "caml_js_from_string" `Mutable (fun cx loc ->
if Config.Flag.use_js_string ()
then cx
else
J.ECall (J.EDot (cx, "toString"), [], loc)); *)
register_tern_prim "caml_js_set" (fun cx cy cz _ ->
J.EBin (J.Eq, J.EAccess (cx, cy), cz));
register_bin_prim "caml_js_get" `Mutable (fun cx cy _ -> J.EAccess (cx, cy));
Expand All @@ -935,7 +930,10 @@ let _ =
bool (J.EBin (J.InstanceOf, cx, cy)));
register_un_prim "caml_js_typeof" `Pure (fun cx _ -> J.EUn (J.Typeof, cx))

(* This is not correct when switching the js-string flag *)
(* {[
register_un_prim "caml_jsstring_of_string" `Mutable (fun cx loc ->
J.ECall (J.EDot (cx, "toString"), [], loc));
register_bin_prim "caml_string_notequal" `Pure (fun cx cy _ ->
J.EBin (J.NotEqEq, cx, cy));
register_bin_prim "caml_string_equal" `Pure (fun cx cy _ ->
Expand Down
115 changes: 74 additions & 41 deletions compiler/lib/linker.ml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type fragment =
; version_constraint : ((int -> int -> bool) * string) list list
; weakdef : bool
; code : Javascript.program
; ignore : [ `No | `Because of Primitive.condition ]
}

let loc pi =
Expand All @@ -45,6 +46,8 @@ let parse_annot loc s =
| `Provides (_, n, k, ka) -> Some (`Provides (Some loc, n, k, ka))
| `Version (_, l) -> Some (`Version (Some loc, l))
| `Weakdef _ -> Some (`Weakdef (Some loc))
| `If (_, name) -> Some (`If (Some loc, name))
| `Ifnot (_, name) -> Some (`Ifnot (Some loc, name))
with
| Not_found -> None
| _ -> None
Expand Down Expand Up @@ -105,6 +108,7 @@ let parse_from_lex ~filename lex =
; version_constraint = []
; weakdef = false
; code
; ignore = `No
}
in
List.fold_left annot ~init:fragment ~f:(fun fragment a ->
Expand All @@ -114,7 +118,31 @@ let parse_from_lex ~filename lex =
| `Requires (_, mn) -> { fragment with requires = mn @ fragment.requires }
| `Version (_, l) ->
{ fragment with version_constraint = l :: fragment.version_constraint }
| `Weakdef _ -> { fragment with weakdef = true })
| `Weakdef _ -> { fragment with weakdef = true }
| `If (_, "js-string") as reason ->
if not (Config.Flag.use_js_string ())
then { fragment with ignore = `Because reason }
else fragment
| `Ifnot (_, "js-string") as reason ->
if Config.Flag.use_js_string ()
then { fragment with ignore = `Because reason }
else fragment
| `If (pi, name) | `Ifnot (pi, name) ->
let loc =
match pi with
| None -> ""
| Some loc ->
Format.sprintf "%d:%d" loc.Parse_info.line loc.Parse_info.col
in
let filename =
match pi with
| Some { Parse_info.src = Some x; _ }
| Some { Parse_info.name = Some x; _ } ->
x
| _ -> "??"
in
Format.eprintf "Unkown flag %S in %s %s\n" name filename loc;
fragment)
with Parse_js.Parsing_error pi ->
let name =
match pi with
Expand Down Expand Up @@ -288,46 +316,51 @@ let find_named_value code =
ignore (p#program code);
!all

let load_fragment ~filename { provides; requires; version_constraint; weakdef; code } =
let vmatch =
match version_constraint with
| [] -> true
| l -> List.exists l ~f:version_match
in
if vmatch
then (
incr last_code_id;
let id = !last_code_id in
match provides with
| None -> always_included := { filename; program = code } :: !always_included
| Some (pi, name, kind, ka) ->
let code = Macro.f code in
let module J = Javascript in
let rec find = function
| [] -> None
| (J.Function_declaration (J.S { J.name = n; _ }, l, _, _), _) :: _
when String.equal name n ->
Some (List.length l)
| _ :: rem -> find rem
in
let arity = find code in
let named_values = find_named_value code in
Primitive.register name kind ka arity;
StringSet.iter Primitive.register_named_value named_values;
(if Hashtbl.mem provided name
then
let _, ploc, weakdef = Hashtbl.find provided name in
if not weakdef
then
warn
"warning: overriding primitive %S\n old: %s\n new: %s@."
name
(loc ploc)
(loc pi));
Hashtbl.add provided name (id, pi, weakdef);
Hashtbl.add provided_rev id (name, pi);
check_primitive ~name pi ~code ~requires;
Hashtbl.add code_pieces id (code, requires))
let load_fragment
~filename
{ provides; requires; version_constraint; weakdef; code; ignore } =
match ignore with
| `Because _ -> ()
| `No ->
let vmatch =
match version_constraint with
| [] -> true
| l -> List.exists l ~f:version_match
in
if vmatch
then (
incr last_code_id;
let id = !last_code_id in
match provides with
| None -> always_included := { filename; program = code } :: !always_included
| Some (pi, name, kind, ka) ->
let code = Macro.f code in
let module J = Javascript in
let rec find = function
| [] -> None
| (J.Function_declaration (J.S { J.name = n; _ }, l, _, _), _) :: _
when String.equal name n ->
Some (List.length l)
| _ :: rem -> find rem
in
let arity = find code in
let named_values = find_named_value code in
Primitive.register name kind ka arity;
StringSet.iter Primitive.register_named_value named_values;
(if Hashtbl.mem provided name
then
let _, ploc, weakdef = Hashtbl.find provided name in
if not weakdef
then
warn
"warning: overriding primitive %S\n old: %s\n new: %s@."
name
(loc ploc)
(loc pi));
Hashtbl.add provided name (id, pi, weakdef);
Hashtbl.add provided_rev id (name, pi);
check_primitive ~name pi ~code ~requires;
Hashtbl.add code_pieces id (code, requires))

let add_file filename = List.iter (parse_file filename) ~f:(load_fragment ~filename)

Expand Down
1 change: 1 addition & 0 deletions compiler/lib/linker.mli
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type fragment =
; version_constraint : ((int -> int -> bool) * string) list list
; weakdef : bool
; code : Javascript.program
; ignore : [ `No | `Because of Primitive.condition ]
}

val parse_file : string -> fragment list
Expand Down
6 changes: 5 additions & 1 deletion compiler/lib/parse_bytecode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2518,7 +2518,11 @@ let predefined_exceptions () =
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
, if Config.Flag.use_js_string ()
then Constant (IString name)
else Prim (Extern "caml_jsstring_of_string", [ Pc (IString name) ]) )
; Let (v_index, Constant (Int (Int32.of_int (-index))))
; Let (exn, Block (248, [| v_name; v_index |], NotArray))
; Let
Expand Down
6 changes: 6 additions & 0 deletions compiler/lib/primitive.ml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ type kind_arg =
| `Mutable
]

type condition =
[ `If of Parse_info.t option * string
| `Ifnot of Parse_info.t option * string
]

type t =
[ `Requires of Parse_info.t option * string list
| `Provides of Parse_info.t option * string * kind * kind_arg list option
| `Version of Parse_info.t option * ((int -> int -> bool) * string) list
| `Weakdef of Parse_info.t option
| condition
]

let kinds = Hashtbl.create 37
Expand Down
6 changes: 6 additions & 0 deletions compiler/lib/primitive.mli
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,17 @@ type kind_arg =
| `Mutable
]

type condition =
[ `If of Parse_info.t option * string
| `Ifnot of Parse_info.t option * string
]

type t =
[ `Requires of Parse_info.t option * string list
| `Provides of Parse_info.t option * string * kind * kind_arg list option
| `Version of Parse_info.t option * ((int -> int -> bool) * string) list
| `Weakdef of Parse_info.t option
| condition
]

val kind : string -> kind
Expand Down
2 changes: 1 addition & 1 deletion compiler/lib/specialize_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ let specialize_instr info i rem =
| Some s -> Let (x, Prim (Extern "caml_js_delete", [ o; Pc (String s) ]))
| _ -> i)
:: rem
| Let (x, Prim (Extern "caml_js_from_string", [ y ])) ->
| 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))
| _ -> i)
Expand Down
5 changes: 5 additions & 0 deletions compiler/lib/var_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ let name t v nm_orig =
| "", _ -> "symbol"
| str, _ -> str
in
(* protect against large names *)
let max_len = 20 in
let str =
if String.length str > max_len then String.sub str ~pos:0 ~len:max_len else str
in
name_raw t v str)

let get_name t v = try Some (Hashtbl.find t.names v) with Not_found -> None
Expand Down
Loading

0 comments on commit 56d6a69

Please sign in to comment.