5
Jane Street Holding, LLC
7
email: mmottl\@janestcapital.com
8
WWW: http://www.janestcapital.com/ocaml
10
This library is free software; you can redistribute it and/or
11
modify it under the terms of the GNU Lesser General Public
12
License as published by the Free Software Foundation; either
13
version 2 of the License, or (at your option) any later version.
15
This library is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
Lesser General Public License for more details.
20
You should have received a copy of the GNU Lesser General Public
21
License along with this library; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
/* Stubs for reading basic values in the binary protocol */
27
#include "common_stubs.h"
31
static value *v_exc_Error = NULL;
32
static value *v_exc_Read_error = NULL;
34
CAMLprim value bin_prot_unsafe_read_c_init_stub(value __unused v_unit)
36
v_exc_Error = caml_named_value("Bin_prot.Unsafe_read_c.Error");
40
CAMLprim value bin_prot_read_ml_init_stub(value __unused v_unit)
42
v_exc_Read_error = caml_named_value("Bin_prot.Common.Read_error");
49
/* Constant values come from the order of variants in common.ml */
50
#define READ_ERROR_NEG_INT8 0
51
#define READ_ERROR_INT_CODE 1
52
#define READ_ERROR_INT_OVERFLOW 2
53
#define READ_ERROR_NAT0_CODE 3
54
#define READ_ERROR_NAT0_OVERFLOW 4
55
#define READ_ERROR_INT32_CODE 5
56
#define READ_ERROR_INT64_CODE 6
57
#define READ_ERROR_NATIVEINT_CODE 7
58
#define READ_ERROR_UNIT_CODE 8
59
#define READ_ERROR_BOOL_CODE 9
60
#define READ_ERROR_OPTION_CODE 10
61
#define READ_ERROR_STRING_TOO_LONG 11
62
#define READ_ERROR_VARIANT_TAG 12
63
#define READ_ERROR_ARRAY_TOO_LONG 13
65
static inline value raise_Error(int loc) Noreturn;
67
static inline value raise_Error(int loc)
69
caml_raise_with_arg(*v_exc_Error, Val_int(loc));
72
static inline void raise_Read_error(int loc, unsigned long pos) Noreturn;
74
static inline void raise_Read_error(int loc, unsigned long pos)
76
value v_exc = caml_alloc_small(3, 0);
77
Field(v_exc, 0) = *v_exc_Read_error;
78
Field(v_exc, 1) = Val_int(loc);
79
Field(v_exc, 2) = Val_long(pos);
86
#define MK_DO_READ(SIZE, TYPE) \
87
static inline __pure TYPE do_read_int##SIZE(char **sptr_ptr) \
89
return *(TYPE *) *sptr_ptr; \
92
#define MK_GEN_SAFE_READ(NAME, SIZE, TYPE, LEN, CHECK) \
93
static inline TYPE safe_read_##NAME##SIZE(char **sptr_ptr, char *eptr) \
95
char *sptr = *sptr_ptr; \
96
char *next = sptr + LEN; \
98
if (unlikely(next > eptr)) \
99
caml_raise_constant(*v_bin_prot_exc_Buffer_short); \
100
n = do_read_int##SIZE(sptr_ptr); \
106
#define MK_SAFE_READ(SIZE, TYPE, LEN, CHECK) \
107
MK_DO_READ(SIZE, TYPE) \
108
MK_GEN_SAFE_READ(int, SIZE, TYPE, LEN, CHECK)
110
#define MK_GEN_SAFE_NAT0_READ(PREF, SIZE, TYPE, LEN, CHECK) \
111
MK_GEN_SAFE_READ(PREF##nat0_, SIZE, unsigned TYPE, LEN, CHECK)
113
#define MK_SAFE_NAT0_READ(SIZE, TYPE, LEN, CHECK) \
114
MK_GEN_SAFE_NAT0_READ(, SIZE, TYPE, LEN, CHECK)
116
#define MK_ML_READER(NAME) \
117
CAMLprim value ml_read_##NAME##_stub(value v_buf, value v_pos_ref) \
119
CAMLparam2(v_buf, v_pos_ref); \
120
struct caml_ba_array *buf = Caml_ba_array_val(v_buf); \
121
char *start = buf->data; \
122
long pos = Long_val(Field(v_pos_ref, 0)); \
123
char *sptr = start + pos; \
124
char **sptr_ptr = &sptr; \
125
char *eptr = start + *buf->dim; \
127
if (unlikely(pos < 0)) caml_array_bound_error(); \
128
v_res = read_##NAME##_stub(sptr_ptr, eptr); \
129
Field(v_pos_ref, 0) = Val_long(sptr - start); \
134
/* Reading OCaml integers */
138
MK_GEN_SAFE_READ(neg_int, 8, char, 1,
139
if (unlikely(n >= 0)) {
140
*sptr_ptr = sptr - 1;
141
raise_Error(READ_ERROR_NEG_INT8);
144
MK_SAFE_READ(16, short, 2,)
146
#ifdef ARCH_SIXTYFOUR
147
MK_SAFE_READ(32, int, 4,)
150
MK_GEN_SAFE_READ(int, 32, int, 4,
151
if (unlikely(n < -0x40000000l || n > 0x3FFFFFFFl)) {
152
*sptr_ptr = sptr - 1;
153
raise_Error(READ_ERROR_INT_OVERFLOW);
155
MK_GEN_SAFE_READ(nocheck_int, 32, int, 4,)
158
#ifdef ARCH_SIXTYFOUR
159
MK_SAFE_READ(64, long, 8,
160
if (unlikely(n < -0x4000000000000000L || n > 0x3FFFFFFFFFFFFFFFL)) {
161
*sptr_ptr = sptr - 1;
162
raise_Error(READ_ERROR_INT_OVERFLOW);
164
MK_GEN_SAFE_READ(nocheck_int, 64, long, 8,)
167
static inline long read_int(char **sptr_ptr, char *eptr)
169
char *sptr = *sptr_ptr;
171
if (unlikely(sptr >= eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
173
*sptr_ptr = sptr + 1;
174
if (likely(code >= 0)) return code;
175
if (likely(code == CODE_INT16)) return safe_read_int16(sptr_ptr, eptr);
176
if (likely(code == CODE_NEG_INT8)) return safe_read_neg_int8(sptr_ptr, eptr);
177
if (likely(code == CODE_INT32)) return safe_read_int32(sptr_ptr, eptr);
178
#ifdef ARCH_SIXTYFOUR
179
if (likely(code == CODE_INT64)) return safe_read_int64(sptr_ptr, eptr);
182
raise_Error(READ_ERROR_INT_CODE);
185
CAMLprim value read_int_stub(char **sptr_ptr, char *eptr)
187
return Val_long(read_int(sptr_ptr, eptr));
191
/* Non-negative OCaml integers */
193
MK_SAFE_NAT0_READ(16, short, 2,)
195
#ifdef ARCH_SIXTYFOUR
196
MK_SAFE_NAT0_READ(32, int, 4,)
198
MK_SAFE_NAT0_READ(32, int, 4,
199
if (unlikely(n > 0x3FFFFFFFl)) {
200
*sptr_ptr = sptr - 1;
201
raise_Error(READ_ERROR_NAT0_OVERFLOW);
203
MK_GEN_SAFE_NAT0_READ(nocheck, 32, int, 4,)
206
#ifdef ARCH_SIXTYFOUR
207
MK_SAFE_NAT0_READ(64, long, 8,
208
if (unlikely(n > 0x3FFFFFFFFFFFFFFFL)) {
209
*sptr_ptr = sptr - 1;
210
raise_Error(READ_ERROR_NAT0_OVERFLOW);
212
MK_GEN_SAFE_NAT0_READ(nocheck, 64, long, 8,)
215
static inline unsigned long read_nat0(char **sptr_ptr, char *eptr)
217
char *sptr = *sptr_ptr;
219
if (unlikely(sptr >= eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
221
*sptr_ptr = sptr + 1;
222
if (likely(code >= 0)) return code;
223
if (likely(code == CODE_INT16)) return safe_read_nat0_16(sptr_ptr, eptr);
224
if (likely(code == CODE_INT32)) return safe_read_nat0_32(sptr_ptr, eptr);
225
#ifdef ARCH_SIXTYFOUR
226
if (likely(code == CODE_INT64)) return safe_read_nat0_64(sptr_ptr, eptr);
229
raise_Error(READ_ERROR_NAT0_CODE);
232
CAMLprim value read_nat0_stub(char **sptr_ptr, char *eptr)
234
return Val_long(read_nat0(sptr_ptr, eptr));
238
/* Reading 32bit integers */
240
static inline long read_int32(char **sptr_ptr, char *eptr)
242
char *sptr = *sptr_ptr;
244
if (unlikely(sptr >= eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
246
*sptr_ptr = sptr + 1;
247
if (likely(code >= 0)) return code;
248
if (likely(code == CODE_INT16)) return safe_read_int16(sptr_ptr, eptr);
249
if (likely(code == CODE_NEG_INT8)) return safe_read_neg_int8(sptr_ptr, eptr);
250
if (likely(code == CODE_INT32))
251
#ifdef ARCH_SIXTYFOUR
252
return safe_read_int32(sptr_ptr, eptr);
254
return safe_read_nocheck_int32(sptr_ptr, eptr);
257
raise_Error(READ_ERROR_INT32_CODE);
260
CAMLprim value read_int32_stub(char **sptr_ptr, char *eptr)
262
return caml_copy_int32(read_int32(sptr_ptr, eptr));
266
/* Reading 64bit integers */
268
#ifdef ARCH_INT64_TYPE
269
#include "int64_native.h"
271
#include "int64_emul.h"
274
static inline int64 read_int64(char **sptr_ptr, char *eptr)
276
char *sptr = *sptr_ptr;
278
if (unlikely(sptr >= eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
280
*sptr_ptr = sptr + 1;
281
if (likely(code >= 0))
282
#ifdef ARCH_SIXTYFOUR
284
if (likely(code == CODE_INT16)) return safe_read_int16(sptr_ptr, eptr);
285
if (likely(code == CODE_NEG_INT8)) return safe_read_neg_int8(sptr_ptr, eptr);
286
if (likely(code == CODE_INT32)) return safe_read_int32(sptr_ptr, eptr);
287
if (likely(code == CODE_INT64)) return safe_read_nocheck_int64(sptr_ptr, eptr);
289
return I64_literal(0, code);
290
if (likely(code == CODE_INT16))
291
return I64_of_int32(safe_read_int16(sptr_ptr, eptr));
292
if (likely(code == CODE_NEG_INT8))
293
return I64_literal(0xFFFFFFFF, safe_read_neg_int8(sptr_ptr, eptr));
294
if (likely(code == CODE_INT32))
295
return I64_of_int32(safe_read_nocheck_int32(sptr_ptr, eptr));
296
if (likely(code == CODE_INT64)) {
297
unsigned int l = safe_read_nocheck_int32(sptr_ptr, eptr);
298
return I64_literal(safe_read_nocheck_int32(sptr_ptr, eptr), l);
302
raise_Error(READ_ERROR_INT64_CODE);
305
CAMLprim value read_int64_stub(char **sptr_ptr, char *eptr)
307
return caml_copy_int64(read_int64(sptr_ptr, eptr));
311
/* Reading nativeints */
313
static inline long read_nativeint(char **sptr_ptr, char *eptr)
315
char *sptr = *sptr_ptr;
317
if (unlikely(sptr >= eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
319
*sptr_ptr = sptr + 1;
320
if (likely(code >= 0)) return code;
321
if (likely(code == CODE_INT16)) return safe_read_int16(sptr_ptr, eptr);
322
if (likely(code == CODE_NEG_INT8)) return safe_read_neg_int8(sptr_ptr, eptr);
323
#ifdef ARCH_SIXTYFOUR
324
if (likely(code == CODE_INT32)) return safe_read_int32(sptr_ptr, eptr);
325
if (likely(code == CODE_INT64)) return safe_read_nocheck_int64(sptr_ptr, eptr);
327
if (likely(code == CODE_INT32)) return safe_read_nocheck_int32(sptr_ptr, eptr);
330
raise_Error(READ_ERROR_NATIVEINT_CODE);
333
CAMLprim value read_nativeint_stub(char **sptr_ptr, char *eptr)
335
return caml_copy_nativeint(read_nativeint(sptr_ptr, eptr));
339
/* Reading unsigned short words */
341
CAMLprim value read_uint16_stub(char **sptr_ptr, char *eptr)
343
unsigned short res = safe_read_nat0_16(sptr_ptr, eptr);
348
/* Reading unit value */
350
CAMLprim value read_unit_stub(char **sptr_ptr, char *eptr)
352
char *sptr = *sptr_ptr;
354
if (unlikely(sptr >= eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
356
if (res == 0) { *sptr_ptr = ++sptr; return Val_unit; }
357
raise_Error(READ_ERROR_UNIT_CODE);
361
/* Reading booleans and options */
363
#define READ_ZERO_OR_ONE(NAME, CODE) \
364
CAMLprim value read_##NAME##_stub(char **sptr_ptr, char *eptr) \
366
char *sptr = *sptr_ptr; \
368
if (unlikely(sptr >= eptr)) \
369
caml_raise_constant(*v_bin_prot_exc_Buffer_short); \
371
if (res == 0) { *sptr_ptr = ++sptr; return Val_int(0); } \
372
if (res == 1) { *sptr_ptr = ++sptr; return Val_int(1); } \
376
READ_ZERO_OR_ONE(bool, READ_ERROR_BOOL_CODE)
377
READ_ZERO_OR_ONE(option_bool, READ_ERROR_OPTION_CODE)
380
/* Reading characters */
382
CAMLprim value read_char_stub(char **sptr_ptr, char *eptr)
384
char *sptr = *sptr_ptr;
386
if (unlikely(sptr >= eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
393
/* Reading strings */
395
CAMLprim value read_string_stub(char **sptr_ptr, char *eptr)
398
char *start = *sptr_ptr;
399
unsigned long len = read_nat0(sptr_ptr, eptr);
400
char *sptr = *sptr_ptr;
401
char *next = sptr + len;
402
if (unlikely(len > Bsize_wsize(Max_wosize) - 1)) {
404
raise_Error(READ_ERROR_STRING_TOO_LONG);
406
if (unlikely(next > eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
408
v_res = caml_alloc_string(len);
409
memcpy(String_val(v_res), sptr, len);
414
/* Reading floats and float arrays */
416
CAMLprim inline value read_float_stub(char **sptr_ptr, char *eptr)
418
char *sptr = *sptr_ptr;
419
char *next = sptr + sizeof(double);
420
if (unlikely(next > eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
422
return caml_copy_double(*(double *) sptr);
427
CAMLprim value read_float_array_stub(char **sptr_ptr, char *eptr)
429
char *start = *sptr_ptr;
430
unsigned long len = read_nat0(sptr_ptr, eptr);
431
unsigned long tot_size;
436
if (unlikely(len == 0)) return Atom(0);
437
wsize = len * Double_wosize;
438
if (unlikely(wsize > Max_wosize)) {
440
raise_Error(READ_ERROR_ARRAY_TOO_LONG);
443
tot_size = len * sizeof(double);
444
next = sptr + tot_size;
445
if (unlikely(next > eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
447
v_res = caml_alloc(wsize, Double_array_tag);
448
memcpy((double *) v_res, sptr, tot_size);
452
CAMLprim value ml_read_float_array_stub(value v_buf, value v_pos_ref)
454
CAMLparam2(v_buf, v_pos_ref);
455
struct caml_ba_array *buf = Caml_ba_array_val(v_buf);
456
char *start = buf->data;
457
long pos = Long_val(Field(v_pos_ref, 0));
458
char *sptr = start + pos;
459
char **sptr_ptr = &sptr;
460
char *eptr = start + *buf->dim;
463
unsigned long tot_size;
466
if (unlikely(pos < 0)) caml_array_bound_error();
467
len = read_nat0(sptr_ptr, eptr);
468
if (unlikely(len == 0)) {
469
Field(v_pos_ref, 0) = Val_long(sptr - start);
472
wsize = len * Double_wosize;
473
if (unlikely(wsize > Max_wosize))
474
raise_Read_error(READ_ERROR_ARRAY_TOO_LONG, pos);
475
tot_size = len * sizeof(double);
476
next = sptr + tot_size;
477
if (unlikely(next > eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
478
v_res = caml_alloc(wsize, Double_array_tag);
479
memcpy((double *) v_res, sptr, tot_size);
480
Field(v_pos_ref, 0) = Val_long(next - start);
485
/* Reading polymorphic variants */
487
CAMLprim value read_variant_tag_stub(char **sptr_ptr, char *eptr)
489
char *sptr = *sptr_ptr;
490
char *next = sptr + 4;
492
if (unlikely(next > eptr)) caml_raise_constant(*v_bin_prot_exc_Buffer_short);
494
if (likely(Is_long(n))) {
498
raise_Error(READ_ERROR_VARIANT_TAG);
501
CAMLprim value ml_read_variant_tag_stub(value v_buf, value v_pos_ref)
503
struct caml_ba_array *buf = Caml_ba_array_val(v_buf);
504
char *start = buf->data;
505
long pos = Long_val(Field(v_pos_ref, 0));
506
char *sptr = start + pos;
507
int next_pos = pos + 4;
509
if (unlikely(pos < 0)) caml_array_bound_error();
510
if (unlikely(next_pos > *buf->dim))
511
caml_raise_constant(*v_bin_prot_exc_Buffer_short);
513
if (likely(Is_long(n))) {
514
Field(v_pos_ref, 0) = Val_long(next_pos);
517
else raise_Read_error(READ_ERROR_VARIANT_TAG, pos);
521
/* Reading bigarrays */
523
#define MK_BA1_READER(NAME, TYPE, TFLAG) \
524
CAMLprim inline value read_##NAME##_stub(char **sptr_ptr, char *eptr) \
526
unsigned long len = read_nat0(sptr_ptr, eptr); \
527
int tot_size = len * sizeof(TYPE); \
528
char *sptr = *sptr_ptr; \
529
char *next = sptr + tot_size; \
532
if (unlikely(next > eptr)) \
533
caml_raise_constant(*v_bin_prot_exc_Buffer_short); \
537
CAML_BA_##TFLAG | CAML_BA_FORTRAN_LAYOUT, 1, NULL, &dim); \
539
if (unlikely(tot_size > 65536)) { \
540
Begin_roots1(v_res); \
541
caml_enter_blocking_section(); \
542
memcpy((TYPE *) Caml_ba_data_val(v_res), sptr, tot_size); \
543
caml_leave_blocking_section(); \
545
} else memcpy((TYPE *) Caml_ba_data_val(v_res), sptr, tot_size); \
551
MK_BA1_READER(bigstring, char, UINT8)
553
#define MK_VEC_MAT_READERS(NAME, TYPE, TFLAG) \
554
MK_BA1_READER(NAME##_vec, TYPE, TFLAG) \
556
CAMLprim inline value read_##NAME##_mat_stub(char **sptr_ptr, char *eptr) \
558
unsigned long dim1 = read_nat0(sptr_ptr, eptr); \
559
unsigned long dim2 = read_nat0(sptr_ptr, eptr); \
560
unsigned long size = dim1 * dim2; \
561
int tot_size = size * sizeof(TYPE); \
562
char *sptr = *sptr_ptr; \
563
char *next = sptr + tot_size; \
566
if (unlikely(next > eptr)) \
567
caml_raise_constant(*v_bin_prot_exc_Buffer_short); \
572
CAML_BA_##TFLAG | CAML_BA_FORTRAN_LAYOUT, 2, NULL, dims); \
574
if (unlikely(tot_size > 65536)) { \
575
Begin_roots1(v_res); \
576
caml_enter_blocking_section(); \
577
memcpy((TYPE *) Caml_ba_data_val(v_res), sptr, tot_size); \
578
caml_leave_blocking_section(); \
580
} else memcpy((TYPE *) Caml_ba_data_val(v_res), sptr, tot_size); \
584
MK_ML_READER(NAME##_mat)
586
MK_VEC_MAT_READERS(float32, float, FLOAT32)
587
MK_VEC_MAT_READERS(float64, double, FLOAT64)