зеркало из https://github.com/mozilla/gecko-dev.git
Bug 962555 part 6 - IonMonkey: Simplify encoding & decoding of RValueAllocations. r=h4writer
This commit is contained in:
Родитель
50033bf490
Коммит
14278fe362
|
@ -259,12 +259,25 @@ class SnapshotIterator : public SnapshotReader
|
|||
|
||||
private:
|
||||
// Read a spilled register from the machine state.
|
||||
bool hasRegister(const Location &loc);
|
||||
uintptr_t fromRegister(const Location &loc);
|
||||
bool hasRegister(Register reg) const {
|
||||
return machine_.has(reg);
|
||||
}
|
||||
uintptr_t fromRegister(Register reg) const {
|
||||
return machine_.read(reg);
|
||||
}
|
||||
|
||||
bool hasRegister(FloatRegister reg) const {
|
||||
return machine_.has(reg);
|
||||
}
|
||||
double fromRegister(FloatRegister reg) const {
|
||||
return machine_.read(reg);
|
||||
}
|
||||
|
||||
// Read an uintptr_t from the stack.
|
||||
bool hasStack(const Location &loc);
|
||||
uintptr_t fromStack(const Location &loc);
|
||||
bool hasStack(int32_t offset) const {
|
||||
return true;
|
||||
}
|
||||
uintptr_t fromStack(int32_t offset) const;
|
||||
|
||||
Value allocationValue(const RValueAllocation &a);
|
||||
bool allocationReadable(const RValueAllocation &a);
|
||||
|
|
|
@ -1322,29 +1322,10 @@ SnapshotIterator::SnapshotIterator()
|
|||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SnapshotIterator::hasRegister(const Location &loc)
|
||||
{
|
||||
return machine_.has(loc.reg());
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
SnapshotIterator::fromRegister(const Location &loc)
|
||||
SnapshotIterator::fromStack(int32_t offset) const
|
||||
{
|
||||
return machine_.read(loc.reg());
|
||||
}
|
||||
|
||||
bool
|
||||
SnapshotIterator::hasStack(const Location &loc)
|
||||
{
|
||||
JS_ASSERT(loc.isStackOffset());
|
||||
return true;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
SnapshotIterator::fromStack(const Location &loc)
|
||||
{
|
||||
return ReadFrameSlot(fp_, loc.stackOffset());
|
||||
return ReadFrameSlot(fp_, offset);
|
||||
}
|
||||
|
||||
static Value
|
||||
|
@ -1381,25 +1362,25 @@ SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
|
|||
{
|
||||
switch (alloc.mode()) {
|
||||
case RValueAllocation::DOUBLE_REG:
|
||||
return machine_.has(alloc.floatReg());
|
||||
return hasRegister(alloc.fpuReg());
|
||||
|
||||
case RValueAllocation::TYPED_REG:
|
||||
return machine_.has(alloc.reg());
|
||||
return hasRegister(alloc.reg());
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
case RValueAllocation::UNTYPED_REG_REG:
|
||||
return hasRegister(alloc.type()) && hasRegister(alloc.payload());
|
||||
return hasRegister(alloc.reg()) && hasRegister(alloc.reg2());
|
||||
case RValueAllocation::UNTYPED_REG_STACK:
|
||||
return hasRegister(alloc.type()) && hasStack(alloc.payload());
|
||||
return hasRegister(alloc.reg()) && hasStack(alloc.stackOffset2());
|
||||
case RValueAllocation::UNTYPED_STACK_REG:
|
||||
return hasStack(alloc.type()) && hasRegister(alloc.payload());
|
||||
return hasStack(alloc.stackOffset()) && hasRegister(alloc.reg2());
|
||||
case RValueAllocation::UNTYPED_STACK_STACK:
|
||||
return hasStack(alloc.type()) && hasStack(alloc.payload());
|
||||
return hasStack(alloc.stackOffset()) && hasStack(alloc.stackOffset2());
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case RValueAllocation::UNTYPED_REG:
|
||||
return hasRegister(alloc.value());
|
||||
return hasRegister(alloc.reg());
|
||||
case RValueAllocation::UNTYPED_STACK:
|
||||
return hasStack(alloc.value());
|
||||
return hasStack(alloc.stackOffset());
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
@ -1411,8 +1392,17 @@ Value
|
|||
SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
||||
{
|
||||
switch (alloc.mode()) {
|
||||
case RValueAllocation::CONSTANT:
|
||||
return ionScript_->getConstant(alloc.index());
|
||||
|
||||
case RValueAllocation::CST_UNDEFINED:
|
||||
return UndefinedValue();
|
||||
|
||||
case RValueAllocation::CST_NULL:
|
||||
return NullValue();
|
||||
|
||||
case RValueAllocation::DOUBLE_REG:
|
||||
return DoubleValue(machine_.read(alloc.floatReg()));
|
||||
return DoubleValue(fromRegister(alloc.fpuReg()));
|
||||
|
||||
case RValueAllocation::FLOAT32_REG:
|
||||
{
|
||||
|
@ -1420,7 +1410,7 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
|||
double d;
|
||||
float f;
|
||||
} pun;
|
||||
pun.d = machine_.read(alloc.floatReg());
|
||||
pun.d = fromRegister(alloc.fpuReg());
|
||||
// The register contains the encoding of a float32. We just read
|
||||
// the bits without making any conversion.
|
||||
return Float32Value(pun.f);
|
||||
|
@ -1430,21 +1420,21 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
|||
return Float32Value(ReadFrameFloat32Slot(fp_, alloc.stackOffset()));
|
||||
|
||||
case RValueAllocation::TYPED_REG:
|
||||
return FromTypedPayload(alloc.knownType(), machine_.read(alloc.reg()));
|
||||
return FromTypedPayload(alloc.knownType(), fromRegister(alloc.reg2()));
|
||||
|
||||
case RValueAllocation::TYPED_STACK:
|
||||
{
|
||||
switch (alloc.knownType()) {
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset()));
|
||||
return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_INT32:
|
||||
return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset()));
|
||||
return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset()));
|
||||
return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_STRING:
|
||||
return FromStringPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
|
||||
return FromStringPayload(fromStack(alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return FromObjectPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
|
||||
return FromObjectPayload(fromStack(alloc.stackOffset2()));
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected type");
|
||||
}
|
||||
|
@ -1454,62 +1444,50 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
|||
case RValueAllocation::UNTYPED_REG_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.type());
|
||||
layout.s.payload.word = fromRegister(alloc.payload());
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
|
||||
layout.s.payload.word = fromRegister(alloc.reg2());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case RValueAllocation::UNTYPED_REG_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.type());
|
||||
layout.s.payload.word = fromStack(alloc.payload());
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
|
||||
layout.s.payload.word = fromStack(alloc.stackOffset2());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case RValueAllocation::UNTYPED_STACK_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.type());
|
||||
layout.s.payload.word = fromRegister(alloc.payload());
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
|
||||
layout.s.payload.word = fromRegister(alloc.reg2());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case RValueAllocation::UNTYPED_STACK_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.type());
|
||||
layout.s.payload.word = fromStack(alloc.payload());
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
|
||||
layout.s.payload.word = fromStack(alloc.stackOffset2());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case RValueAllocation::UNTYPED_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.asBits = fromRegister(alloc.value());
|
||||
layout.asBits = fromRegister(alloc.reg());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case RValueAllocation::UNTYPED_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.asBits = fromStack(alloc.value());
|
||||
layout.asBits = fromStack(alloc.stackOffset());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
#endif
|
||||
|
||||
case RValueAllocation::JS_UNDEFINED:
|
||||
return UndefinedValue();
|
||||
|
||||
case RValueAllocation::JS_NULL:
|
||||
return NullValue();
|
||||
|
||||
case RValueAllocation::JS_INT32:
|
||||
return Int32Value(alloc.int32Value());
|
||||
|
||||
case RValueAllocation::CONSTANT:
|
||||
return ionScript_->getConstant(alloc.constantIndex());
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
}
|
||||
|
|
|
@ -28,290 +28,325 @@ using namespace js::jit;
|
|||
//
|
||||
// [ptr] Debug only: JSScript *
|
||||
// [vwu] pc offset
|
||||
// [vwu] # of slots, including nargs
|
||||
// [rva*] N recover value allocations entries,
|
||||
// where N = nargs + nfixed + stackDepth
|
||||
// [vwu] # of RVA's indexes, including nargs
|
||||
// [vwu*] List of indexes to R(ecover)ValueAllocation table. Contains
|
||||
// nargs + nfixed + stackDepth items.
|
||||
//
|
||||
// Recover value allocations are encoded at the end of the Snapshot buffer, and
|
||||
// they are padded on ALLOCATION_TABLE_ALIGNMENT. The encoding of each
|
||||
// allocation is determined by the RValueAllocation::Layout, which can be
|
||||
// obtained from the RValueAllocation::Mode with layoutFromMode function. The
|
||||
// layout structure list the type of payload which are used to serialized /
|
||||
// deserialized / dumped the content of the allocations.
|
||||
//
|
||||
// R(ecover)ValueAllocation items:
|
||||
// [u8'] Mode, which defines the type of the payload as well as the
|
||||
// interpretation.
|
||||
// [pld] first payload (packed tag, index, stack offset, register, ...)
|
||||
// [pld] second payload (register, stack offset, none)
|
||||
//
|
||||
// Modes:
|
||||
// CONSTANT [INDEX]
|
||||
// Index into the constant pool.
|
||||
//
|
||||
// CST_UNDEFINED []
|
||||
// Constant value which correspond to the "undefined" JS value.
|
||||
//
|
||||
// CST_NULL []
|
||||
// Constant value which correspond to the "null" JS value.
|
||||
//
|
||||
// DOUBLE_REG [FPU_REG]
|
||||
// Double value stored in a FPU register.
|
||||
//
|
||||
// FLOAT32_REG [FPU_REG]
|
||||
// Float 32bit value stored in a FPU register.
|
||||
//
|
||||
// FLOAT32_STACK [STACK_OFFSET]
|
||||
// Float 32bit value stored on the stack.
|
||||
//
|
||||
// UNTYPED_REG [GPR_REG]
|
||||
// UNTYPED_STACK [STACK_OFFSET]
|
||||
// UNTYPED_REG_REG [GPR_REG, GPR_REG]
|
||||
// UNTYPED_REG_STACK [GPR_REG, STACK_OFFSET]
|
||||
// UNTYPED_STACK_REG [STACK_OFFSET, GPR_REG]
|
||||
// UNTYPED_STACK_STACK [STACK_OFFSET, STACK_OFFSET]
|
||||
// Value with dynamically known type. On 32 bits architecture, the
|
||||
// first register/stack-offset correspond to the holder of the type,
|
||||
// and the second correspond to the payload of the JS Value.
|
||||
//
|
||||
// TYPED_REG [PACKED_TAG, GPR_REG]:
|
||||
// Value with statically known type, which payload is stored in a
|
||||
// register.
|
||||
//
|
||||
// TYPED_STACK [PACKED_TAG, STACK_OFFSET]:
|
||||
// Value with statically known type, which payload is stored at an
|
||||
// offset on the stack.
|
||||
//
|
||||
// Encodings:
|
||||
// [ptr] A fixed-size pointer.
|
||||
// [vwu] A variable-width unsigned integer.
|
||||
// [vws] A variable-width signed integer.
|
||||
// [u8] An 8-bit unsigned integer.
|
||||
// [rva*] list of RValueAllocation which are indicating how to find a js::Value
|
||||
// on a call/bailout. The first byte is split as thus:
|
||||
// Bits 0-2: JSValueType
|
||||
// Bits 3-7: 5-bit register code ("reg").
|
||||
// [u8'] An 8-bit unsigned integer which is potentially extended with packed
|
||||
// data.
|
||||
// [u8"] Packed data which is stored and packed in the previous [u8'].
|
||||
// [vwu*] A list of variable-width unsigned integers.
|
||||
// [pld] Payload of Recover Value Allocation:
|
||||
// PAYLOAD_NONE:
|
||||
// There is no payload.
|
||||
//
|
||||
// JSVAL_TYPE_DOUBLE:
|
||||
// If "reg" is InvalidFloatReg, this byte is followed by a
|
||||
// [vws] stack offset. Otherwise, "reg" encodes an XMM register.
|
||||
// PAYLOAD_INDEX:
|
||||
// [vwu] Index, such as the constant pool index.
|
||||
//
|
||||
// JSVAL_TYPE_INT32:
|
||||
// JSVAL_TYPE_OBJECT:
|
||||
// JSVAL_TYPE_BOOLEAN:
|
||||
// JSVAL_TYPE_STRING:
|
||||
// If "reg" is ESC_REG_FIELD_INDEX, this byte is followed by a
|
||||
// [vws] stack offset. Otherwise, "reg" encodes a GPR register.
|
||||
// PAYLOAD_STACK_OFFSET:
|
||||
// [vws] Stack offset based on the base of the Ion frame.
|
||||
//
|
||||
// JSVAL_TYPE_NULL:
|
||||
// Reg value:
|
||||
// 0-27: Constant integer; Int32Value(n)
|
||||
// 28: Variable float32; Float register code
|
||||
// 29: Variable float32; Stack index
|
||||
// 30: NullValue()
|
||||
// 31: Constant integer; Int32Value([vws])
|
||||
// PAYLOAD_GPR:
|
||||
// [u8] Code of the general register.
|
||||
//
|
||||
// JSVAL_TYPE_UNDEFINED:
|
||||
// Reg value:
|
||||
// 0-27: Constant value, index n into ionScript->constants()
|
||||
// 28-29: unused
|
||||
// 30: UndefinedValue()
|
||||
// 31: Constant value, index [vwu] into
|
||||
// ionScript->constants()
|
||||
// PAYLOAD_FPU:
|
||||
// [u8] Code of the FPU register.
|
||||
//
|
||||
// JSVAL_TYPE_MAGIC: (reg value is 30)
|
||||
// The value is a lazy argument object. Followed by extra fields
|
||||
// indicating the location of the payload.
|
||||
// [vwu] reg2 (0-29)
|
||||
// [vwu] reg2 (31) [vws] stack index
|
||||
//
|
||||
// JSVAL_TYPE_MAGIC:
|
||||
// The type is not statically known. The meaning of this depends
|
||||
// on the boxing style.
|
||||
//
|
||||
// NUNBOX32:
|
||||
// Followed by a type and payload indicator that are one of
|
||||
// the following:
|
||||
// code=0 [vws] stack slot, [vws] stack slot
|
||||
// code=1 [vws] stack slot, reg
|
||||
// code=2 reg, [vws] stack slot
|
||||
// code=3 reg, reg
|
||||
//
|
||||
// PUNBOX64:
|
||||
// "reg" is ESC_REG_FIELD_INDEX: byte is followed by a [vws]
|
||||
// stack offset containing a Value.
|
||||
//
|
||||
// Otherwise, "reg" is a register containing a Value.
|
||||
// PAYLOAD_PACKED_TAG:
|
||||
// [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
|
||||
// of the RValueAllocation.
|
||||
//
|
||||
|
||||
#ifdef JS_NUNBOX32
|
||||
static const uint32_t NUNBOX32_STACK_STACK = 0;
|
||||
static const uint32_t NUNBOX32_STACK_REG = 1;
|
||||
static const uint32_t NUNBOX32_REG_STACK = 2;
|
||||
static const uint32_t NUNBOX32_REG_REG = 3;
|
||||
const RValueAllocation::Layout &
|
||||
RValueAllocation::layoutFromMode(Mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case CONSTANT: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_INDEX,
|
||||
PAYLOAD_NONE,
|
||||
"constant"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
|
||||
case CST_UNDEFINED: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_NONE,
|
||||
PAYLOAD_NONE,
|
||||
"undefined"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
|
||||
case CST_NULL: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_NONE,
|
||||
PAYLOAD_NONE,
|
||||
"null"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
|
||||
case DOUBLE_REG: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_FPU,
|
||||
PAYLOAD_NONE,
|
||||
"double"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
case FLOAT32_REG: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_FPU,
|
||||
PAYLOAD_NONE,
|
||||
"float32"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
case FLOAT32_STACK: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
PAYLOAD_NONE,
|
||||
"float32"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_GPR,
|
||||
PAYLOAD_GPR,
|
||||
"value"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
case UNTYPED_REG_STACK: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_GPR,
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
"value"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
case UNTYPED_STACK_REG: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
PAYLOAD_GPR
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
case UNTYPED_STACK_STACK: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
"value"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case UNTYPED_REG: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_GPR,
|
||||
PAYLOAD_NONE,
|
||||
"value"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
case UNTYPED_STACK: {
|
||||
static const RValueAllocation::Layout layout = {
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
PAYLOAD_NONE,
|
||||
"value"
|
||||
};
|
||||
return layout;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
static const RValueAllocation::Layout regLayout = {
|
||||
PAYLOAD_PACKED_TAG,
|
||||
PAYLOAD_GPR,
|
||||
"typed value"
|
||||
};
|
||||
|
||||
static const uint32_t MAX_TYPE_FIELD_VALUE = 7;
|
||||
static const RValueAllocation::Layout stackLayout = {
|
||||
PAYLOAD_PACKED_TAG,
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
"typed value"
|
||||
};
|
||||
|
||||
static const uint32_t MAX_REG_FIELD_VALUE = 31;
|
||||
static const uint32_t ESC_REG_FIELD_INDEX = 31;
|
||||
static const uint32_t ESC_REG_FIELD_CONST = 30;
|
||||
static const uint32_t ESC_REG_FIELD_FLOAT32_STACK = 29;
|
||||
static const uint32_t ESC_REG_FIELD_FLOAT32_REG = 28;
|
||||
static const uint32_t MIN_REG_FIELD_ESC = 28;
|
||||
if (mode >= TYPED_REG_MIN && mode <= TYPED_REG_MAX)
|
||||
return regLayout;
|
||||
if (mode >= TYPED_STACK_MIN && mode <= TYPED_STACK_MAX)
|
||||
return stackLayout;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Wrong mode type?");
|
||||
}
|
||||
|
||||
// Pad serialized RValueAllocations by a multiple of X bytes in the allocation
|
||||
// buffer. By padding serialized value allocations, we are building an
|
||||
// indexable table of elements of X bytes, and thus we can safely divide any
|
||||
// offset within the buffer by X to obtain an index.
|
||||
//
|
||||
// By padding, we are loosing space within the allocation buffer, but we
|
||||
// multiple by X the number of indexes that we can store on one byte in each
|
||||
// snapshots.
|
||||
//
|
||||
// Some value allocations are taking more than X bytes to be encoded, in which
|
||||
// case we will pad to a multiple of X, and we are wasting indexes. The choice
|
||||
// of X should be balanced between the wasted padding of serialized value
|
||||
// allocation, and the saving made in snapshot indexes.
|
||||
static const size_t ALLOCATION_TABLE_ALIGNMENT = 2; /* bytes */
|
||||
|
||||
void
|
||||
RValueAllocation::readPayload(CompactBufferReader &reader, PayloadType type,
|
||||
uint8_t *mode, Payload *p)
|
||||
{
|
||||
switch (type) {
|
||||
case PAYLOAD_NONE:
|
||||
break;
|
||||
case PAYLOAD_INDEX:
|
||||
p->index = reader.readUnsigned();
|
||||
break;
|
||||
case PAYLOAD_STACK_OFFSET:
|
||||
p->stackOffset = reader.readSigned();
|
||||
break;
|
||||
case PAYLOAD_GPR:
|
||||
p->gpr = Register::FromCode(reader.readByte());
|
||||
break;
|
||||
case PAYLOAD_FPU:
|
||||
p->fpu = FloatRegister::FromCode(reader.readByte());
|
||||
break;
|
||||
case PAYLOAD_PACKED_TAG:
|
||||
p->type = JSValueType(*mode & 0x07);
|
||||
*mode = *mode & ~0x07;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RValueAllocation
|
||||
RValueAllocation::read(CompactBufferReader &reader)
|
||||
{
|
||||
uint8_t b = reader.readByte();
|
||||
uint8_t mode = reader.readByte();
|
||||
const Layout &layout = layoutFromMode(Mode(mode));
|
||||
Payload arg1, arg2;
|
||||
|
||||
JSValueType type = JSValueType(b & 0x7);
|
||||
uint32_t code = b >> 3;
|
||||
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Double(FloatRegister::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Typed(type, reader.readSigned());
|
||||
|
||||
case JSVAL_TYPE_INT32:
|
||||
case JSVAL_TYPE_STRING:
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Typed(type, Register::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Typed(type, reader.readSigned());
|
||||
|
||||
case JSVAL_TYPE_NULL:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return Null();
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return Int32(reader.readSigned());
|
||||
if (code == ESC_REG_FIELD_FLOAT32_REG)
|
||||
return Float32(FloatRegister::FromCode(reader.readUnsigned()));
|
||||
if (code == ESC_REG_FIELD_FLOAT32_STACK)
|
||||
return Float32(reader.readSigned());
|
||||
return Int32(code);
|
||||
|
||||
case JSVAL_TYPE_UNDEFINED:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return Undefined();
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return ConstantPool(reader.readUnsigned());
|
||||
return ConstantPool(code);
|
||||
|
||||
case JSVAL_TYPE_MAGIC:
|
||||
{
|
||||
if (code == ESC_REG_FIELD_CONST) {
|
||||
uint8_t reg2 = reader.readUnsigned();
|
||||
if (reg2 != ESC_REG_FIELD_INDEX)
|
||||
return Typed(type, Register::FromCode(reg2));
|
||||
return Typed(type, reader.readSigned());
|
||||
}
|
||||
|
||||
#ifdef JS_NUNBOX32
|
||||
int32_t type, payload;
|
||||
switch (code) {
|
||||
case NUNBOX32_STACK_STACK:
|
||||
type = reader.readSigned();
|
||||
payload = reader.readSigned();
|
||||
return Untyped(type, payload);
|
||||
case NUNBOX32_STACK_REG:
|
||||
type = reader.readSigned();
|
||||
payload = reader.readByte();
|
||||
return Untyped(type, Register::FromCode(payload));
|
||||
case NUNBOX32_REG_STACK:
|
||||
type = reader.readByte();
|
||||
payload = reader.readSigned();
|
||||
return Untyped(Register::FromCode(type), payload);
|
||||
case NUNBOX32_REG_REG:
|
||||
type = reader.readByte();
|
||||
payload = reader.readByte();
|
||||
return Untyped(Register::FromCode(type),
|
||||
Register::FromCode(payload));
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("bad code");
|
||||
break;
|
||||
}
|
||||
#elif JS_PUNBOX64
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return Untyped(Register::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return Untyped(reader.readSigned());
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("bad type");
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
readPayload(reader, layout.type1, &mode, &arg1);
|
||||
readPayload(reader, layout.type2, &mode, &arg2);
|
||||
return RValueAllocation(Mode(mode), arg1, arg2);
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::writeHeader(CompactBufferWriter &writer,
|
||||
JSValueType type,
|
||||
uint32_t regCode) const
|
||||
RValueAllocation::writePayload(CompactBufferWriter &writer, PayloadType type,
|
||||
Payload p)
|
||||
{
|
||||
JS_ASSERT(uint32_t(type) <= MAX_TYPE_FIELD_VALUE);
|
||||
JS_ASSERT(uint32_t(regCode) <= MAX_REG_FIELD_VALUE);
|
||||
JS_STATIC_ASSERT(Registers::Total < MIN_REG_FIELD_ESC);
|
||||
switch (type) {
|
||||
case PAYLOAD_NONE:
|
||||
break;
|
||||
case PAYLOAD_INDEX:
|
||||
writer.writeUnsigned(p.index);
|
||||
break;
|
||||
case PAYLOAD_STACK_OFFSET:
|
||||
writer.writeSigned(p.stackOffset);
|
||||
break;
|
||||
case PAYLOAD_GPR:
|
||||
static_assert(Registers::Total <= 0x100,
|
||||
"Not enough bytes to encode all registers.");
|
||||
writer.writeByte(p.gpr.code());
|
||||
break;
|
||||
case PAYLOAD_FPU:
|
||||
static_assert(FloatRegisters::Total <= 0x100,
|
||||
"Not enough bytes to encode all float registers.");
|
||||
writer.writeByte(p.fpu.code());
|
||||
break;
|
||||
case PAYLOAD_PACKED_TAG: {
|
||||
// This code assumes that the PACKED_TAG payload is following the
|
||||
// writeByte of the mode.
|
||||
MOZ_ASSERT(writer.length());
|
||||
uint8_t *mode = writer.buffer() + (writer.length() - 1);
|
||||
MOZ_ASSERT((*mode & 0x07) == 0 && (p.type & ~0x07) == 0);
|
||||
*mode = *mode | p.type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t byte = uint32_t(type) | (regCode << 3);
|
||||
writer.writeByte(byte);
|
||||
void
|
||||
RValueAllocation::writePadding(CompactBufferWriter &writer)
|
||||
{
|
||||
// Write 0x7f in all padding bytes.
|
||||
while (writer.length() % ALLOCATION_TABLE_ALIGNMENT)
|
||||
writer.writeByte(0x7f);
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::write(CompactBufferWriter &writer) const
|
||||
{
|
||||
switch (mode()) {
|
||||
case CONSTANT: {
|
||||
if (constantIndex() < MIN_REG_FIELD_ESC) {
|
||||
writeHeader(writer, JSVAL_TYPE_UNDEFINED, constantIndex());
|
||||
} else {
|
||||
writeHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_INDEX);
|
||||
writer.writeUnsigned(constantIndex());
|
||||
}
|
||||
break;
|
||||
}
|
||||
const Layout &layout = layoutFromMode(mode());
|
||||
MOZ_ASSERT(layout.type2 != PAYLOAD_PACKED_TAG);
|
||||
MOZ_ASSERT(writer.length() % ALLOCATION_TABLE_ALIGNMENT == 0);
|
||||
|
||||
case DOUBLE_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_DOUBLE, floatReg().code());
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOAT32_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_REG);
|
||||
writer.writeUnsigned(floatReg().code());
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOAT32_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_STACK);
|
||||
writer.writeSigned(stackOffset());
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPED_REG: {
|
||||
writeHeader(writer, knownType(), reg().code());
|
||||
break;
|
||||
}
|
||||
case TYPED_STACK: {
|
||||
writeHeader(writer, knownType(), ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(stackOffset());
|
||||
break;
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
|
||||
writer.writeByte(type().reg().code());
|
||||
writer.writeByte(payload().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_REG_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_STACK);
|
||||
writer.writeByte(type().reg().code());
|
||||
writer.writeSigned(payload().stackOffset());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_REG);
|
||||
writer.writeSigned(type().stackOffset());
|
||||
writer.writeByte(payload().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_STACK);
|
||||
writer.writeSigned(type().stackOffset());
|
||||
writer.writeSigned(payload().stackOffset());
|
||||
break;
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case UNTYPED_REG: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, value().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK: {
|
||||
writeHeader(writer, JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(value().stackOffset());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case JS_UNDEFINED: {
|
||||
writeHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_CONST);
|
||||
break;
|
||||
}
|
||||
case JS_NULL: {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_CONST);
|
||||
break;
|
||||
}
|
||||
case JS_INT32: {
|
||||
if (int32Value() >= 0 && uint32_t(int32Value()) < MIN_REG_FIELD_ESC) {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, int32Value());
|
||||
} else {
|
||||
writeHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(int32Value());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INVALID: {
|
||||
MOZ_ASSUME_UNREACHABLE("not initialized");
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.writeByte(mode_);
|
||||
writePayload(writer, layout.type1, arg1_);
|
||||
writePayload(writer, layout.type2, arg2_);
|
||||
writePadding(writer);
|
||||
}
|
||||
|
||||
HashNumber
|
||||
|
@ -320,10 +355,10 @@ RValueAllocation::hash() const {
|
|||
write(writer);
|
||||
|
||||
// We should never oom because the compact buffer writer has 32 inlined
|
||||
// bytes, and in the worse case scenario, only encode 11 bytes (= header
|
||||
// + signed + signed).
|
||||
// bytes, and in the worse case scenario, only encode 12 bytes
|
||||
// (12 == mode + signed + signed + pad).
|
||||
MOZ_ASSERT(!writer.oom());
|
||||
MOZ_ASSERT(writer.length() <= 11);
|
||||
MOZ_ASSERT(writer.length() <= 12);
|
||||
|
||||
HashNumber res = 0;
|
||||
for (size_t i = 0; i < writer.length(); i++) {
|
||||
|
@ -333,15 +368,6 @@ RValueAllocation::hash() const {
|
|||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
Location::dump(FILE *fp) const
|
||||
{
|
||||
if (isStackOffset())
|
||||
fprintf(fp, "stack %d", stackOffset());
|
||||
else
|
||||
fprintf(fp, "reg %s", reg().name());
|
||||
}
|
||||
|
||||
static const char *
|
||||
ValTypeToString(JSValueType type)
|
||||
{
|
||||
|
@ -364,72 +390,66 @@ ValTypeToString(JSValueType type)
|
|||
}
|
||||
|
||||
void
|
||||
RValueAllocation::dump(FILE *fp) const
|
||||
RValueAllocation::dumpPayload(FILE *fp, PayloadType type, Payload p)
|
||||
{
|
||||
switch (mode()) {
|
||||
case CONSTANT:
|
||||
fprintf(fp, "constant (pool index %u)", constantIndex());
|
||||
switch (type) {
|
||||
case PAYLOAD_NONE:
|
||||
break;
|
||||
|
||||
case DOUBLE_REG:
|
||||
fprintf(fp, "double (reg %s)", floatReg().name());
|
||||
case PAYLOAD_INDEX:
|
||||
fprintf(fp, "index %u", p.index);
|
||||
break;
|
||||
|
||||
case FLOAT32_REG:
|
||||
fprintf(fp, "float32 (reg %s)", floatReg().name());
|
||||
case PAYLOAD_STACK_OFFSET:
|
||||
fprintf(fp, "stack %d", p.stackOffset);
|
||||
break;
|
||||
|
||||
case FLOAT32_STACK:
|
||||
fprintf(fp, "float32 (");
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
case PAYLOAD_GPR:
|
||||
fprintf(fp, "reg %s", p.gpr.name());
|
||||
break;
|
||||
|
||||
case TYPED_REG:
|
||||
case TYPED_STACK:
|
||||
fprintf(fp, "%s (", ValTypeToString(knownType()));
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
case PAYLOAD_FPU:
|
||||
fprintf(fp, "reg %s", p.fpu.name());
|
||||
break;
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG:
|
||||
case UNTYPED_REG_STACK:
|
||||
case UNTYPED_STACK_REG:
|
||||
case UNTYPED_STACK_STACK:
|
||||
fprintf(fp, "value (type = ");
|
||||
type().dump(fp);
|
||||
fprintf(fp, ", payload = ");
|
||||
payload().dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case UNTYPED_REG:
|
||||
case UNTYPED_STACK:
|
||||
fprintf(fp, "value (");
|
||||
value().dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
#endif
|
||||
|
||||
case JS_UNDEFINED:
|
||||
fprintf(fp, "undefined");
|
||||
break;
|
||||
|
||||
case JS_NULL:
|
||||
fprintf(fp, "null");
|
||||
break;
|
||||
|
||||
case JS_INT32:
|
||||
fprintf(fp, "int32_t %d", int32Value());
|
||||
break;
|
||||
|
||||
case INVALID:
|
||||
fprintf(fp, "invalid");
|
||||
case PAYLOAD_PACKED_TAG:
|
||||
fprintf(fp, ValTypeToString(p.type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::dump(FILE *fp) const
|
||||
{
|
||||
const Layout &layout = layoutFromMode(mode());
|
||||
fprintf(fp, "%s", layout.name);
|
||||
|
||||
if (layout.type1 != PAYLOAD_NONE)
|
||||
fprintf(fp, " (");
|
||||
dumpPayload(fp, layout.type1, arg1_);
|
||||
if (layout.type2 != PAYLOAD_NONE)
|
||||
fprintf(fp, ", ");
|
||||
dumpPayload(fp, layout.type2, arg2_);
|
||||
if (layout.type1 != PAYLOAD_NONE)
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
|
||||
bool
|
||||
RValueAllocation::equalPayloads(PayloadType type, Payload lhs, Payload rhs)
|
||||
{
|
||||
switch (type) {
|
||||
case PAYLOAD_NONE:
|
||||
return true;
|
||||
case PAYLOAD_INDEX:
|
||||
return lhs.index == rhs.index;
|
||||
case PAYLOAD_STACK_OFFSET:
|
||||
return lhs.stackOffset == rhs.stackOffset;
|
||||
case PAYLOAD_GPR:
|
||||
return lhs.gpr == rhs.gpr;
|
||||
case PAYLOAD_FPU:
|
||||
return lhs.fpu == rhs.fpu;
|
||||
case PAYLOAD_PACKED_TAG:
|
||||
return lhs.type == rhs.type;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset,
|
||||
uint32_t RVATableSize, uint32_t listSize)
|
||||
: reader_(snapshots + offset, snapshots + listSize),
|
||||
|
@ -503,21 +523,6 @@ SnapshotReader::spewBailingFrom() const
|
|||
}
|
||||
#endif
|
||||
|
||||
// Pad serialized RValueAllocations by a multiple of X bytes in the allocation
|
||||
// buffer. By padding serialized value allocations, we are building an
|
||||
// indexable table of elements of X bytes, and thus we can safely divide any
|
||||
// offset within the buffer by X to obtain an index.
|
||||
//
|
||||
// By padding, we are loosing space within the allocation buffer, but we
|
||||
// multiple by X the number of indexes that we can store on one byte in each
|
||||
// snapshots.
|
||||
//
|
||||
// Some value allocations are taking more than X bytes to be encoded, in which
|
||||
// case we will pad to a multiple of X, and we are wasting indexes. The choice
|
||||
// of X should be balanced between the wasted padding of serialized value
|
||||
// allocation, and the saving made in snapshot indexes.
|
||||
static const size_t ALLOCATION_TABLE_ALIGNMENT = 2; /* bytes */
|
||||
|
||||
RValueAllocation
|
||||
SnapshotReader::readAllocation()
|
||||
{
|
||||
|
@ -606,12 +611,7 @@ SnapshotWriter::add(const RValueAllocation &alloc)
|
|||
uint32_t offset;
|
||||
RValueAllocMap::AddPtr p = allocMap_.lookupForAdd(alloc);
|
||||
if (!p) {
|
||||
// Write 0x7f in all padding bytes.
|
||||
while (allocWriter_.length() % ALLOCATION_TABLE_ALIGNMENT)
|
||||
allocWriter_.writeByte(0x7f);
|
||||
|
||||
offset = allocWriter_.length();
|
||||
JS_ASSERT(offset % ALLOCATION_TABLE_ALIGNMENT == 0);
|
||||
alloc.write(allocWriter_);
|
||||
if (!allocMap_.add(p, alloc, offset))
|
||||
return false;
|
||||
|
|
|
@ -21,51 +21,6 @@ namespace jit {
|
|||
|
||||
class RValueAllocation;
|
||||
|
||||
class Location
|
||||
{
|
||||
friend class RValueAllocation;
|
||||
|
||||
// An offset that is illegal for a local variable's stack allocation.
|
||||
static const int32_t InvalidStackOffset = -1;
|
||||
|
||||
Register::Code reg_;
|
||||
int32_t stackOffset_;
|
||||
|
||||
static Location From(const Register ®) {
|
||||
Location loc;
|
||||
loc.reg_ = reg.code();
|
||||
loc.stackOffset_ = InvalidStackOffset;
|
||||
return loc;
|
||||
}
|
||||
static Location From(int32_t stackOffset) {
|
||||
JS_ASSERT(stackOffset != InvalidStackOffset);
|
||||
Location loc;
|
||||
loc.reg_ = Register::Code(0); // Quell compiler warnings.
|
||||
loc.stackOffset_ = stackOffset;
|
||||
return loc;
|
||||
}
|
||||
|
||||
public:
|
||||
Register reg() const {
|
||||
JS_ASSERT(!isStackOffset());
|
||||
return Register::FromCode(reg_);
|
||||
}
|
||||
int32_t stackOffset() const {
|
||||
JS_ASSERT(isStackOffset());
|
||||
return stackOffset_;
|
||||
}
|
||||
bool isStackOffset() const {
|
||||
return stackOffset_ != InvalidStackOffset;
|
||||
}
|
||||
|
||||
void dump(FILE *fp) const;
|
||||
|
||||
public:
|
||||
bool operator==(const Location &l) const {
|
||||
return reg_ == l.reg_ && stackOffset_ == l.stackOffset_;
|
||||
}
|
||||
};
|
||||
|
||||
// A Recover Value Allocation mirror what is known at compiled time as being the
|
||||
// MIRType and the LAllocation. This is read out of the snapshot to recover the
|
||||
// value which would be there if this frame was an interpreter frame instead of
|
||||
|
@ -73,104 +28,126 @@ class Location
|
|||
//
|
||||
// It is used with the SnapshotIterator to recover a Value from the stack,
|
||||
// spilled registers or the list of constant of the compiled script.
|
||||
//
|
||||
// Unit tests are located in jsapi-tests/testJitRValueAlloc.cpp.
|
||||
class RValueAllocation
|
||||
{
|
||||
public:
|
||||
|
||||
// See RValueAllocation encoding in Snapshots.cpp
|
||||
enum Mode
|
||||
{
|
||||
CONSTANT, // An index into the constant pool.
|
||||
DOUBLE_REG, // Type is double, payload is in a register.
|
||||
FLOAT32_REG, // Type is float32, payload is in a register.
|
||||
FLOAT32_STACK, // Type is float32, payload is on the stack.
|
||||
TYPED_REG, // Type is constant, payload is in a register.
|
||||
TYPED_STACK, // Type is constant, payload is on the stack.
|
||||
CONSTANT = 0x00,
|
||||
CST_UNDEFINED = 0x01,
|
||||
CST_NULL = 0x02,
|
||||
DOUBLE_REG = 0x03,
|
||||
FLOAT32_REG = 0x04,
|
||||
FLOAT32_STACK = 0x05,
|
||||
#if defined(JS_NUNBOX32)
|
||||
UNTYPED_REG_REG, // Type is not known, type & payload are is in
|
||||
// registers.
|
||||
UNTYPED_REG_STACK, // Type is not known, type is in a register and the
|
||||
// payload is on the stack.
|
||||
UNTYPED_STACK_REG, // Type is not known, type is on the stack and the
|
||||
// payload is in a register.
|
||||
UNTYPED_STACK_STACK, // Type is not known, type & payload are on the
|
||||
// stack.
|
||||
UNTYPED_REG_REG = 0x06,
|
||||
UNTYPED_REG_STACK = 0x07,
|
||||
UNTYPED_STACK_REG = 0x08,
|
||||
UNTYPED_STACK_STACK = 0x09,
|
||||
#elif defined(JS_PUNBOX64)
|
||||
UNTYPED_REG, // Type is not known, value is in a register.
|
||||
UNTYPED_STACK, // Type is not known, value is on the stack.
|
||||
UNTYPED_REG = 0x06,
|
||||
UNTYPED_STACK = 0x07,
|
||||
#endif
|
||||
JS_UNDEFINED, // UndefinedValue()
|
||||
JS_NULL, // NullValue()
|
||||
JS_INT32, // Int32Value(n)
|
||||
INVALID,
|
||||
// The JSValueType is packed in the Mode.
|
||||
TYPED_REG_MIN = 0x10,
|
||||
TYPED_REG_MAX = 0x17,
|
||||
TYPED_REG = TYPED_REG_MIN,
|
||||
|
||||
// Assert that the mode is UNTYPED by checking the range.
|
||||
#if defined(JS_NUNBOX32)
|
||||
UNTYPED_MIN = UNTYPED_REG_REG,
|
||||
UNTYPED_MAX = UNTYPED_STACK_STACK
|
||||
#elif defined(JS_PUNBOX64)
|
||||
UNTYPED_MIN = UNTYPED_REG,
|
||||
UNTYPED_MAX = UNTYPED_STACK
|
||||
#endif
|
||||
// The JSValueType is packed in the Mode.
|
||||
TYPED_STACK_MIN = 0x18,
|
||||
TYPED_STACK_MAX = 0x1f,
|
||||
TYPED_STACK = TYPED_STACK_MIN,
|
||||
|
||||
INVALID = 0x100,
|
||||
};
|
||||
|
||||
// See Payload encoding in Snapshots.cpp
|
||||
enum PayloadType {
|
||||
PAYLOAD_NONE,
|
||||
PAYLOAD_INDEX,
|
||||
PAYLOAD_STACK_OFFSET,
|
||||
PAYLOAD_GPR,
|
||||
PAYLOAD_FPU,
|
||||
PAYLOAD_PACKED_TAG
|
||||
};
|
||||
|
||||
struct Layout {
|
||||
PayloadType type1;
|
||||
PayloadType type2;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
private:
|
||||
Mode mode_;
|
||||
|
||||
union {
|
||||
// DOUBLE_REG or FLOAT32_REG
|
||||
FloatRegister::Code fpu_;
|
||||
|
||||
// TYPED_REG or TYPED_STACK or FLOAT32_STACK
|
||||
struct {
|
||||
JSValueType type;
|
||||
Location payload;
|
||||
} known_type_;
|
||||
|
||||
// UNTYPED
|
||||
#if defined(JS_NUNBOX32)
|
||||
struct {
|
||||
Location type;
|
||||
Location payload;
|
||||
} unknown_type_;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
struct {
|
||||
Location value;
|
||||
} unknown_type_;
|
||||
#endif
|
||||
|
||||
// CONSTANT's index or JS_INT32
|
||||
int32_t value_;
|
||||
// Additional information to recover the content of the allocation.
|
||||
union Payload {
|
||||
uint32_t index;
|
||||
int32_t stackOffset;
|
||||
Register gpr;
|
||||
FloatRegister fpu;
|
||||
JSValueType type;
|
||||
};
|
||||
|
||||
RValueAllocation(Mode mode, JSValueType type, const Location &loc)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == TYPED_REG || mode == TYPED_STACK);
|
||||
known_type_.type = type;
|
||||
known_type_.payload = loc;
|
||||
Payload arg1_;
|
||||
Payload arg2_;
|
||||
|
||||
static Payload payloadOfIndex(uint32_t index) {
|
||||
Payload p;
|
||||
p.index = index;
|
||||
return p;
|
||||
}
|
||||
RValueAllocation(Mode mode, const FloatRegister ®)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_REG || mode == DOUBLE_REG);
|
||||
fpu_ = reg.code();
|
||||
static Payload payloadOfStackOffset(int32_t offset) {
|
||||
Payload p;
|
||||
p.stackOffset = offset;
|
||||
return p;
|
||||
}
|
||||
RValueAllocation(Mode mode, const Location &loc)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_STACK);
|
||||
known_type_.payload = loc;
|
||||
static Payload payloadOfRegister(Register reg) {
|
||||
Payload p;
|
||||
p.gpr = reg;
|
||||
return p;
|
||||
}
|
||||
RValueAllocation(Mode mode, int32_t index)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
|
||||
value_ = index;
|
||||
static Payload payloadOfFloatRegister(FloatRegister reg) {
|
||||
Payload p;
|
||||
p.fpu = reg;
|
||||
return p;
|
||||
}
|
||||
static Payload payloadOfValueType(JSValueType type) {
|
||||
Payload p;
|
||||
p.type = type;
|
||||
return p;
|
||||
}
|
||||
|
||||
static const Layout &layoutFromMode(Mode mode);
|
||||
|
||||
static void readPayload(CompactBufferReader &reader, PayloadType t,
|
||||
uint8_t *mode, Payload *p);
|
||||
static void writePayload(CompactBufferWriter &writer, PayloadType t,
|
||||
Payload p);
|
||||
static void writePadding(CompactBufferWriter &writer);
|
||||
static void dumpPayload(FILE *fp, PayloadType t, Payload p);
|
||||
static bool equalPayloads(PayloadType t, Payload lhs, Payload rhs);
|
||||
|
||||
RValueAllocation(Mode mode, Payload a1, Payload a2)
|
||||
: mode_(mode),
|
||||
arg1_(a1),
|
||||
arg2_(a2)
|
||||
{
|
||||
}
|
||||
|
||||
RValueAllocation(Mode mode, Payload a1)
|
||||
: mode_(mode),
|
||||
arg1_(a1)
|
||||
{
|
||||
}
|
||||
|
||||
RValueAllocation(Mode mode)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == JS_UNDEFINED || mode == JS_NULL ||
|
||||
(UNTYPED_MIN <= mode && mode <= UNTYPED_MAX));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -180,15 +157,15 @@ class RValueAllocation
|
|||
|
||||
// DOUBLE_REG
|
||||
static RValueAllocation Double(const FloatRegister ®) {
|
||||
return RValueAllocation(DOUBLE_REG, reg);
|
||||
return RValueAllocation(DOUBLE_REG, payloadOfFloatRegister(reg));
|
||||
}
|
||||
|
||||
// FLOAT32_REG or FLOAT32_STACK
|
||||
static RValueAllocation Float32(const FloatRegister ®) {
|
||||
return RValueAllocation(FLOAT32_REG, reg);
|
||||
return RValueAllocation(FLOAT32_REG, payloadOfFloatRegister(reg));
|
||||
}
|
||||
static RValueAllocation Float32(int32_t stackIndex) {
|
||||
return RValueAllocation(FLOAT32_STACK, Location::From(stackIndex));
|
||||
static RValueAllocation Float32(int32_t offset) {
|
||||
return RValueAllocation(FLOAT32_STACK, payloadOfStackOffset(offset));
|
||||
}
|
||||
|
||||
// TYPED_REG or TYPED_STACK
|
||||
|
@ -197,75 +174,64 @@ class RValueAllocation
|
|||
type != JSVAL_TYPE_MAGIC &&
|
||||
type != JSVAL_TYPE_NULL &&
|
||||
type != JSVAL_TYPE_UNDEFINED);
|
||||
return RValueAllocation(TYPED_REG, type, Location::From(reg));
|
||||
return RValueAllocation(TYPED_REG, payloadOfValueType(type),
|
||||
payloadOfRegister(reg));
|
||||
}
|
||||
static RValueAllocation Typed(JSValueType type, int32_t stackIndex) {
|
||||
static RValueAllocation Typed(JSValueType type, int32_t offset) {
|
||||
JS_ASSERT(type != JSVAL_TYPE_MAGIC &&
|
||||
type != JSVAL_TYPE_NULL &&
|
||||
type != JSVAL_TYPE_UNDEFINED);
|
||||
return RValueAllocation(TYPED_STACK, type, Location::From(stackIndex));
|
||||
return RValueAllocation(TYPED_STACK, payloadOfValueType(type),
|
||||
payloadOfStackOffset(offset));
|
||||
}
|
||||
|
||||
// UNTYPED
|
||||
#if defined(JS_NUNBOX32)
|
||||
static RValueAllocation Untyped(const Register &type, const Register &payload) {
|
||||
RValueAllocation slot(UNTYPED_REG_REG);
|
||||
slot.unknown_type_.type = Location::From(type);
|
||||
slot.unknown_type_.payload = Location::From(payload);
|
||||
return slot;
|
||||
return RValueAllocation(UNTYPED_REG_REG,
|
||||
payloadOfRegister(type),
|
||||
payloadOfRegister(payload));
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(const Register &type, int32_t payloadStackIndex) {
|
||||
RValueAllocation slot(UNTYPED_REG_STACK);
|
||||
slot.unknown_type_.type = Location::From(type);
|
||||
slot.unknown_type_.payload = Location::From(payloadStackIndex);
|
||||
return slot;
|
||||
static RValueAllocation Untyped(const Register &type, int32_t payloadStackOffset) {
|
||||
return RValueAllocation(UNTYPED_REG_STACK,
|
||||
payloadOfRegister(type),
|
||||
payloadOfStackOffset(payloadStackOffset));
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(int32_t typeStackIndex, const Register &payload) {
|
||||
RValueAllocation slot(UNTYPED_STACK_REG);
|
||||
slot.unknown_type_.type = Location::From(typeStackIndex);
|
||||
slot.unknown_type_.payload = Location::From(payload);
|
||||
return slot;
|
||||
static RValueAllocation Untyped(int32_t typeStackOffset, const Register &payload) {
|
||||
return RValueAllocation(UNTYPED_STACK_REG,
|
||||
payloadOfStackOffset(typeStackOffset),
|
||||
payloadOfRegister(payload));
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(int32_t typeStackIndex, int32_t payloadStackIndex) {
|
||||
RValueAllocation slot(UNTYPED_STACK_STACK);
|
||||
slot.unknown_type_.type = Location::From(typeStackIndex);
|
||||
slot.unknown_type_.payload = Location::From(payloadStackIndex);
|
||||
return slot;
|
||||
static RValueAllocation Untyped(int32_t typeStackOffset, int32_t payloadStackOffset) {
|
||||
return RValueAllocation(UNTYPED_STACK_STACK,
|
||||
payloadOfStackOffset(typeStackOffset),
|
||||
payloadOfStackOffset(payloadStackOffset));
|
||||
}
|
||||
|
||||
#elif defined(JS_PUNBOX64)
|
||||
static RValueAllocation Untyped(const Register &value) {
|
||||
RValueAllocation slot(UNTYPED_REG);
|
||||
slot.unknown_type_.value = Location::From(value);
|
||||
return slot;
|
||||
static RValueAllocation Untyped(const Register ®) {
|
||||
return RValueAllocation(UNTYPED_REG, payloadOfRegister(reg));
|
||||
}
|
||||
|
||||
static RValueAllocation Untyped(int32_t stackOffset) {
|
||||
RValueAllocation slot(UNTYPED_STACK);
|
||||
slot.unknown_type_.value = Location::From(stackOffset);
|
||||
return slot;
|
||||
return RValueAllocation(UNTYPED_STACK, payloadOfStackOffset(stackOffset));
|
||||
}
|
||||
#endif
|
||||
|
||||
// common constants.
|
||||
static RValueAllocation Undefined() {
|
||||
return RValueAllocation(JS_UNDEFINED);
|
||||
return RValueAllocation(CST_UNDEFINED);
|
||||
}
|
||||
static RValueAllocation Null() {
|
||||
return RValueAllocation(JS_NULL);
|
||||
}
|
||||
|
||||
// JS_INT32
|
||||
static RValueAllocation Int32(int32_t value) {
|
||||
return RValueAllocation(JS_INT32, value);
|
||||
return RValueAllocation(CST_NULL);
|
||||
}
|
||||
|
||||
// CONSTANT's index
|
||||
static RValueAllocation ConstantPool(uint32_t index) {
|
||||
return RValueAllocation(CONSTANT, int32_t(index));
|
||||
return RValueAllocation(CONSTANT, payloadOfIndex(index));
|
||||
}
|
||||
|
||||
void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
|
||||
|
@ -277,83 +243,48 @@ class RValueAllocation
|
|||
Mode mode() const {
|
||||
return mode_;
|
||||
}
|
||||
uint32_t constantIndex() const {
|
||||
JS_ASSERT(mode() == CONSTANT);
|
||||
return value_;
|
||||
}
|
||||
int32_t int32Value() const {
|
||||
JS_ASSERT(mode() == JS_INT32);
|
||||
return value_;
|
||||
}
|
||||
JSValueType knownType() const {
|
||||
JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
|
||||
return known_type_.type;
|
||||
}
|
||||
Register reg() const {
|
||||
JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
|
||||
return known_type_.payload.reg();
|
||||
}
|
||||
FloatRegister floatReg() const {
|
||||
JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
|
||||
return FloatRegister::FromCode(fpu_);
|
||||
|
||||
uint32_t index() const {
|
||||
JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_INDEX);
|
||||
return arg1_.index;
|
||||
}
|
||||
int32_t stackOffset() const {
|
||||
JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
|
||||
return known_type_.payload.stackOffset();
|
||||
JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_STACK_OFFSET);
|
||||
return arg1_.stackOffset;
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
Location payload() const {
|
||||
JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
|
||||
return unknown_type_.payload;
|
||||
Register reg() const {
|
||||
JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_GPR);
|
||||
return arg1_.gpr;
|
||||
}
|
||||
Location type() const {
|
||||
JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
|
||||
return unknown_type_.type;
|
||||
FloatRegister fpuReg() const {
|
||||
JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_FPU);
|
||||
return arg1_.fpu;
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
Location value() const {
|
||||
JS_ASSERT((UNTYPED_MIN <= mode() && mode() <= UNTYPED_MAX));
|
||||
return unknown_type_.value;
|
||||
JSValueType knownType() const {
|
||||
JS_ASSERT(layoutFromMode(mode()).type1 == PAYLOAD_PACKED_TAG);
|
||||
return arg1_.type;
|
||||
}
|
||||
|
||||
int32_t stackOffset2() const {
|
||||
JS_ASSERT(layoutFromMode(mode()).type2 == PAYLOAD_STACK_OFFSET);
|
||||
return arg2_.stackOffset;
|
||||
}
|
||||
Register reg2() const {
|
||||
JS_ASSERT(layoutFromMode(mode()).type2 == PAYLOAD_GPR);
|
||||
return arg2_.gpr;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
const char *modeToString() const;
|
||||
void dump(FILE *fp) const;
|
||||
void dump() const;
|
||||
|
||||
public:
|
||||
bool operator==(const RValueAllocation &s) const {
|
||||
if (mode_ != s.mode_)
|
||||
bool operator==(const RValueAllocation &rhs) const {
|
||||
if (mode_ != rhs.mode_)
|
||||
return false;
|
||||
|
||||
switch (mode_) {
|
||||
case DOUBLE_REG:
|
||||
case FLOAT32_REG:
|
||||
return fpu_ == s.fpu_;
|
||||
case TYPED_REG:
|
||||
case TYPED_STACK:
|
||||
case FLOAT32_STACK:
|
||||
return known_type_.type == s.known_type_.type &&
|
||||
known_type_.payload == s.known_type_.payload;
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG:
|
||||
case UNTYPED_REG_STACK:
|
||||
case UNTYPED_STACK_REG:
|
||||
case UNTYPED_STACK_STACK:
|
||||
return unknown_type_.type == s.unknown_type_.type &&
|
||||
unknown_type_.payload == s.unknown_type_.payload;
|
||||
#else
|
||||
case UNTYPED_REG:
|
||||
case UNTYPED_STACK:
|
||||
return unknown_type_.value == s.unknown_type_.value;
|
||||
#endif
|
||||
case CONSTANT:
|
||||
case JS_INT32:
|
||||
return value_ == s.value_;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
const Layout &layout = layoutFromMode(mode());
|
||||
return equalPayloads(layout.type1, arg1_, rhs.arg1_) &&
|
||||
equalPayloads(layout.type2, arg2_, rhs.arg2_);
|
||||
}
|
||||
|
||||
HashNumber hash() const;
|
||||
|
|
|
@ -180,17 +180,10 @@ CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resume
|
|||
alloc = RValueAllocation::Double(reg);
|
||||
} else {
|
||||
MConstant *constant = mir->toConstant();
|
||||
const Value &v = constant->value();
|
||||
|
||||
// Don't bother with the constant pool for smallish integers.
|
||||
if (v.isInt32() && v.toInt32() >= -32 && v.toInt32() <= 32) {
|
||||
alloc = RValueAllocation::Int32(v.toInt32());
|
||||
} else {
|
||||
uint32_t index;
|
||||
if (!graph.addConstantToPool(constant->value(), &index))
|
||||
return false;
|
||||
alloc = RValueAllocation::ConstantPool(index);
|
||||
}
|
||||
uint32_t index;
|
||||
if (!graph.addConstantToPool(constant->value(), &index))
|
||||
return false;
|
||||
alloc = RValueAllocation::ConstantPool(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -214,18 +214,6 @@ BEGIN_TEST(testJitRValueAlloc_UndefinedAndNull)
|
|||
}
|
||||
END_TEST(testJitRValueAlloc_UndefinedAndNull)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_Int32)
|
||||
{
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = RValueAllocation::Int32(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitRValueAlloc_Int32)
|
||||
|
||||
BEGIN_TEST(testJitRValueAlloc_ConstantPool)
|
||||
{
|
||||
RValueAllocation s;
|
||||
|
|
Загрузка…
Ссылка в новой задаче