Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
668 lines
18 KiB
C++
668 lines
18 KiB
C++
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
|
|
/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "hm-main.h"
|
|
#include "hm-deoptimizer.h"
|
|
|
|
#ifdef VMCFG_HALFMOON
|
|
|
|
namespace halfmoon {
|
|
|
|
using namespace avmplus;
|
|
using namespace nanojit;
|
|
|
|
void HMDeoptDataWriter::mdAlloc(NIns*& start, NIns*& end, NIns*& bytep)
|
|
{
|
|
if (start)
|
|
CodeAlloc::add(data_, start, end);
|
|
|
|
// MetaDataAlloc contract: allocations never fail
|
|
md_alloc_.alloc(start, end, 0);
|
|
bytep = start;
|
|
}
|
|
|
|
HMDeoptDataWriter::HMDeoptDataWriter(CodeAlloc& md_alloc,
|
|
Allocator& tmp_alloc,
|
|
const MethodSignature* signature,
|
|
LIns** defs)
|
|
: md_alloc_(md_alloc),
|
|
tmp_alloc_(tmp_alloc),
|
|
def_ins_(defs),
|
|
data_(NULL),
|
|
mdins_(NULL),
|
|
start_(NULL),
|
|
end_(NULL),
|
|
sig_(signature),
|
|
mdstart_(NULL)
|
|
{
|
|
mdAlloc(start_, end_, mdins_);
|
|
|
|
mdstart_ = mdins_;
|
|
|
|
// Leave space for HMDeoptData header.
|
|
mdins_ += sizeof(DeoptData);
|
|
|
|
frame_size_ = signature->frame_size();
|
|
stack_base_ = signature->stack_base();
|
|
scope_base_ = signature->scope_base();
|
|
n_locals_ = signature->local_count();
|
|
|
|
npc_ = 1; // Must differ from sentinel value of 0.
|
|
vpc_ = 0;
|
|
scopep_ = 0;
|
|
stackp_ = 0;
|
|
frame_slots_ = new (tmp_alloc_) int[frame_size_];
|
|
VMPI_memset(frame_slots_, 0, frame_size_ * sizeof(int));
|
|
frame_types_ = new (tmp_alloc_) uint8_t[frame_size_];
|
|
VMPI_memset(frame_types_, SST_MAX_VALUE, frame_size_ * sizeof(uint8_t));
|
|
}
|
|
|
|
//#define DEOPT_METADATA_DIAGNOSTIC_HACK
|
|
|
|
DeoptData* HMDeoptDataWriter::finish()
|
|
{
|
|
AvmAssert(mdstart_ != NULL);
|
|
md_alloc_.addRemainder(data_, start_, end_, start_, mdins_);
|
|
|
|
// Placement new. Create HMDeoptData header in space previously reserved.
|
|
DeoptData* dd = new (mdstart_) DeoptData(sig_);
|
|
|
|
#ifdef DEOPT_METADATA_DIAGNOSTIC_HACK
|
|
//fprintf(stderr, "READING\n");
|
|
HMDeoptContext ctx(dd);
|
|
// Force full parse of metadata.
|
|
// Relies on sentinel set in endAssembly().
|
|
ctx.setSafepointFromNativePc(0);
|
|
#endif
|
|
|
|
return dd;
|
|
}
|
|
|
|
void HMDeoptDataWriter::abandon()
|
|
{
|
|
md_alloc_.freeAll(data_);
|
|
mdstart_ = NULL;
|
|
}
|
|
|
|
void HMDeoptDataWriter::ensureSpace(int bytes)
|
|
{
|
|
// There had better be enough space for both the
|
|
// instruction we wish to allocate, and the link
|
|
// to the next chunk that may follow it.
|
|
if (mdins_ + bytes + (1+sizeof(uintptr_t)) > end_) {
|
|
mdAlloc(start_, end_, mdins_);
|
|
writeUInt8(MD_LINK);
|
|
writeUIntPtr(uintptr_t(mdins_));
|
|
}
|
|
}
|
|
|
|
void HMDeoptDataWriter::writeUInt8(uint8_t value)
|
|
{
|
|
*(mdins_++) = value;
|
|
}
|
|
|
|
void HMDeoptDataWriter::writeUInt32(uint32_t value)
|
|
{
|
|
// Write bytewise to avoid unaligned writes.
|
|
// Probably cheaper to write unaligned if the
|
|
// machine handles it without a software trap.
|
|
*(mdins_++) = uint8_t(value & 0x000000ff);
|
|
*(mdins_++) = uint8_t((value & 0x0000ff00) >> 8);
|
|
*(mdins_++) = uint8_t((value & 0x00ff0000) >> 16);
|
|
*(mdins_++) = uint8_t((value & 0xff000000) >> 24);
|
|
}
|
|
|
|
#ifdef VMCFG_64BIT
|
|
void HMDeoptDataWriter::writeUInt64(uint64_t value)
|
|
{
|
|
*(mdins_++) = uint8_t(value & 0x00000000000000ff);
|
|
*(mdins_++) = uint8_t((value & 0x000000000000ff00) >> 8);
|
|
*(mdins_++) = uint8_t((value & 0x0000000000ff0000) >> 16);
|
|
*(mdins_++) = uint8_t((value & 0x00000000ff000000) >> 24);
|
|
*(mdins_++) = uint8_t((value & 0x000000ff00000000) >> 32);
|
|
*(mdins_++) = uint8_t((value & 0x0000ff0000000000) >> 40);
|
|
*(mdins_++) = uint8_t((value & 0x00ff000000000000) >> 48);
|
|
*(mdins_++) = uint8_t((value & 0xff00000000000000) >> 56);
|
|
}
|
|
#endif
|
|
|
|
void HMDeoptDataWriter::writeUIntPtr(uintptr_t value)
|
|
{
|
|
#ifdef VMCFG_64BIT
|
|
writeUInt64(value);
|
|
#else
|
|
writeUInt32(value);
|
|
#endif
|
|
}
|
|
|
|
void HMDeoptDataWriter::writeULEB128(uint32_t value)
|
|
{
|
|
do {
|
|
uint8_t byte = value & 0x7f;
|
|
value >>= 7;
|
|
if (value > 0) byte |= 0x80;
|
|
*(mdins_++) = byte;
|
|
} while (value > 0);
|
|
}
|
|
|
|
int HMDeoptDataWriter::byteCountULEB128(uint32_t value)
|
|
{
|
|
int count = 0;
|
|
do {
|
|
count++;
|
|
value >>= 7;
|
|
} while (value > 0);
|
|
return count;
|
|
}
|
|
|
|
void HMDeoptDataWriter::writeSLEB128(int32_t value)
|
|
{
|
|
// TODO: Portability issue -- Signed >> must be an arithmetic shift.
|
|
AvmAssert(-1 >> 1 == -1);
|
|
for(;;) {
|
|
uint8_t byte = value & 0x7f;
|
|
value >>= 7;
|
|
// Stop writing when the remaining bits are just copies of the sign bit.
|
|
if (((value == 0) && !(byte & 0x40)) || ((value == -1) && (byte & 0x40))) {
|
|
*(mdins_++) = byte;
|
|
return;
|
|
} else {
|
|
*(mdins_++) = byte | 0x80;
|
|
}
|
|
}
|
|
}
|
|
|
|
int HMDeoptDataWriter::byteCountSLEB128(int32_t value)
|
|
{
|
|
int count = 0;
|
|
for(;;) {
|
|
count++;
|
|
int byte = value & 0x7f;
|
|
value >>= 7;
|
|
if (((value == 0) && !(byte & 0x40)) || ((value == -1) && (byte & 0x40))) {
|
|
return count;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HMDeoptDataWriter::beginAssembly(Assembler* assm, uint8_t* address)
|
|
{
|
|
(void)assm;
|
|
npc_ = uintptr_t(address);
|
|
ensureSpace(1+sizeof(uintptr_t));
|
|
writeUInt8(MD_SET_NPC);
|
|
writeUIntPtr(uintptr_t(npc_));
|
|
}
|
|
|
|
void HMDeoptDataWriter::safepointStart(Assembler* assm, void* payload, uint8_t* address)
|
|
{
|
|
(void)assm;
|
|
DeoptSafepointInstr* safepoint = static_cast<DeoptSafepointInstr*>(payload);
|
|
uintptr_t addr = uintptr_t(address);
|
|
|
|
// Virtual pc may advance or retreat with native pc advance, so adjustment is signed.
|
|
int32_t vpc_adjustment = int32_t(vpc_) - int32_t(safepoint->vpc);
|
|
// Native pc values are assigned in monotonically decreasing order (due to assembly
|
|
// in reverse), so the adjustment is always non-negative, interpreted as a decrement.
|
|
int32_t npc_decrement = int32_t(npc_) - int32_t(addr);
|
|
AvmAssert(npc_decrement >= 0);
|
|
|
|
ensureSpace(1 + byteCountSLEB128(vpc_adjustment) + byteCountULEB128(npc_decrement));
|
|
writeUInt8(MD_END);
|
|
writeSLEB128(vpc_adjustment);
|
|
writeULEB128(npc_decrement);
|
|
vpc_ = safepoint->vpc;
|
|
npc_ = addr;
|
|
}
|
|
|
|
void HMDeoptDataWriter::emitSetSlotIdx(DeoptSafepointInstr* safepoint,
|
|
Assembler* assm, int slot, int i)
|
|
{
|
|
Use& use = safepoint->value_in(i);
|
|
int frame_idx = assm->forceStackIndex(def_ins(use));
|
|
SlotStorageType sst = type2sst(type(use));
|
|
// The slot type will likely change much less often than the frame_index,
|
|
// but it is unclear at this point whether a separate MD_SLOT_TYPE instruction
|
|
// is warranted. For now, each MD_SLOT_IDX contains the type.
|
|
if (frame_slots_[slot] != frame_idx || frame_types_[slot] != sst) {
|
|
//fprintf(stderr, "slot %d @ %d : %d\n", slot, frame_idx, sst);
|
|
ensureSpace(1 + 1 + byteCountULEB128(slot) + byteCountULEB128(frame_idx));
|
|
writeUInt8(MD_SLOT_IDX);
|
|
writeUInt8(uint8_t(sst));
|
|
writeULEB128(slot);
|
|
writeULEB128(frame_idx);
|
|
frame_types_[slot] = uint8_t(sst);
|
|
frame_slots_[slot] = frame_idx;
|
|
}
|
|
}
|
|
|
|
void HMDeoptDataWriter::safepointEnd(Assembler* assm, void* payload, uint8_t* address)
|
|
{
|
|
(void)address;
|
|
DeoptSafepointInstr* safepoint = static_cast<DeoptSafepointInstr*>(payload);
|
|
|
|
int n_operands = safepoint->stackp;
|
|
int n_scopes = safepoint->scopep;
|
|
|
|
// TODO: Recognize nested safepoints and produce MD_INLINE.
|
|
// This is probably better done here than in hm-liremitter.cpp.
|
|
|
|
switch (safepoint->kind) {
|
|
case kCallSafepoint:
|
|
AvmAssert(safepoint->vlen < 16);
|
|
ensureSpace(1 + 1 + byteCountULEB128(safepoint->nargs));
|
|
writeUInt8(MD_CALL);
|
|
writeUInt8(uint8_t((safepoint->rtype << 4) | safepoint->vlen));
|
|
writeULEB128(safepoint->nargs);
|
|
break;
|
|
case kInlineSafepoint:
|
|
ensureSpace(1+sizeof(uintptr_t));
|
|
writeUInt8(MD_INLINE);
|
|
writeUIntPtr(uintptr_t(safepoint->minfo));
|
|
break;
|
|
case kThrowSafepoint:
|
|
ensureSpace(1);
|
|
writeUInt8(MD_THROW);
|
|
break;
|
|
case kBailoutSafepoint:
|
|
ensureSpace(1);
|
|
writeUInt8(MD_BAILOUT);
|
|
break;
|
|
default:
|
|
AvmAssert(false);
|
|
}
|
|
|
|
if (safepoint->stackp != stackp_) {
|
|
stackp_ = safepoint->stackp;
|
|
ensureSpace(1 + byteCountULEB128(stackp_));
|
|
writeUInt8(MD_SET_STACK);
|
|
writeULEB128(stackp_);
|
|
}
|
|
if (safepoint->scopep != scopep_) {
|
|
scopep_ = safepoint->scopep;
|
|
ensureSpace(1 + byteCountULEB128(scopep_));
|
|
writeUInt8(MD_SET_SCOPE);
|
|
writeULEB128(scopep_);
|
|
}
|
|
|
|
int j = 0;
|
|
for (int i = 0; i < n_locals_; i++) {
|
|
emitSetSlotIdx(safepoint, assm, i, j++);
|
|
}
|
|
for (int i = scope_base_; i <= n_scopes; i++) {
|
|
emitSetSlotIdx(safepoint, assm, i, j++);
|
|
}
|
|
for (int i = stack_base_; i <= n_operands; i++) {
|
|
emitSetSlotIdx(safepoint, assm, i, j++);
|
|
}
|
|
|
|
}
|
|
|
|
void HMDeoptDataWriter::setNativePc(uint8_t* address)
|
|
{
|
|
//fprintf(stderr, "NEW CHUNK address=0x%p\n", address);
|
|
npc_ = uintptr_t(address);
|
|
ensureSpace(1+sizeof(uintptr_t));
|
|
writeUInt8(MD_SET_NPC);
|
|
writeUIntPtr(npc_);
|
|
}
|
|
|
|
void HMDeoptDataWriter::endAssembly(Assembler* assm, uint8_t* address)
|
|
{
|
|
(void)assm; (void)address;
|
|
// Write sentinel value. Not strictly necessary, but we are presently
|
|
// depending on it in the implementation of some diagnostics.
|
|
ensureSpace(1 + sizeof(uintptr_t));
|
|
writeUInt8(MD_SET_NPC);
|
|
writeUIntPtr(0);
|
|
}
|
|
|
|
|
|
/// Deoptimizer for compiled methods generated by Halfmoon.
|
|
|
|
typedef DeoptimizerInstance<DeoptData, HMDeoptContext> HMDeoptimizer;
|
|
|
|
Deoptimizer* DeoptData::createDeoptimizer(MethodInfo* info)
|
|
{
|
|
return mmfx_new(HMDeoptimizer(info, this));
|
|
}
|
|
|
|
// Return a generic pointer to local slot at the specified index.
|
|
static void* addrOfJitSlot(uint8_t* nativefp, int slot_ix, int shift) {
|
|
return (void*)(nativefp + (slot_ix << shift));
|
|
}
|
|
|
|
/// Frame populators for compiled methods generated by Halfmoon.
|
|
|
|
class HMFramePopulator : /*implements*/ public FramePopulator {
|
|
public:
|
|
HMFramePopulator(AvmCore* core, const HMDeoptContext& ctx, uint8_t* nativefp)
|
|
: core_(core),
|
|
ctx_(ctx),
|
|
nativefp_(nativefp)
|
|
{}
|
|
virtual void populate(Atom* framep, int *scopeDepth, int *stackDepth);
|
|
virtual ~HMFramePopulator() {}
|
|
protected:
|
|
AvmCore* core_;
|
|
const HMDeoptContext& ctx_;
|
|
uint8_t* nativefp_;
|
|
SlotStorageType slotType(int i);
|
|
void populateLocals(Atom* framep);
|
|
void populateScopes(Atom* framep, int *scopeDepth);
|
|
void populateStack(Atom* framep, int *stackDepth);
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(HMFramePopulator);
|
|
};
|
|
|
|
SlotStorageType HMFramePopulator::slotType(int i)
|
|
{
|
|
uint32_t tag = ctx_.frame_types_[i];
|
|
return SlotStorageType(tag);
|
|
}
|
|
|
|
void HMFramePopulator::populateLocals(Atom* framep)
|
|
{
|
|
int local_count = ctx_.signature_->local_count();
|
|
for (int i = 0; i < local_count; i++) {
|
|
void *slot_addr = addrOfJitSlot(nativefp_, ctx_.frame_slots_[i],
|
|
VARSHIFT(this));
|
|
framep[i] = nativeLocalToAtom(core_, slot_addr, slotType(i));
|
|
}
|
|
}
|
|
|
|
void HMFramePopulator::populateScopes(Atom* framep, int *scope_depth)
|
|
{
|
|
int scope_base = ctx_.signature_->scope_base();
|
|
|
|
for (int i = 0; i < ctx_.scopep_; i++) {
|
|
int j = scope_base + i;
|
|
void *slot_addr = addrOfJitSlot(nativefp_, ctx_.frame_slots_[j],
|
|
VARSHIFT(this));
|
|
framep[j] = nativeLocalToAtom(core_, slot_addr, slotType(j));
|
|
}
|
|
*scope_depth = ctx_.scopep_;
|
|
}
|
|
|
|
void HMFramePopulator::populateStack(Atom* framep, int *stack_depth)
|
|
{
|
|
int stack_base = ctx_.signature_->stack_base();
|
|
|
|
for (int i = 0; i < ctx_.stackp_; i++) {
|
|
int j = stack_base + i;
|
|
void *slot_addr = addrOfJitSlot(nativefp_, ctx_.frame_slots_[j],
|
|
VARSHIFT(this));
|
|
framep[j] = nativeLocalToAtom(core_, slot_addr, slotType(j));
|
|
}
|
|
*stack_depth = ctx_.stackp_;
|
|
}
|
|
|
|
void HMFramePopulator::populate(Atom* framep, int *scope_depth, int *stack_depth)
|
|
{
|
|
populateLocals(framep);
|
|
populateScopes(framep, scope_depth);
|
|
populateStack(framep, stack_depth);
|
|
}
|
|
|
|
class HMHandlerFramePopulator : public HMFramePopulator {
|
|
public:
|
|
HMHandlerFramePopulator(AvmCore* core, const HMDeoptContext& ctx,
|
|
uint8_t* nativefp, Atom exn_val)
|
|
: HMFramePopulator(core, ctx, nativefp),
|
|
exn_val_(exn_val)
|
|
{}
|
|
virtual void populate(Atom* framep, int *scope_depth, int *stack_depth);
|
|
virtual ~HMHandlerFramePopulator() {}
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(HMHandlerFramePopulator);
|
|
Atom exn_val_;
|
|
};
|
|
|
|
void HMHandlerFramePopulator::populate(Atom* framep, int *scope_depth,
|
|
int *stack_depth)
|
|
{
|
|
populateLocals(framep);
|
|
*scope_depth = 0;
|
|
int stack_base = ctx_.signature_->stack_base();
|
|
framep[stack_base] = exn_val_;
|
|
*stack_depth = 1;
|
|
}
|
|
|
|
class HMReturnFramePopulator : public HMFramePopulator {
|
|
public:
|
|
HMReturnFramePopulator(AvmCore* core, const HMDeoptContext& ctx,
|
|
uint8_t* nativefp, Atom return_val)
|
|
: HMFramePopulator(core, ctx, nativefp),
|
|
return_val_(return_val)
|
|
{}
|
|
virtual void populate(Atom* framep, int *scope_depth, int *stack_depth);
|
|
virtual ~HMReturnFramePopulator() {}
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(HMReturnFramePopulator);
|
|
Atom return_val_;
|
|
};
|
|
|
|
void HMReturnFramePopulator::populate(Atom* framep, int *scope_depth,
|
|
int *stack_depth)
|
|
{
|
|
int stack_idx;
|
|
populateLocals(framep);
|
|
populateScopes(framep, scope_depth);
|
|
populateStack(framep, &stack_idx);
|
|
stack_idx -= ctx_.nargs_;
|
|
int stack_base = ctx_.signature_->stack_base();
|
|
framep[stack_base + stack_idx] = return_val_;
|
|
*stack_depth = stack_idx + 1;
|
|
}
|
|
|
|
|
|
/// Interpret deoptimization metadata.
|
|
|
|
HMDeoptContext::HMDeoptContext(DeoptData* data)
|
|
: deopt_data_(data),
|
|
signature_(data->signature_),
|
|
frame_size_(signature_->frame_size()),
|
|
stack_base_(signature_->stack_base()),
|
|
scope_base_(signature_->scope_base()),
|
|
n_locals_(signature_->local_count()),
|
|
npc_(0),
|
|
vpc_(0),
|
|
scopep_(0),
|
|
stackp_(0),
|
|
mdins_(0)
|
|
{
|
|
frame_slots_ = mmfx_new_array(int, frame_size_);
|
|
frame_types_ = mmfx_new_array(uint8_t, frame_size_);
|
|
}
|
|
|
|
HMDeoptContext::~HMDeoptContext()
|
|
{
|
|
mmfx_delete_array(frame_slots_);
|
|
mmfx_delete_array(frame_types_);
|
|
}
|
|
|
|
uint8_t HMDeoptContext::readUInt8()
|
|
{
|
|
return uint8_t(*(mdins_++));
|
|
}
|
|
|
|
uint32_t HMDeoptContext::readUInt32()
|
|
{
|
|
uint32_t value = *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
return value;
|
|
}
|
|
|
|
#ifdef VMCFG_64BIT
|
|
uint64_t HMDeoptContext::readUInt64()
|
|
{
|
|
uint64_t value = *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
value = (value << 8) | *(mdins_++);
|
|
return value;
|
|
}
|
|
#endif
|
|
|
|
uintptr_t HMDeoptContext::readUIntPtr()
|
|
{
|
|
#ifdef VMCFG_64BIT
|
|
return readUInt64();
|
|
#else
|
|
return readUInt32();
|
|
#endif
|
|
}
|
|
|
|
uint32_t HMDeoptContext::readULEB128()
|
|
{
|
|
int byte;
|
|
uint32_t value = 0;
|
|
do {
|
|
byte = *(mdins_++);
|
|
value = (value << 7) | (byte & 0x7f);
|
|
} while (byte & 0x80);
|
|
return value;
|
|
}
|
|
|
|
int32_t HMDeoptContext::readSLEB128()
|
|
{
|
|
int byte;
|
|
int shift = 0;
|
|
uint32_t value = 0;
|
|
do {
|
|
byte = *(mdins_++);
|
|
value |= (byte & 0x7f) << shift;
|
|
shift += 7;
|
|
} while (byte & 0x80);
|
|
// Sign-extend
|
|
if (byte & 0x40) {
|
|
value |= 0xffffffff << shift;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void HMDeoptContext::setSafepointFromNativePc(uint8_t* pc)
|
|
{
|
|
kind_ = kInvalidSafepoint;
|
|
npc_ = 1; // Must differ from sentinel value of 0.
|
|
vpc_ = 0;
|
|
scopep_ = 0;
|
|
stackp_ = 0;
|
|
VMPI_memset(frame_slots_, 0, frame_size_ * sizeof(int));
|
|
VMPI_memset(frame_types_, SST_MAX_VALUE, frame_size_ * sizeof(uint8_t));
|
|
nargs_ = 0;
|
|
vlen_ = 0;
|
|
rtype_ = SST_MAX_VALUE; // FIXME: bogus placeholder
|
|
minfo_ = NULL;
|
|
|
|
mdins_ = deopt_data_->instructions();
|
|
//fprintf(stderr, "mdins_ = %p\n", mdins_);
|
|
|
|
while (npc_ > uintptr_t(pc)) {
|
|
// TODO: Need check for end of stream, if only for assertion.
|
|
int op = *(mdins_++);
|
|
//fprintf(stderr, "OP %d @ %p\n", op, mdins_);
|
|
switch (op) {
|
|
case MD_CALL: {
|
|
kind_ = kCallSafepoint;
|
|
uint8_t val = readUInt8();
|
|
vlen_ = val & 0xff;
|
|
rtype_ = SlotStorageType(val >> 4);
|
|
nargs_ = readULEB128();
|
|
break;
|
|
}
|
|
case MD_INLINE: {
|
|
kind_ = kInlineSafepoint;
|
|
minfo_ = (MethodInfo*)readUIntPtr();
|
|
AvmAssert(false); // NYI
|
|
break;
|
|
}
|
|
case MD_THROW: {
|
|
kind_ = kThrowSafepoint;
|
|
AvmAssert(false); // NYI
|
|
break;
|
|
}
|
|
case MD_BAILOUT: {
|
|
kind_ = kBailoutSafepoint;
|
|
break;
|
|
}
|
|
case MD_SLOT_IDX: {
|
|
uint8_t sst = readUInt8();
|
|
uint32_t slot = readULEB128();
|
|
uint32_t frame_idx = readULEB128();
|
|
frame_slots_[slot] = frame_idx;
|
|
frame_types_[slot] = sst;
|
|
//fprintf(stderr, "set_slot %d @ %d\n", slot, frame_idx);
|
|
break;
|
|
}
|
|
case MD_SET_STACK: {
|
|
stackp_ = readULEB128();
|
|
break;
|
|
}
|
|
case MD_SET_SCOPE: {
|
|
scopep_ = readULEB128();
|
|
break;
|
|
}
|
|
case MD_SET_NPC: {
|
|
npc_ = readUIntPtr();
|
|
break;
|
|
}
|
|
case MD_END: {
|
|
vpc_ += readSLEB128();
|
|
npc_ -= readULEB128();
|
|
break;
|
|
}
|
|
case MD_LINK: {
|
|
mdins_ = (NIns*)readUIntPtr();
|
|
break;
|
|
}
|
|
default:
|
|
AvmAssert(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
Atom HMDeoptContext::interpretFromSafepoint(uint8_t* fp, MethodEnv* env)
|
|
{
|
|
// Continue at safepoint instruction.
|
|
AvmAssert(signature_ == env->method->getMethodSignature());
|
|
HMFramePopulator populator(env->core(), *this, fp);
|
|
return interpBoxedAtLocation(env, vpc_, populator);
|
|
}
|
|
|
|
Atom HMDeoptContext::interpretFromCallSafepoint(uint8_t* fp,
|
|
MethodEnv* env,
|
|
Atom return_val)
|
|
{
|
|
// Interpreter frame will reconstruct state at call, with boxed result pushed
|
|
// on operand stack.
|
|
AvmAssert(signature_ == env->method->getMethodSignature());
|
|
AvmAssert(isSafepointAtAbcCall());
|
|
HMReturnFramePopulator populator(env->core(), *this, fp, return_val);
|
|
return interpBoxedAtLocation(env, (vpc_ + vlen_), populator);
|
|
}
|
|
|
|
Atom HMDeoptContext::interpretFromThrowSafepoint(uint8_t* fp,
|
|
MethodEnv* env,
|
|
int32_t handler_vpc,
|
|
Atom exn_val) {
|
|
// Continue at handler target, with stacks reset and exception pushed.
|
|
AvmAssert(signature_ == env->method->getMethodSignature());
|
|
AvmAssert(isSafepointAtThrow());
|
|
HMHandlerFramePopulator populator(env->core(), *this, fp, exn_val);
|
|
return interpBoxedAtLocation(env, handler_vpc, populator);
|
|
}
|
|
|
|
} // end namespace halfmoon
|
|
|
|
#endif // VMCFG_HALFMOON
|