diff options
author | Björn Gustavsson <[email protected]> | 2017-09-06 04:26:47 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2017-09-14 10:16:15 +0200 |
commit | 41b832fd133dd2bfebe858c42ae51db8f0ac0584 (patch) | |
tree | b190fd1896b7449f6e17786c07bc40c12d015711 /erts/emulator/beam/beam_load.c | |
parent | be8fb5a57d1a30c203e79ae2baf9e541226020d8 (diff) | |
download | otp-41b832fd133dd2bfebe858c42ae51db8f0ac0584.tar.gz otp-41b832fd133dd2bfebe858c42ae51db8f0ac0584.tar.bz2 otp-41b832fd133dd2bfebe858c42ae51db8f0ac0584.zip |
Implement packing of 'f' and 'j'
Diffstat (limited to 'erts/emulator/beam/beam_load.c')
-rw-r--r-- | erts/emulator/beam/beam_load.c | 142 |
1 files changed, 127 insertions, 15 deletions
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 2888158c7b..2acf3a2c1c 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -87,6 +87,8 @@ ErlDrvBinary* erts_gzinflate_buffer(char*, int); typedef struct { Uint pos; /* Position of label reference to patch. */ + Uint offset; /* Offset from patch location. */ + int packed; /* 0 (not packed), 1 (lsw), 2 (msw) */ } LabelPatch; /* @@ -237,7 +239,7 @@ typedef struct { typedef struct literal_patch LiteralPatch; struct literal_patch { - int pos; /* Position in code */ + Uint pos; /* Position in code */ LiteralPatch* next; }; @@ -1948,8 +1950,11 @@ register_label_patch(LoaderState* stp, Uint label, Uint ci, Uint offset) (void *) lp->patches, lp->num_allocated * sizeof(LabelPatch)); } - lp->patches[lp->num_patches++].pos = ci; - stp->codev[ci] = offset; + lp->patches[lp->num_patches].pos = ci; + lp->patches[lp->num_patches].offset = offset; + lp->patches[lp->num_patches].packed = 0; + lp->num_patches++; + stp->codev[ci] = label; } static int @@ -2519,23 +2524,58 @@ load_code(LoaderState* stp) char* prog; /* Program for packing engine. */ struct pack_stack { BeamInstr instr; - LiteralPatch* patch; + Uint* patch_pos; } stack[8]; /* Stack. */ struct pack_stack* sp = stack; /* Points to next free position. */ BeamInstr packed = 0; /* Accumulator for packed operations. */ + LabelPatch* packed_label = 0; for (prog = opc[stp->specific_op].pack; *prog; prog++) { switch (*prog) { - case 'g': /* Get instruction; push on stack. */ + case 'g': /* Get operand and push on stack. */ + ci--; + sp->instr = code[ci]; + sp->patch_pos = 0; + sp++; + break; + case 'f': /* Get possible 'f' operand and push on stack. */ + { + Uint w = code[--ci]; + sp->instr = w; + sp->patch_pos = 0; + + if (w != 0) { + LabelPatch* lbl_p; + int num_patches; + int patch; + + ASSERT(w < stp->num_labels); + lbl_p = stp->labels[w].patches; + num_patches = stp->labels[w].num_patches; + for (patch = num_patches - 1; patch >= 0; patch--) { + if (lbl_p[patch].pos == ci) { + sp->patch_pos = &lbl_p[patch].pos; + break; + } + } + ASSERT(sp->patch_pos); + } + sp++; + } + break; + case 'q': /* Get possible 'q' operand and push on stack. */ { LiteralPatch* lp; ci--; sp->instr = code[ci]; - sp->patch = 0; - for (lp = stp->literal_patches; lp && lp->pos > ci-MAX_OPARGS; lp = lp->next) { + sp->patch_pos = 0; + + for (lp = stp->literal_patches; + lp && lp->pos > ci-MAX_OPARGS; + lp = lp->next) { if (lp->pos == ci) { - sp->patch = lp; + sp->patch_pos = &lp->pos; break; } } @@ -2547,28 +2587,68 @@ load_code(LoaderState* stp) break; case '0': /* Tight shift */ packed = (packed << BEAM_TIGHT_SHIFT) | code[--ci]; + if (packed_label) { + packed_label->packed++; + } break; case '6': /* Shift 16 steps */ packed = (packed << BEAM_LOOSE_SHIFT) | code[--ci]; + if (packed_label) { + packed_label->packed++; + } break; #ifdef ARCH_64 case 'w': /* Shift 32 steps */ - packed = (packed << BEAM_WIDE_SHIFT) | code[--ci]; - break; + { + Uint w = code[--ci]; + + if (packed_label) { + packed_label->packed++; + } + + /* + * 'w' can handle both labels ('f' and 'j'), as well + * as 'I'. Test whether this is a label. + */ + + if (w < stp->num_labels) { + /* + * Probably a label. Look for patch pointing to this + * position. + */ + LabelPatch* lp = stp->labels[w].patches; + int num_patches = stp->labels[w].num_patches; + int patch; + for (patch = num_patches - 1; patch >= 0; patch--) { + if (lp[patch].pos == ci) { + lp[patch].packed = 1; + packed_label = &lp[patch]; + break; + } + } + } + packed = (packed << BEAM_WIDE_SHIFT) | + (code[ci] & BEAM_WIDE_MASK); + } + break; #endif case 'p': /* Put instruction (from stack). */ --sp; code[ci] = sp->instr; - if (sp->patch) { - sp->patch->pos = ci; + if (sp->patch_pos) { + *sp->patch_pos = ci; } ci++; break; case 'P': /* Put packed operands. */ sp->instr = packed; - sp->patch = 0; + sp->patch_pos = 0; sp++; packed = 0; + if (packed_label) { + packed_label->pos = ci; + packed_label = 0; + } break; default: ASSERT(0); @@ -4873,7 +4953,8 @@ freeze_code(LoaderState* stp) } ASSERT(value < stp->ci); for (patch = 0; patch < stp->labels[i].num_patches; patch++) { - Uint pos = stp->labels[i].patches[patch].pos; + LabelPatch* lp = &stp->labels[i].patches[patch]; + Uint pos = lp->pos; ASSERT(pos < stp->ci); if (pos < stp->num_functions) { /* @@ -4882,7 +4963,38 @@ freeze_code(LoaderState* stp) */ codev[pos] = (BeamInstr) (codev + value); } else { - codev[pos] += value; +#ifdef DEBUG + Uint w; +#endif + Sint32 rel = lp->offset + value; + switch (lp->packed) { + case 0: /* Not packed */ + ASSERT(codev[pos] == i); + codev[pos] = rel; + break; +#ifdef BEAM_WIDE_MASK + case 1: /* Least significant word. */ +#ifdef DEBUG + w = codev[pos] & BEAM_WIDE_MASK; + /* Correct label in least significant word? */ + ASSERT(w == i); +#endif + codev[pos] = (codev[pos] & ~BEAM_WIDE_MASK) | + (rel & BEAM_WIDE_MASK); + break; + case 2: /* Most significant word */ +#ifdef DEBUG + w = (codev[pos] >> BEAM_WIDE_SHIFT) & BEAM_WIDE_MASK; + /* Correct label in most significant word? */ + ASSERT(w == i); +#endif + codev[pos] = ((Uint)rel << BEAM_WIDE_SHIFT) | + (codev[pos] & BEAM_WIDE_MASK); + break; +#endif + default: + ASSERT(0); + } } } } |