summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/emu/generators.tab
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/emu/generators.tab')
-rw-r--r--erts/emulator/beam/emu/generators.tab160
1 files changed, 160 insertions, 0 deletions
diff --git a/erts/emulator/beam/emu/generators.tab b/erts/emulator/beam/emu/generators.tab
index f9988f2399..397ddb97e7 100644
--- a/erts/emulator/beam/emu/generators.tab
+++ b/erts/emulator/beam/emu/generators.tab
@@ -831,3 +831,163 @@ gen.init_yregs(N, Yregs) {
$INIT_YREGS(S, N.val);
return first;
}
+
+gen.create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) {
+ BeamOp* op;
+ int fixed_args;
+ BeamOpArg* src;
+ BeamOpArg* dst;
+ BeamOpArg* endp;
+
+ endp = Segments + N.val;
+ N.val = 5*N.val/6;
+
+ $NewBeamOp(S, op);
+ $BeamOpNameArity(op, i_bs_create_bin, 5);
+ fixed_args = op->arity;
+ $BeamOpArity(op, (N.val + fixed_args));
+
+ op->a[0] = Fail;
+ op->a[1] = Alloc;
+ op->a[2] = Live;
+ op->a[3] = Dst;
+ op->a[4] = N;
+
+ for (src = Segments, dst = op->a+fixed_args; src < endp; src += 6, dst += 5) {
+ UWord unit;
+ BeamOpArg Flags;
+ Uint flags = 0;
+ BeamOpArg Size;
+ Uint type;
+ Uint segment;
+
+ ASSERT(src[0].type = TAG_a);
+ ASSERT(src[1].type == TAG_u);
+ ASSERT(src[2].type == TAG_u);
+ segment = src[1].val;
+
+ /* Get unit. */
+ dst[1] = src[2];
+ unit = dst[1].val;
+
+ /* Translate flags. */
+ Flags = src[3]; /* Flags */
+ if (Flags.type != TAG_n) {
+ if (Flags.type == TAG_q) {
+ Eterm term = beamfile_get_literal(&S->beam, Flags.val);
+ while (is_list(term)) {
+ Eterm* consp = list_val(term);
+ Eterm elem = CAR(consp);
+ switch (elem) {
+ case am_little:
+ flags |= BSF_LITTLE;
+ break;
+ case am_native:
+ flags |= BSF_NATIVE;
+ break;
+ }
+ term = CDR(consp);
+ }
+ ASSERT(is_nil(term));
+ }
+ }
+ Flags.type = TAG_u;
+ Flags.val = flags;
+ $NativeEndian(Flags);
+ Flags.val = (segment << 3) | Flags.val;
+ dst[2] = Flags;
+
+ /* Store source. */
+ dst[3] = src[4]; /* Src */
+
+ /* Get size */
+ Size = src[5]; /* Size */
+
+ /* Translate type. */
+ switch (src[0].val) {
+ case am_append:
+ type = BSC_APPEND;
+ break;
+ case am_private_append:
+ type = BSC_PRIVATE_APPEND;
+ break;
+ case am_binary:
+ {
+ UWord bits;
+ type = BSC_BINARY;
+ if (Size.type == TAG_a && Size.val == am_all) {
+ type = BSC_BINARY_ALL;
+ } else if (Size.type == TAG_i &&
+ (Sint) Size.val >= 0 &&
+ beam_load_safe_mul(Size.val, unit, &bits) &&
+ (bits >> (sizeof(Uint)-1)*8) == 0) {
+ type = BSC_BINARY_FIXED_SIZE;
+ Size.type = TAG_u;
+ Size.val = bits;
+ unit = 0;
+ }
+ }
+ break;
+ case am_float:
+ {
+ UWord bits;
+ type = BSC_FLOAT;
+ if (Size.type == TAG_i &&
+ (Sint) Size.val >= 0 &&
+ beam_load_safe_mul(Size.val, unit, &bits) &&
+ (bits >> (sizeof(Uint)-1)*8) == 0) {
+ type = BSC_FLOAT_FIXED_SIZE;
+ Size.type = TAG_u;
+ Size.val = bits;
+ unit = 0;
+ }
+ }
+ break;
+ case am_integer:
+ {
+ UWord bits;
+ type = BSC_INTEGER;
+ if (Size.type == TAG_i &&
+ (Sint) Size.val >= 0 &&
+ beam_load_safe_mul(Size.val, unit, &bits) &&
+ (bits >> (sizeof(Uint)-1)*8) == 0) {
+ type = BSC_INTEGER_FIXED_SIZE;
+ Size.type = TAG_u;
+ Size.val = bits;
+ unit = 0;
+ }
+ }
+ break;
+ case am_string:
+ type = BSC_STRING;
+ ASSERT(Size.type == TAG_i);
+ ASSERT(unit == 8);
+ Size.type = TAG_u;
+ Size.val = Size.val; /* Size of string in bytes. */
+ unit = 0;
+ break;
+ case am_utf8:
+ type = BSC_UTF8;
+ break;
+ case am_utf16:
+ type = BSC_UTF16;
+ break;
+ case am_utf32:
+ type = BSC_UTF32;
+ Size.type = TAG_u;
+ Size.val = 32;
+ break;
+ default:
+ abort();
+ }
+ dst[0].type = TAG_u;
+ dst[0].val = type;
+
+ /* Store value of unit. */
+ dst[1].val = unit;
+
+ /* Store size. */
+ dst[4] = Size;
+ }
+ return op;
+}