Skip to content

Commit d5046c5

Browse files
committed
string-concat
1 parent 770ce92 commit d5046c5

File tree

5 files changed

+139
-0
lines changed

5 files changed

+139
-0
lines changed

compiler/lib/generate.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ let _ =
748748
[ "%int_mul", "caml_mul"
749749
; "%int_div", "caml_div"
750750
; "%int_mod", "caml_mod"
751+
; "%string_concat", "caml_string_concat"
751752
; "caml_int32_neg", "%int_neg"
752753
; "caml_int32_add", "%int_add"
753754
; "caml_int32_sub", "%int_sub"
@@ -1186,6 +1187,11 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list =
11861187
in
11871188
e, const_p, queue
11881189
| Extern "caml_alloc_dummy_function", _ -> assert false
1190+
| Extern "%string_concat", [ a; b ] when Config.Flag.use_js_string () ->
1191+
let (_pa, ca), queue = access_queue' ~ctx queue a in
1192+
let (_pb, cb), queue = access_queue' ~ctx queue b in
1193+
let e = J.EBin (J.Plus, ca, cb) in
1194+
e, const_p, queue
11891195
| Extern name, l -> (
11901196
let name = Primitive.resolve name in
11911197
match internal_prim name with

compiler/lib/specialize_js.ml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,37 @@ let specialize_instr info i rem =
150150
:: rem
151151
| _ -> i :: rem
152152

153+
let all_equal = function
154+
| [] -> true
155+
| x :: xs -> List.for_all xs ~f:(fun y -> Var.equal x y)
156+
153157
let rec specialize_instrs info checks l =
154158
match l with
155159
| [] -> []
160+
| Let (alen, Prim (Extern "caml_ml_string_length", [ Pv a ]))
161+
:: Let (blen, Prim (Extern "caml_ml_string_length", [ Pv b ]))
162+
:: Let (len, Prim (Extern "%int_add", [ Pv alen'; Pv blen' ]))
163+
:: Let (bytes, Prim (Extern "caml_create_bytes", [ Pv len' ]))
164+
:: Let
165+
( _
166+
, Prim
167+
( Extern "caml_blit_string"
168+
, [ Pv a'; Pc (Int 0l); Pv bytes'; Pc (Int 0l); Pv alen'' ] ) )
169+
:: Let
170+
( _
171+
, Prim
172+
( Extern "caml_blit_string"
173+
, [ Pv b'; Pc (Int 0l); Pv bytes''; Pv alen'''; Pv blen'' ] ) )
174+
:: Let (res, Prim (Extern "caml_string_of_bytes", [ Pv bytes''' ]))
175+
:: rest
176+
when all_equal [ a; a' ]
177+
&& all_equal [ b; b' ]
178+
&& all_equal [ len; len' ]
179+
&& all_equal [ alen; alen'; alen''; alen''' ]
180+
&& all_equal [ blen; blen'; blen'' ]
181+
&& all_equal [ bytes; bytes'; bytes''; bytes''' ] ->
182+
Let (res, Prim (Extern "%string_concat", [ Pv a; Pv b ]))
183+
:: specialize_instrs info checks rest
156184
| i :: r -> (
157185
(* We make bound checking explicit. Then, we can remove duplicated
158186
bound checks. Also, it appears to be more efficient to inline

compiler/lib/var_printer.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ let name t v nm_orig =
9999
match str, nm_orig with
100100
| "", ">>=" -> "symbol_bind"
101101
| "", ">>|" -> "symbol_map"
102+
| "", "^" -> "symbol_concat"
102103
| "", _ -> "symbol"
103104
| str, _ -> str
104105
in
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
(* Js_of_ocaml tests
2+
* http://www.ocsigen.org/js_of_ocaml/
3+
* Copyright (C) 2019 Ty Overby
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation; either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18+
*)
19+
20+
open Util
21+
22+
let%expect_test _ =
23+
let program =
24+
compile_and_parse
25+
~debug:false
26+
~flags:[ "--enable"; "use-js-string" ]
27+
{|
28+
external string_length : string -> int = "%string_length"
29+
external bytes_create : int -> bytes = "caml_create_bytes"
30+
external string_blit : string -> int -> bytes -> int -> int -> unit
31+
= "caml_blit_string" [@@noalloc]
32+
external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string"
33+
34+
let ( ^ ) s1 s2 =
35+
let l1 = string_length s1 and l2 = string_length s2 in
36+
let s = bytes_create (l1 + l2) in
37+
string_blit s1 0 s 0 l1;
38+
string_blit s2 0 s l1 l2;
39+
bytes_unsafe_to_string s
40+
41+
let here () =
42+
let a = "a" in
43+
let b = "b" in
44+
a ^ a ^ b ^ b
45+
46+
let (_ : string) = here ()
47+
|}
48+
in
49+
print_fun_decl program None;
50+
[%expect
51+
{|
52+
function _b_(_c_){return cst_a + (cst_a + (cst_b + cst_b))} |}]
53+
54+
let%expect_test _ =
55+
let program =
56+
compile_and_parse
57+
~debug:false
58+
~flags:[ "--disable"; "use-js-string" ]
59+
{|
60+
external string_length : string -> int = "%string_length"
61+
external bytes_create : int -> bytes = "caml_create_bytes"
62+
external string_blit : string -> int -> bytes -> int -> int -> unit
63+
= "caml_blit_string" [@@noalloc]
64+
65+
external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string"
66+
67+
let ( ^ ) s1 s2 =
68+
let l1 = string_length s1 and l2 = string_length s2 in
69+
let s = bytes_create (l1 + l2) in
70+
string_blit s1 0 s 0 l1;
71+
string_blit s2 0 s l1 l2;
72+
bytes_unsafe_to_string s
73+
74+
let here () =
75+
let a = "a" in
76+
let b = "b" in
77+
a ^ a ^ b ^ b
78+
79+
let (_ : string) = here ()
80+
|}
81+
in
82+
print_fun_decl program None;
83+
[%expect
84+
{|
85+
function _b_(_c_)
86+
{return caml_string_concat
87+
(cst_a,caml_string_concat(cst_a,caml_string_concat(cst_b,cst_b)))} |}]

runtime/mlBytes.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,14 @@ MlBytes.prototype.slice = function (){
438438
return new MlBytes(this.t,content,this.l);
439439
}
440440

441+
//Provides: caml_bytes_concat
442+
//Requires: caml_convert_string_to_bytes, MlBytes
443+
function caml_bytes_concat(s1,s2){
444+
(s1.t & 6) && caml_convert_string_to_bytes(s1);
445+
(s2.t & 6) && caml_convert_string_to_bytes(s2);
446+
return new MlBytes(s1.t,s1.c+s2.c,s1.l+s2.l)
447+
}
448+
441449
//Provides: caml_convert_string_to_bytes
442450
//Requires: caml_str_repeat, caml_subarray_to_jsbytes
443451
function caml_convert_string_to_bytes (s) {
@@ -649,6 +657,15 @@ function caml_blit_string(a,b,c,d,e) {
649657
//Provides: caml_ml_bytes_length const
650658
function caml_ml_bytes_length(s) { return s.l }
651659

660+
//Provides: caml_string_concat
661+
//If: js-string
662+
function caml_string_concat(a,b) { return a + b }
663+
664+
//Provides: caml_string_concat
665+
//Requires: caml_bytes_concat
666+
//If: !js-string
667+
function caml_string_concat(a,b) { return caml_bytes_concat(a,b) }
668+
652669
//Provides: caml_string_unsafe_get const
653670
//If: js-string
654671
function caml_string_unsafe_get (s, i) {

0 commit comments

Comments
 (0)