Skip to content

Commit 0454ee7

Browse files
authored
Add some new locally-allocating primitives (#57)
- Polymorphic comparison operators now accept local values - Local bytes can be created - bytes and Bigstring boxed integer accessors can return locally allocated values - Local arrays can be created and manipulated New primitives are not currently exposed in the stdlib.
1 parent 8acdda1 commit 0454ee7

File tree

12 files changed

+216
-37
lines changed

12 files changed

+216
-37
lines changed

runtime/alloc.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,20 @@ CAMLexport value caml_alloc_string (mlsize_t len)
9494
return result;
9595
}
9696

97+
/* [len] is a number of bytes (chars) */
98+
CAMLexport value caml_alloc_local_string (mlsize_t len)
99+
{
100+
mlsize_t offset_index;
101+
mlsize_t wosize = (len + sizeof (value)) / sizeof (value);
102+
value result;
103+
104+
result = caml_alloc_local(wosize, String_tag);
105+
Field (result, wosize - 1) = 0;
106+
offset_index = Bsize_wsize (wosize) - 1;
107+
Byte (result, offset_index) = offset_index - len;
108+
return result;
109+
}
110+
97111
/* [len] is a number of bytes (chars) */
98112
CAMLexport value caml_alloc_initialized_string (mlsize_t len, const char *p)
99113
{

runtime/array.c

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ CAMLprim value caml_floatarray_create(value len)
282282
return caml_process_pending_actions_with_root (result);
283283
}
284284

285+
CAMLprim value caml_floatarray_create_local(value len)
286+
{
287+
mlsize_t wosize = Long_val(len) * Double_wosize;
288+
return caml_alloc_local (wosize, Double_array_tag);
289+
}
290+
285291
/* [len] is a [value] representing number of words or floats */
286292
static value make_vect_gen(value len, value init, int local)
287293
{
@@ -447,8 +453,9 @@ CAMLprim value caml_array_blit(value a1, value ofs1, value a2, value ofs2,
447453
}
448454
#endif
449455
CAMLassert (Tag_val(a2) != Double_array_tag);
450-
if (Is_young(a2)) {
451-
/* Arrays of values, destination is in young generation.
456+
if (Is_young(a2) ||
457+
Color_hd(Hd_val(a2)) == Local_unmarked) {
458+
/* Arrays of values, destination is local or in young generation.
452459
Here too we can do a direct copy since this cannot create
453460
old-to-young pointers, nor mess up with the incremental major GC.
454461
Again, memmove takes care of overlap. */
@@ -487,7 +494,8 @@ CAMLprim value caml_array_blit(value a1, value ofs1, value a2, value ofs2,
487494
static value caml_array_gather(intnat num_arrays,
488495
value arrays[/*num_arrays*/],
489496
intnat offsets[/*num_arrays*/],
490-
intnat lengths[/*num_arrays*/])
497+
intnat lengths[/*num_arrays*/],
498+
int local)
491499
{
492500
CAMLparamN(arrays, num_arrays);
493501
value res; /* no need to register it as a root */
@@ -516,7 +524,9 @@ static value caml_array_gather(intnat num_arrays,
516524
/* This is an array of floats. We can use memcpy directly. */
517525
if (size > Max_wosize/Double_wosize) caml_invalid_argument("Array.concat");
518526
wsize = size * Double_wosize;
519-
res = caml_alloc(wsize, Double_array_tag);
527+
res = local ?
528+
caml_alloc_local(wsize, Double_array_tag) :
529+
caml_alloc(wsize, Double_array_tag);
520530
for (i = 0, pos = 0; i < num_arrays; i++) {
521531
memcpy((double *)res + pos,
522532
(double *)arrays[i] + offsets[i],
@@ -526,21 +536,22 @@ static value caml_array_gather(intnat num_arrays,
526536
CAMLassert(pos == size);
527537
}
528538
#endif
529-
else if (size <= Max_young_wosize) {
530-
/* Array of values, small enough to fit in young generation.
539+
else if (size > Max_wosize) {
540+
/* Array of values, too big. */
541+
caml_invalid_argument("Array.concat");
542+
} else if (size <= Max_young_wosize || local) {
543+
/* Array of values, local or small enough to fit in young generation.
531544
We can use memcpy directly. */
532-
res = caml_alloc_small(size, 0);
545+
res = local ?
546+
caml_alloc_local(size, 0) :
547+
caml_alloc_small(size, 0);
533548
for (i = 0, pos = 0; i < num_arrays; i++) {
534549
memcpy(&Field(res, pos),
535550
&Field(arrays[i], offsets[i]),
536551
lengths[i] * sizeof(value));
537552
pos += lengths[i];
538553
}
539554
CAMLassert(pos == size);
540-
}
541-
else if (size > Max_wosize) {
542-
/* Array of values, too big. */
543-
caml_invalid_argument("Array.concat");
544555
} else {
545556
/* Array of values, must be allocated in old generation and filled
546557
using caml_initialize. */
@@ -567,18 +578,34 @@ CAMLprim value caml_array_sub(value a, value ofs, value len)
567578
value arrays[1] = { a };
568579
intnat offsets[1] = { Long_val(ofs) };
569580
intnat lengths[1] = { Long_val(len) };
570-
return caml_array_gather(1, arrays, offsets, lengths);
581+
return caml_array_gather(1, arrays, offsets, lengths, 0);
582+
}
583+
584+
CAMLprim value caml_array_sub_local(value a, value ofs, value len)
585+
{
586+
value arrays[1] = { a };
587+
intnat offsets[1] = { Long_val(ofs) };
588+
intnat lengths[1] = { Long_val(len) };
589+
return caml_array_gather(1, arrays, offsets, lengths, 1);
571590
}
572591

573592
CAMLprim value caml_array_append(value a1, value a2)
574593
{
575594
value arrays[2] = { a1, a2 };
576595
intnat offsets[2] = { 0, 0 };
577596
intnat lengths[2] = { caml_array_length(a1), caml_array_length(a2) };
578-
return caml_array_gather(2, arrays, offsets, lengths);
597+
return caml_array_gather(2, arrays, offsets, lengths, 0);
579598
}
580599

581-
CAMLprim value caml_array_concat(value al)
600+
CAMLprim value caml_array_append_local(value a1, value a2)
601+
{
602+
value arrays[2] = { a1, a2 };
603+
intnat offsets[2] = { 0, 0 };
604+
intnat lengths[2] = { caml_array_length(a1), caml_array_length(a2) };
605+
return caml_array_gather(2, arrays, offsets, lengths, 1);
606+
}
607+
608+
static value array_concat_gen(value al, int local)
582609
{
583610
#define STATIC_SIZE 16
584611
value static_arrays[STATIC_SIZE], * arrays;
@@ -615,7 +642,7 @@ CAMLprim value caml_array_concat(value al)
615642
lengths[i] = caml_array_length(Field(l, 0));
616643
}
617644
/* Do the concatenation */
618-
res = caml_array_gather(n, arrays, offsets, lengths);
645+
res = caml_array_gather(n, arrays, offsets, lengths, local);
619646
/* Free the extra storage if needed */
620647
if (n > STATIC_SIZE) {
621648
caml_stat_free(arrays);
@@ -625,6 +652,16 @@ CAMLprim value caml_array_concat(value al)
625652
return res;
626653
}
627654

655+
CAMLprim value caml_array_concat(value al)
656+
{
657+
return array_concat_gen(al, 0);
658+
}
659+
660+
CAMLprim value caml_array_concat_local(value al)
661+
{
662+
return array_concat_gen(al, 1);
663+
}
664+
628665
CAMLprim value caml_array_fill(value array,
629666
value v_ofs,
630667
value v_len,
@@ -647,7 +684,8 @@ CAMLprim value caml_array_fill(value array,
647684
}
648685
#endif
649686
fp = &Field(array, ofs);
650-
if (Is_young(array)) {
687+
if (Is_young(array) ||
688+
Color_hd(Hd_val(array)) == Local_unmarked) {
651689
for (; len > 0; len--, fp++) *fp = val;
652690
} else {
653691
int is_val_young_block = Is_block(val) && Is_young(val);

runtime/caml/address_class.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
#define Is_in_heap_or_young(a) (Classify_addr(a) & (In_heap | In_young))
8383

8484
#define Is_in_value_area(a) \
85-
(Classify_addr(a) & (In_heap | In_young | In_static_data))
85+
(Classify_addr(a) & (In_heap | In_young | In_static_data | In_local))
8686

8787
#define Is_in_static_data(a) (Classify_addr(a) & In_static_data)
8888

@@ -95,6 +95,7 @@
9595
#define In_heap 1
9696
#define In_young 2
9797
#define In_static_data 4
98+
#define In_local 8
9899

99100
#ifdef ARCH_SIXTYFOUR
100101

runtime/caml/alloc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ CAMLextern value caml_alloc_tuple (mlsize_t wosize);
3636
CAMLextern value caml_alloc_float_array (mlsize_t len);
3737
CAMLextern value caml_alloc_string (mlsize_t len); /* len in bytes (chars) */
3838
CAMLextern value caml_alloc_initialized_string (mlsize_t len, const char *);
39+
CAMLextern value caml_alloc_local_string (mlsize_t len);
3940
CAMLextern value caml_copy_string (char const *);
4041
CAMLextern value caml_copy_string_array (char const **);
4142
CAMLextern value caml_copy_double (double);

runtime/caml/gc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
struct caml_local_arena {
7878
char* base;
7979
uintnat length;
80+
void* alloc_block;
8081
};
8182
typedef struct caml_local_arenas {
8283
int count;

runtime/memory.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ void caml_local_realloc()
728728
caml_local_arenas* s = caml_get_local_arenas();
729729
intnat i;
730730
char* arena;
731+
caml_stat_block block;
731732
if (s == NULL) {
732733
s = caml_stat_alloc(sizeof(*s));
733734
s->count = 0;
@@ -748,9 +749,10 @@ void caml_local_realloc()
748749
/* may need to loop, if a very large allocation was requested */
749750
} while (s->saved_sp + s->next_length < 0);
750751

751-
arena = caml_stat_alloc_noexc(s->next_length);
752+
arena = caml_stat_alloc_aligned_noexc(s->next_length, 0, &block);
752753
if (arena == NULL)
753754
caml_fatal_error("Local allocation stack overflow - out of memory");
755+
caml_page_table_add(In_local, arena, arena + s->next_length);
754756
#ifdef DEBUG
755757
for (i = 0; i < s->next_length; i += sizeof(value)) {
756758
*((header_t*)(arena + i)) = Debug_uninit_local;
@@ -765,6 +767,7 @@ void caml_local_realloc()
765767
s->count++;
766768
s->arenas[s->count-1].length = s->next_length;
767769
s->arenas[s->count-1].base = arena;
770+
s->arenas[s->count-1].alloc_block = block;
768771
caml_set_local_arenas(s);
769772
CAMLassert(Caml_state->local_limit <= Caml_state->local_sp);
770773
}

runtime/str.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ CAMLprim value caml_create_bytes(value len)
7878
return caml_alloc_string(size);
7979
}
8080

81+
CAMLprim value caml_create_local_bytes(value len)
82+
{
83+
mlsize_t size = Long_val(len);
84+
if (size > Bsize_wsize (Max_wosize) - 1){
85+
caml_invalid_argument("Bytes.create");
86+
}
87+
return caml_alloc_local_string(size);
88+
}
8189

8290

8391
CAMLprim value caml_string_get(value str, value index)

stdlib/stdlib.ml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ external __POS_OF__ : 'a -> (string * int * int * int) * 'a = "%loc_POS"
6363

6464
(* Comparisons *)
6565

66-
external ( = ) : 'a -> 'a -> bool = "%equal"
67-
external ( <> ) : 'a -> 'a -> bool = "%notequal"
68-
external ( < ) : 'a -> 'a -> bool = "%lessthan"
69-
external ( > ) : 'a -> 'a -> bool = "%greaterthan"
70-
external ( <= ) : 'a -> 'a -> bool = "%lessequal"
71-
external ( >= ) : 'a -> 'a -> bool = "%greaterequal"
72-
external compare : 'a -> 'a -> int = "%compare"
66+
external ( = ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%equal"
67+
external ( <> ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%notequal"
68+
external ( < ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%lessthan"
69+
external ( > ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%greaterthan"
70+
external ( <= ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%lessequal"
71+
external ( >= ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%greaterequal"
72+
external compare : ('a[@local_opt]) -> ('a[@local_opt]) -> int = "%compare"
7373

7474
let min x y = if x <= y then x else y
7575
let max x y = if x >= y then x else y

stdlib/stdlib.mli

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ exception Undefined_recursive_module of (string * int * int)
118118

119119
(** {1 Comparisons} *)
120120

121-
external ( = ) : 'a -> 'a -> bool = "%equal"
121+
external ( = ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%equal"
122122
(** [e1 = e2] tests for structural equality of [e1] and [e2].
123123
Mutable structures (e.g. references and arrays) are equal
124124
if and only if their current contents are structurally equal,
@@ -127,27 +127,27 @@ external ( = ) : 'a -> 'a -> bool = "%equal"
127127
Equality between cyclic data structures may not terminate.
128128
Left-associative operator, see {!Ocaml_operators} for more information. *)
129129

130-
external ( <> ) : 'a -> 'a -> bool = "%notequal"
130+
external ( <> ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%notequal"
131131
(** Negation of {!Stdlib.( = )}.
132132
Left-associative operator, see {!Ocaml_operators} for more information.
133133
*)
134134

135-
external ( < ) : 'a -> 'a -> bool = "%lessthan"
135+
external ( < ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%lessthan"
136136
(** See {!Stdlib.( >= )}.
137137
Left-associative operator, see {!Ocaml_operators} for more information.
138138
*)
139139

140-
external ( > ) : 'a -> 'a -> bool = "%greaterthan"
140+
external ( > ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%greaterthan"
141141
(** See {!Stdlib.( >= )}.
142142
Left-associative operator, see {!Ocaml_operators} for more information.
143143
*)
144144

145-
external ( <= ) : 'a -> 'a -> bool = "%lessequal"
145+
external ( <= ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%lessequal"
146146
(** See {!Stdlib.( >= )}.
147147
Left-associative operator, see {!Ocaml_operators} for more information.
148148
*)
149149

150-
external ( >= ) : 'a -> 'a -> bool = "%greaterequal"
150+
external ( >= ) : ('a[@local_opt]) -> ('a[@local_opt]) -> bool = "%greaterequal"
151151
(** Structural ordering functions. These functions coincide with
152152
the usual orderings over integers, characters, strings, byte sequences
153153
and floating-point numbers, and extend them to a
@@ -159,7 +159,7 @@ external ( >= ) : 'a -> 'a -> bool = "%greaterequal"
159159
Left-associative operator, see {!Ocaml_operators} for more information.
160160
*)
161161

162-
external compare : 'a -> 'a -> int = "%compare"
162+
external compare : ('a[@local_opt]) -> ('a[@local_opt]) -> int = "%compare"
163163
(** [compare x y] returns [0] if [x] is equal to [y],
164164
a negative integer if [x] is less than [y], and a positive integer
165165
if [x] is greater than [y]. The ordering implemented by [compare]

0 commit comments

Comments
 (0)