зеркало из https://github.com/mozilla/gecko-dev.git
Bug 962555 part 4 - Merge Headers and rename Slot to RValueAllocation. r=h4writer
--HG-- rename : js/src/jit/Slot.h => js/src/jit/Snapshots.h rename : js/src/jsapi-tests/testJitSlot.cpp => js/src/jsapi-tests/testJitRValueAlloc.cpp
This commit is contained in:
Родитель
226cc7f3b7
Коммит
2aadd38210
|
@ -12,7 +12,7 @@
|
|||
#include "jit/Ion.h"
|
||||
#include "jit/IonSpewer.h"
|
||||
#include "jit/JitCompartment.h"
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
#include "jit/IonFrameIterator-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
|
|
@ -91,9 +91,6 @@ namespace jit {
|
|||
|
||||
static const BailoutId INVALID_BAILOUT_ID = BailoutId(-1);
|
||||
|
||||
static const uint32_t BAILOUT_KIND_BITS = 3;
|
||||
static const uint32_t BAILOUT_RESUME_BITS = 1;
|
||||
|
||||
// Keep this arbitrarily small for now, for testing.
|
||||
static const uint32_t BAILOUT_TABLE_SIZE = 16;
|
||||
|
||||
|
|
|
@ -475,7 +475,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
if (excInfo)
|
||||
exprStackSlots = excInfo->numExprSlots;
|
||||
else
|
||||
exprStackSlots = iter.slots() - (script->nfixed() + CountArgSlots(script, fun));
|
||||
exprStackSlots = iter.allocations() - (script->nfixed() + CountArgSlots(script, fun));
|
||||
|
||||
builder.resetFramePushed();
|
||||
|
||||
|
@ -623,9 +623,9 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
|
||||
*builder.valuePointerAtStackOffset(thisvOffset) = thisv;
|
||||
|
||||
JS_ASSERT(iter.slots() >= CountArgSlots(script, fun));
|
||||
JS_ASSERT(iter.allocations() >= CountArgSlots(script, fun));
|
||||
IonSpew(IonSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u",
|
||||
iter.slots(), fun->nargs(), script->nfixed());
|
||||
iter.allocations(), fun->nargs(), script->nfixed());
|
||||
|
||||
if (!callerPC) {
|
||||
// This is the first frame. Store the formals in a Vector until we
|
||||
|
|
|
@ -28,14 +28,6 @@ class AsmJSModule;
|
|||
|
||||
namespace jit {
|
||||
|
||||
// The maximum size of any buffer associated with an assembler or code object.
|
||||
// This is chosen to not overflow a signed integer, leaving room for an extra
|
||||
// bit on offsets.
|
||||
static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
|
||||
|
||||
// Maximum number of scripted arg slots.
|
||||
static const uint32_t SNAPSHOT_MAX_NARGS = 127;
|
||||
|
||||
class MacroAssembler;
|
||||
class CodeOffsetLabel;
|
||||
class PatchableBackedge;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "jstypes.h"
|
||||
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
namespace js {
|
||||
class ActivationIterator;
|
||||
|
@ -245,9 +245,9 @@ class SnapshotIterator : public SnapshotReader
|
|||
bool hasStack(const Location &loc);
|
||||
uintptr_t fromStack(const Location &loc);
|
||||
|
||||
Value slotValue(const Slot &slot);
|
||||
bool slotReadable(const Slot &slot);
|
||||
void warnUnreadableSlot();
|
||||
Value allocationValue(const RValueAllocation &a);
|
||||
bool allocationReadable(const RValueAllocation &a);
|
||||
void warnUnreadableAllocation();
|
||||
|
||||
public:
|
||||
SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
|
||||
|
@ -256,15 +256,19 @@ class SnapshotIterator : public SnapshotReader
|
|||
SnapshotIterator(const IonBailoutIterator &iter);
|
||||
SnapshotIterator();
|
||||
|
||||
Value skip() {
|
||||
readAllocation();
|
||||
return UndefinedValue();
|
||||
}
|
||||
Value read() {
|
||||
return slotValue(readSlot());
|
||||
return allocationValue(readAllocation());
|
||||
}
|
||||
Value maybeRead(bool silentFailure = false) {
|
||||
Slot s = readSlot();
|
||||
if (slotReadable(s))
|
||||
return slotValue(s);
|
||||
RValueAllocation a = readAllocation();
|
||||
if (allocationReadable(a))
|
||||
return allocationValue(a);
|
||||
if (!silentFailure)
|
||||
warnUnreadableSlot();
|
||||
warnUnreadableAllocation();
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
|
@ -308,15 +312,15 @@ class SnapshotIterator : public SnapshotReader
|
|||
}
|
||||
}
|
||||
|
||||
Value maybeReadSlotByIndex(size_t index) {
|
||||
Value maybeReadAllocByIndex(size_t index) {
|
||||
while (index--) {
|
||||
JS_ASSERT(moreSlots());
|
||||
JS_ASSERT(moreAllocations());
|
||||
skip();
|
||||
}
|
||||
|
||||
Value s = maybeRead(true);
|
||||
|
||||
while (moreSlots())
|
||||
while (moreAllocations())
|
||||
skip();
|
||||
|
||||
return s;
|
||||
|
@ -427,8 +431,8 @@ class InlineFrameIteratorMaybeGC
|
|||
|
||||
// Skip over all slots untill we get to the last slots (= arguments slots of callee)
|
||||
// the +3 is for [this], [returnvalue], [scopechain], and maybe +1 for [argsObj]
|
||||
JS_ASSERT(parent_s.slots() >= nactual + 3 + argsObjAdj);
|
||||
unsigned skip = parent_s.slots() - nactual - 3 - argsObjAdj;
|
||||
JS_ASSERT(parent_s.allocations() >= nactual + 3 + argsObjAdj);
|
||||
unsigned skip = parent_s.allocations() - nactual - 3 - argsObjAdj;
|
||||
for (unsigned j = 0; j < skip; j++)
|
||||
parent_s.skip();
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "jit/ParallelFunctions.h"
|
||||
#include "jit/PcScriptCache.h"
|
||||
#include "jit/Safepoints.h"
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/Snapshots.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
@ -1333,14 +1333,14 @@ SnapshotIterator::fromRegister(const Location &loc)
|
|||
bool
|
||||
SnapshotIterator::hasStack(const Location &loc)
|
||||
{
|
||||
JS_ASSERT(loc.isStackSlot());
|
||||
JS_ASSERT(loc.isStackOffset());
|
||||
return true;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
SnapshotIterator::fromStack(const Location &loc)
|
||||
{
|
||||
return ReadFrameSlot(fp_, loc.stackSlot());
|
||||
return ReadFrameSlot(fp_, loc.stackOffset());
|
||||
}
|
||||
|
||||
static Value
|
||||
|
@ -1373,29 +1373,29 @@ FromTypedPayload(JSValueType type, uintptr_t payload)
|
|||
}
|
||||
|
||||
bool
|
||||
SnapshotIterator::slotReadable(const Slot &slot)
|
||||
SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
|
||||
{
|
||||
switch (slot.mode()) {
|
||||
case Slot::DOUBLE_REG:
|
||||
return machine_.has(slot.floatReg());
|
||||
switch (alloc.mode()) {
|
||||
case RValueAllocation::DOUBLE_REG:
|
||||
return machine_.has(alloc.floatReg());
|
||||
|
||||
case Slot::TYPED_REG:
|
||||
return machine_.has(slot.reg());
|
||||
case RValueAllocation::TYPED_REG:
|
||||
return machine_.has(alloc.reg());
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
case Slot::UNTYPED_REG_REG:
|
||||
return hasRegister(slot.type()) && hasRegister(slot.payload());
|
||||
case Slot::UNTYPED_REG_STACK:
|
||||
return hasRegister(slot.type()) && hasStack(slot.payload());
|
||||
case Slot::UNTYPED_STACK_REG:
|
||||
return hasStack(slot.type()) && hasRegister(slot.payload());
|
||||
case Slot::UNTYPED_STACK_STACK:
|
||||
return hasStack(slot.type()) && hasStack(slot.payload());
|
||||
case RValueAllocation::UNTYPED_REG_REG:
|
||||
return hasRegister(alloc.type()) && hasRegister(alloc.payload());
|
||||
case RValueAllocation::UNTYPED_REG_STACK:
|
||||
return hasRegister(alloc.type()) && hasStack(alloc.payload());
|
||||
case RValueAllocation::UNTYPED_STACK_REG:
|
||||
return hasStack(alloc.type()) && hasRegister(alloc.payload());
|
||||
case RValueAllocation::UNTYPED_STACK_STACK:
|
||||
return hasStack(alloc.type()) && hasStack(alloc.payload());
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case Slot::UNTYPED_REG:
|
||||
return hasRegister(slot.value());
|
||||
case Slot::UNTYPED_STACK:
|
||||
return hasStack(slot.value());
|
||||
case RValueAllocation::UNTYPED_REG:
|
||||
return hasRegister(alloc.value());
|
||||
case RValueAllocation::UNTYPED_STACK:
|
||||
return hasStack(alloc.value());
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
@ -1404,107 +1404,107 @@ SnapshotIterator::slotReadable(const Slot &slot)
|
|||
}
|
||||
|
||||
Value
|
||||
SnapshotIterator::slotValue(const Slot &slot)
|
||||
SnapshotIterator::allocationValue(const RValueAllocation &alloc)
|
||||
{
|
||||
switch (slot.mode()) {
|
||||
case Slot::DOUBLE_REG:
|
||||
return DoubleValue(machine_.read(slot.floatReg()));
|
||||
switch (alloc.mode()) {
|
||||
case RValueAllocation::DOUBLE_REG:
|
||||
return DoubleValue(machine_.read(alloc.floatReg()));
|
||||
|
||||
case Slot::FLOAT32_REG:
|
||||
case RValueAllocation::FLOAT32_REG:
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
float f;
|
||||
} pun;
|
||||
pun.d = machine_.read(slot.floatReg());
|
||||
pun.d = machine_.read(alloc.floatReg());
|
||||
// The register contains the encoding of a float32. We just read
|
||||
// the bits without making any conversion.
|
||||
return Float32Value(pun.f);
|
||||
}
|
||||
|
||||
case Slot::FLOAT32_STACK:
|
||||
return Float32Value(ReadFrameFloat32Slot(fp_, slot.stackSlot()));
|
||||
case RValueAllocation::FLOAT32_STACK:
|
||||
return Float32Value(ReadFrameFloat32Slot(fp_, alloc.stackOffset()));
|
||||
|
||||
case Slot::TYPED_REG:
|
||||
return FromTypedPayload(slot.knownType(), machine_.read(slot.reg()));
|
||||
case RValueAllocation::TYPED_REG:
|
||||
return FromTypedPayload(alloc.knownType(), machine_.read(alloc.reg()));
|
||||
|
||||
case Slot::TYPED_STACK:
|
||||
case RValueAllocation::TYPED_STACK:
|
||||
{
|
||||
switch (slot.knownType()) {
|
||||
switch (alloc.knownType()) {
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
return DoubleValue(ReadFrameDoubleSlot(fp_, slot.stackSlot()));
|
||||
return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_INT32:
|
||||
return Int32Value(ReadFrameInt32Slot(fp_, slot.stackSlot()));
|
||||
return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
return BooleanValue(ReadFrameBooleanSlot(fp_, slot.stackSlot()));
|
||||
return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_STRING:
|
||||
return FromStringPayload(ReadFrameSlot(fp_, slot.stackSlot()));
|
||||
return FromStringPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return FromObjectPayload(ReadFrameSlot(fp_, slot.stackSlot()));
|
||||
return FromObjectPayload(ReadFrameSlot(fp_, alloc.stackOffset()));
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unexpected type");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
case Slot::UNTYPED_REG_REG:
|
||||
case RValueAllocation::UNTYPED_REG_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromRegister(slot.type());
|
||||
layout.s.payload.word = fromRegister(slot.payload());
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.type());
|
||||
layout.s.payload.word = fromRegister(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case Slot::UNTYPED_REG_STACK:
|
||||
case RValueAllocation::UNTYPED_REG_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromRegister(slot.type());
|
||||
layout.s.payload.word = fromStack(slot.payload());
|
||||
layout.s.tag = (JSValueTag) fromRegister(alloc.type());
|
||||
layout.s.payload.word = fromStack(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case Slot::UNTYPED_STACK_REG:
|
||||
case RValueAllocation::UNTYPED_STACK_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromStack(slot.type());
|
||||
layout.s.payload.word = fromRegister(slot.payload());
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.type());
|
||||
layout.s.payload.word = fromRegister(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case Slot::UNTYPED_STACK_STACK:
|
||||
case RValueAllocation::UNTYPED_STACK_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.s.tag = (JSValueTag) fromStack(slot.type());
|
||||
layout.s.payload.word = fromStack(slot.payload());
|
||||
layout.s.tag = (JSValueTag) fromStack(alloc.type());
|
||||
layout.s.payload.word = fromStack(alloc.payload());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case Slot::UNTYPED_REG:
|
||||
case RValueAllocation::UNTYPED_REG:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.asBits = fromRegister(slot.value());
|
||||
layout.asBits = fromRegister(alloc.value());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
|
||||
case Slot::UNTYPED_STACK:
|
||||
case RValueAllocation::UNTYPED_STACK:
|
||||
{
|
||||
jsval_layout layout;
|
||||
layout.asBits = fromStack(slot.value());
|
||||
layout.asBits = fromStack(alloc.value());
|
||||
return IMPL_TO_JSVAL(layout);
|
||||
}
|
||||
#endif
|
||||
|
||||
case Slot::JS_UNDEFINED:
|
||||
case RValueAllocation::JS_UNDEFINED:
|
||||
return UndefinedValue();
|
||||
|
||||
case Slot::JS_NULL:
|
||||
case RValueAllocation::JS_NULL:
|
||||
return NullValue();
|
||||
|
||||
case Slot::JS_INT32:
|
||||
return Int32Value(slot.int32Value());
|
||||
case RValueAllocation::JS_INT32:
|
||||
return Int32Value(alloc.int32Value());
|
||||
|
||||
case Slot::CONSTANT:
|
||||
return ionScript_->getConstant(slot.constantIndex());
|
||||
case RValueAllocation::CONSTANT:
|
||||
return ionScript_->getConstant(alloc.constantIndex());
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
|
@ -1595,14 +1595,14 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
|
|||
JS_ASSERT(numActualArgs_ != 0xbadbad);
|
||||
|
||||
// Skip over non-argument slots, as well as |this|.
|
||||
unsigned skipCount = (si_.slots() - 1) - numActualArgs_ - 1;
|
||||
unsigned skipCount = (si_.allocations() - 1) - numActualArgs_ - 1;
|
||||
for (unsigned j = 0; j < skipCount; j++)
|
||||
si_.skip();
|
||||
|
||||
Value funval = si_.read();
|
||||
|
||||
// Skip extra slots.
|
||||
while (si_.moreSlots())
|
||||
// Skip extra value allocations.
|
||||
while (si_.moreAllocations())
|
||||
si_.skip();
|
||||
|
||||
si_.nextFrame();
|
||||
|
@ -1721,9 +1721,9 @@ IonFrameIterator::numActualArgs() const
|
|||
}
|
||||
|
||||
void
|
||||
SnapshotIterator::warnUnreadableSlot()
|
||||
SnapshotIterator::warnUnreadableAllocation()
|
||||
{
|
||||
fprintf(stderr, "Warning! Tried to access unreadable IonMonkey slot (possible f.arguments).\n");
|
||||
fprintf(stderr, "Warning! Tried to access unreadable value allocation (possible f.arguments).\n");
|
||||
}
|
||||
|
||||
struct DumpOp {
|
||||
|
@ -1817,8 +1817,8 @@ InlineFrameIteratorMaybeGC<allowGC>::dump() const
|
|||
}
|
||||
|
||||
SnapshotIterator si = snapshotIterator();
|
||||
fprintf(stderr, " slots: %u\n", si.slots() - 1);
|
||||
for (unsigned i = 0; i < si.slots() - 1; i++) {
|
||||
fprintf(stderr, " slots: %u\n", si.allocations() - 1);
|
||||
for (unsigned i = 0; i < si.allocations() - 1; i++) {
|
||||
if (isFunction) {
|
||||
if (i == 0)
|
||||
fprintf(stderr, " scope chain: ");
|
||||
|
|
|
@ -17,6 +17,14 @@ namespace jit {
|
|||
typedef uint32_t SnapshotOffset;
|
||||
typedef uint32_t BailoutId;
|
||||
|
||||
// The maximum size of any buffer associated with an assembler or code object.
|
||||
// This is chosen to not overflow a signed integer, leaving room for an extra
|
||||
// bit on offsets.
|
||||
static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
|
||||
|
||||
// Maximum number of scripted arg slots.
|
||||
static const uint32_t SNAPSHOT_MAX_NARGS = 127;
|
||||
|
||||
static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
|
||||
|
||||
// Different kinds of bailouts. When extending this enum, make sure to check
|
||||
|
@ -41,6 +49,9 @@ enum BailoutKind
|
|||
Bailout_BaselineInfo
|
||||
};
|
||||
|
||||
static const uint32_t BAILOUT_KIND_BITS = 3;
|
||||
static const uint32_t BAILOUT_RESUME_BITS = 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
inline const char *
|
||||
BailoutKindString(BailoutKind kind)
|
||||
|
|
|
@ -1,385 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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 "jit/Slot.h"
|
||||
|
||||
#include "jit/CompactBuffer.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
// [slot] Information on how to reify a js::Value from an Ion frame. The
|
||||
// first byte is split as thus:
|
||||
// Bits 0-2: JSValueType
|
||||
// Bits 3-7: 5-bit register code ("reg").
|
||||
//
|
||||
// JSVAL_TYPE_DOUBLE:
|
||||
// If "reg" is InvalidFloatReg, this byte is followed by a
|
||||
// [vws] stack offset. Otherwise, "reg" encodes an XMM register.
|
||||
//
|
||||
// JSVAL_TYPE_INT32:
|
||||
// JSVAL_TYPE_OBJECT:
|
||||
// JSVAL_TYPE_BOOLEAN:
|
||||
// JSVAL_TYPE_STRING:
|
||||
// If "reg" is InvalidReg1, this byte is followed by a [vws]
|
||||
// stack offset. Otherwise, "reg" encodes a GPR register.
|
||||
//
|
||||
// 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])
|
||||
//
|
||||
// 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()
|
||||
//
|
||||
// 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 InvalidReg1: byte is followed by a [vws] stack
|
||||
// offset containing a Value.
|
||||
//
|
||||
// Otherwise, "reg" is a register containing a Value.
|
||||
//
|
||||
|
||||
#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;
|
||||
#endif
|
||||
|
||||
static const uint32_t MAX_TYPE_FIELD_VALUE = 7;
|
||||
|
||||
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;
|
||||
|
||||
Slot
|
||||
Slot::read(CompactBufferReader &reader)
|
||||
{
|
||||
uint8_t b = reader.readByte();
|
||||
|
||||
JSValueType type = JSValueType(b & 0x7);
|
||||
uint32_t code = b >> 3;
|
||||
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return DoubleSlot(FloatRegister::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return TypedSlot(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 TypedSlot(type, Register::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return TypedSlot(type, reader.readSigned());
|
||||
|
||||
case JSVAL_TYPE_NULL:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return NullSlot();
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return Int32Slot(reader.readSigned());
|
||||
if (code == ESC_REG_FIELD_FLOAT32_REG)
|
||||
return Float32Slot(FloatRegister::FromCode(reader.readUnsigned()));
|
||||
if (code == ESC_REG_FIELD_FLOAT32_STACK)
|
||||
return Float32Slot(reader.readSigned());
|
||||
return Int32Slot(code);
|
||||
|
||||
case JSVAL_TYPE_UNDEFINED:
|
||||
if (code == ESC_REG_FIELD_CONST)
|
||||
return UndefinedSlot();
|
||||
if (code == ESC_REG_FIELD_INDEX)
|
||||
return ConstantPoolSlot(reader.readUnsigned());
|
||||
return ConstantPoolSlot(code);
|
||||
|
||||
case JSVAL_TYPE_MAGIC:
|
||||
{
|
||||
if (code == ESC_REG_FIELD_CONST) {
|
||||
uint8_t reg2 = reader.readUnsigned();
|
||||
if (reg2 != ESC_REG_FIELD_INDEX)
|
||||
return TypedSlot(type, Register::FromCode(reg2));
|
||||
return TypedSlot(type, reader.readSigned());
|
||||
}
|
||||
|
||||
#ifdef JS_NUNBOX32
|
||||
int32_t type, payload;
|
||||
switch (code) {
|
||||
case NUNBOX32_STACK_STACK:
|
||||
type = reader.readSigned();
|
||||
payload = reader.readSigned();
|
||||
return UntypedSlot(type, payload);
|
||||
case NUNBOX32_STACK_REG:
|
||||
type = reader.readSigned();
|
||||
payload = reader.readByte();
|
||||
return UntypedSlot(type, Register::FromCode(payload));
|
||||
case NUNBOX32_REG_STACK:
|
||||
type = reader.readByte();
|
||||
payload = reader.readSigned();
|
||||
return UntypedSlot(Register::FromCode(type), payload);
|
||||
case NUNBOX32_REG_REG:
|
||||
type = reader.readByte();
|
||||
payload = reader.readByte();
|
||||
return UntypedSlot(Register::FromCode(type),
|
||||
Register::FromCode(payload));
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("bad code");
|
||||
break;
|
||||
}
|
||||
#elif JS_PUNBOX64
|
||||
if (code < MIN_REG_FIELD_ESC)
|
||||
return UntypedSlot(Register::FromCode(code));
|
||||
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
|
||||
return UntypedSlot(reader.readSigned());
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("bad type");
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("huh?");
|
||||
}
|
||||
|
||||
void
|
||||
Slot::writeSlotHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const
|
||||
{
|
||||
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);
|
||||
|
||||
uint8_t byte = uint32_t(type) | (regCode << 3);
|
||||
writer.writeByte(byte);
|
||||
}
|
||||
|
||||
void
|
||||
Slot::write(CompactBufferWriter &writer) const
|
||||
{
|
||||
switch (mode()) {
|
||||
case CONSTANT: {
|
||||
if (constantIndex() < MIN_REG_FIELD_ESC) {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_UNDEFINED, constantIndex());
|
||||
} else {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_INDEX);
|
||||
writer.writeUnsigned(constantIndex());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DOUBLE_REG: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_DOUBLE, floatReg().code());
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOAT32_REG: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_REG);
|
||||
writer.writeUnsigned(floatReg().code());
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOAT32_STACK: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_STACK);
|
||||
writer.writeSigned(stackSlot());
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPED_REG: {
|
||||
writeSlotHeader(writer, knownType(), reg().code());
|
||||
break;
|
||||
}
|
||||
case TYPED_STACK: {
|
||||
writeSlotHeader(writer, knownType(), ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(stackSlot());
|
||||
break;
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
case UNTYPED_REG_REG: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
|
||||
writer.writeByte(type().reg().code());
|
||||
writer.writeByte(payload().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_REG_STACK: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_REG_STACK);
|
||||
writer.writeByte(type().reg().code());
|
||||
writer.writeSigned(payload().stackSlot());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK_REG: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_REG);
|
||||
writer.writeSigned(type().stackSlot());
|
||||
writer.writeByte(payload().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK_STACK: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, NUNBOX32_STACK_STACK);
|
||||
writer.writeSigned(type().stackSlot());
|
||||
writer.writeSigned(payload().stackSlot());
|
||||
break;
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case UNTYPED_REG: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, value().reg().code());
|
||||
break;
|
||||
}
|
||||
case UNTYPED_STACK: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(value().stackSlot());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case JS_UNDEFINED: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_CONST);
|
||||
break;
|
||||
}
|
||||
case JS_NULL: {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_CONST);
|
||||
break;
|
||||
}
|
||||
case JS_INT32: {
|
||||
if (int32Value() >= 0 && uint32_t(int32Value()) < MIN_REG_FIELD_ESC) {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_NULL, int32Value());
|
||||
} else {
|
||||
writeSlotHeader(writer, JSVAL_TYPE_NULL, ESC_REG_FIELD_INDEX);
|
||||
writer.writeSigned(int32Value());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INVALID: {
|
||||
MOZ_ASSUME_UNREACHABLE("not initialized");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Location::dump(FILE *fp) const
|
||||
{
|
||||
if (isStackSlot())
|
||||
fprintf(fp, "stack %d", stackSlot());
|
||||
else
|
||||
fprintf(fp, "reg %s", reg().name());
|
||||
}
|
||||
|
||||
static const char *
|
||||
ValTypeToString(JSValueType type)
|
||||
{
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_INT32:
|
||||
return "int32_t";
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
return "double";
|
||||
case JSVAL_TYPE_STRING:
|
||||
return "string";
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
return "boolean";
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return "object";
|
||||
case JSVAL_TYPE_MAGIC:
|
||||
return "magic";
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("no payload");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Slot::dump(FILE *fp) const
|
||||
{
|
||||
switch (mode()) {
|
||||
case CONSTANT:
|
||||
fprintf(fp, "constant (pool index %u)", constantIndex());
|
||||
break;
|
||||
|
||||
case DOUBLE_REG:
|
||||
fprintf(fp, "double (reg %s)", floatReg().name());
|
||||
break;
|
||||
|
||||
case FLOAT32_REG:
|
||||
fprintf(fp, "float32 (reg %s)", floatReg().name());
|
||||
break;
|
||||
|
||||
case FLOAT32_STACK:
|
||||
fprintf(fp, "float32 (");
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
|
||||
case TYPED_REG:
|
||||
case TYPED_STACK:
|
||||
fprintf(fp, "%s (", ValTypeToString(knownType()));
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
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");
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef jit_SnapshotReader_h
|
||||
#define jit_SnapshotReader_h
|
||||
|
||||
#include "jit/CompactBuffer.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/IonTypes.h"
|
||||
#include "jit/Registers.h"
|
||||
#include "jit/Slot.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
class LInstruction;
|
||||
#endif
|
||||
|
||||
// A snapshot reader reads the entries out of the compressed snapshot buffer in
|
||||
// a script. These entries describe the stack state of an Ion frame at a given
|
||||
// position in JIT code.
|
||||
class SnapshotReader
|
||||
{
|
||||
CompactBufferReader reader_;
|
||||
|
||||
uint32_t pcOffset_; // Offset from script->code.
|
||||
uint32_t slotCount_; // Number of slots.
|
||||
uint32_t frameCount_;
|
||||
BailoutKind bailoutKind_;
|
||||
uint32_t framesRead_; // Number of frame headers that have been read.
|
||||
uint32_t slotsRead_; // Number of slots that have been read.
|
||||
bool resumeAfter_;
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
private:
|
||||
uint32_t pcOpcode_;
|
||||
uint32_t mirOpcode_;
|
||||
uint32_t mirId_;
|
||||
uint32_t lirOpcode_;
|
||||
uint32_t lirId_;
|
||||
public:
|
||||
void spewBailingFrom() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void readSnapshotHeader();
|
||||
void readFrameHeader();
|
||||
|
||||
public:
|
||||
SnapshotReader(const uint8_t *buffer, const uint8_t *end);
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
}
|
||||
uint32_t slots() const {
|
||||
return slotCount_;
|
||||
}
|
||||
BailoutKind bailoutKind() const {
|
||||
return bailoutKind_;
|
||||
}
|
||||
bool resumeAfter() const {
|
||||
if (moreFrames())
|
||||
return false;
|
||||
return resumeAfter_;
|
||||
}
|
||||
bool moreFrames() const {
|
||||
return framesRead_ < frameCount_;
|
||||
}
|
||||
void nextFrame() {
|
||||
readFrameHeader();
|
||||
}
|
||||
Slot readSlot();
|
||||
|
||||
Value skip() {
|
||||
readSlot();
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
bool moreSlots() const {
|
||||
return slotsRead_ < slotCount_;
|
||||
}
|
||||
uint32_t frameCount() const {
|
||||
return frameCount_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* jit_SnapshotReader_h */
|
|
@ -1,62 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef jit_SnapshotWriter_h
|
||||
#define jit_SnapshotWriter_h
|
||||
|
||||
#include "jit/Bailouts.h"
|
||||
#include "jit/CompactBuffer.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/Registers.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
// Collects snapshots in a contiguous buffer, which is copied into IonScript
|
||||
// memory after code generation.
|
||||
class SnapshotWriter
|
||||
{
|
||||
CompactBufferWriter writer_;
|
||||
|
||||
// These are only used to assert sanity.
|
||||
uint32_t nslots_;
|
||||
uint32_t slotsWritten_;
|
||||
uint32_t nframes_;
|
||||
uint32_t framesWritten_;
|
||||
SnapshotOffset lastStart_;
|
||||
|
||||
void writeSlotHeader(JSValueType type, uint32_t regCode);
|
||||
|
||||
public:
|
||||
SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
|
||||
void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
void trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
|
||||
uint32_t lirOpcode, uint32_t lirId);
|
||||
#endif
|
||||
void endFrame();
|
||||
|
||||
void addSlot(const Slot &slot);
|
||||
|
||||
void endSnapshot();
|
||||
|
||||
bool oom() const {
|
||||
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return writer_.length();
|
||||
}
|
||||
const uint8_t *buffer() const {
|
||||
return writer_.buffer();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* jit_SnapshotWriter_h */
|
|
@ -4,15 +4,16 @@
|
|||
* 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 "jit/Snapshots.h"
|
||||
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "jit/CompileInfo.h"
|
||||
#include "jit/IonSpewer.h"
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
#include "jit/LIR.h"
|
||||
#include "jit/MIR.h"
|
||||
# include "jit/LIR.h"
|
||||
# include "jit/MIR.h"
|
||||
#endif
|
||||
#include "jit/SnapshotReader.h"
|
||||
#include "jit/SnapshotWriter.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
@ -28,15 +29,16 @@ using namespace js::jit;
|
|||
// [ptr] Debug only: JSScript *
|
||||
// [vwu] pc offset
|
||||
// [vwu] # of slots, including nargs
|
||||
// [slot*] N slot entries, where N = nargs + nfixed + stackDepth
|
||||
// [rva*] N recover value allocations entries,
|
||||
// where N = nargs + nfixed + stackDepth
|
||||
//
|
||||
// Encodings:
|
||||
// [ptr] A fixed-size pointer.
|
||||
// [vwu] A variable-width unsigned integer.
|
||||
// [vws] A variable-width signed integer.
|
||||
// [u8] An 8-bit unsigned integer.
|
||||
// [slot*] Information on how to reify a js::Value from an Ion frame. The
|
||||
// first byte is split as thus:
|
||||
// [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").
|
||||
//
|
||||
|
@ -48,8 +50,8 @@ using namespace js::jit;
|
|||
// JSVAL_TYPE_OBJECT:
|
||||
// JSVAL_TYPE_BOOLEAN:
|
||||
// JSVAL_TYPE_STRING:
|
||||
// If "reg" is InvalidReg1, this byte is followed by a [vws]
|
||||
// stack offset. Otherwise, "reg" encodes a GPR register.
|
||||
// If "reg" is ESC_REG_FIELD_INDEX, this byte is followed by a
|
||||
// [vws] stack offset. Otherwise, "reg" encodes a GPR register.
|
||||
//
|
||||
// JSVAL_TYPE_NULL:
|
||||
// Reg value:
|
||||
|
@ -86,17 +88,334 @@ using namespace js::jit;
|
|||
// code=3 reg, reg
|
||||
//
|
||||
// PUNBOX64:
|
||||
// "reg" is InvalidReg1: byte is followed by a [vws] stack
|
||||
// offset containing a Value.
|
||||
// "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.
|
||||
//
|
||||
|
||||
#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;
|
||||
#endif
|
||||
|
||||
static const uint32_t MAX_TYPE_FIELD_VALUE = 7;
|
||||
|
||||
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;
|
||||
|
||||
RValueAllocation
|
||||
RValueAllocation::read(CompactBufferReader &reader)
|
||||
{
|
||||
uint8_t b = reader.readByte();
|
||||
|
||||
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?");
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::writeHeader(CompactBufferWriter &writer,
|
||||
JSValueType type,
|
||||
uint32_t regCode) const
|
||||
{
|
||||
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);
|
||||
|
||||
uint8_t byte = uint32_t(type) | (regCode << 3);
|
||||
writer.writeByte(byte);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_INT32:
|
||||
return "int32_t";
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
return "double";
|
||||
case JSVAL_TYPE_STRING:
|
||||
return "string";
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
return "boolean";
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return "object";
|
||||
case JSVAL_TYPE_MAGIC:
|
||||
return "magic";
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("no payload");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RValueAllocation::dump(FILE *fp) const
|
||||
{
|
||||
switch (mode()) {
|
||||
case CONSTANT:
|
||||
fprintf(fp, "constant (pool index %u)", constantIndex());
|
||||
break;
|
||||
|
||||
case DOUBLE_REG:
|
||||
fprintf(fp, "double (reg %s)", floatReg().name());
|
||||
break;
|
||||
|
||||
case FLOAT32_REG:
|
||||
fprintf(fp, "float32 (reg %s)", floatReg().name());
|
||||
break;
|
||||
|
||||
case FLOAT32_STACK:
|
||||
fprintf(fp, "float32 (");
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
break;
|
||||
|
||||
case TYPED_REG:
|
||||
case TYPED_STACK:
|
||||
fprintf(fp, "%s (", ValTypeToString(knownType()));
|
||||
known_type_.payload.dump(fp);
|
||||
fprintf(fp, ")");
|
||||
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");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SnapshotReader::SnapshotReader(const uint8_t *buffer, const uint8_t *end)
|
||||
: reader_(buffer, end),
|
||||
slotCount_(0),
|
||||
allocCount_(0),
|
||||
frameCount_(0),
|
||||
slotsRead_(0)
|
||||
allocRead_(0)
|
||||
{
|
||||
if (!buffer)
|
||||
return;
|
||||
|
@ -129,12 +448,10 @@ void
|
|||
SnapshotReader::readFrameHeader()
|
||||
{
|
||||
JS_ASSERT(moreFrames());
|
||||
JS_ASSERT(slotsRead_ == slotCount_);
|
||||
JS_ASSERT(allocRead_ == allocCount_);
|
||||
|
||||
pcOffset_ = reader_.readUnsigned();
|
||||
slotCount_ = reader_.readUnsigned();
|
||||
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, slotCount_);
|
||||
|
||||
allocCount_ = reader_.readUnsigned();
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
pcOpcode_ = reader_.readUnsigned();
|
||||
mirOpcode_ = reader_.readUnsigned();
|
||||
|
@ -142,9 +459,10 @@ SnapshotReader::readFrameHeader()
|
|||
lirOpcode_ = reader_.readUnsigned();
|
||||
lirId_ = reader_.readUnsigned();
|
||||
#endif
|
||||
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
|
||||
|
||||
framesRead_++;
|
||||
slotsRead_ = 0;
|
||||
allocRead_ = 0;
|
||||
}
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
|
@ -163,13 +481,13 @@ SnapshotReader::spewBailingFrom() const
|
|||
}
|
||||
#endif
|
||||
|
||||
Slot
|
||||
SnapshotReader::readSlot()
|
||||
RValueAllocation
|
||||
SnapshotReader::readAllocation()
|
||||
{
|
||||
JS_ASSERT(slotsRead_ < slotCount_);
|
||||
IonSpew(IonSpew_Snapshots, "Reading slot %u", slotsRead_);
|
||||
slotsRead_++;
|
||||
return Slot::read(reader_);
|
||||
JS_ASSERT(allocRead_ < allocCount_);
|
||||
IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_);
|
||||
allocRead_++;
|
||||
return RValueAllocation::read(reader_);
|
||||
}
|
||||
|
||||
SnapshotOffset
|
||||
|
@ -206,16 +524,16 @@ SnapshotWriter::startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, ui
|
|||
uint32_t implicit = StartArgSlot(script);
|
||||
uint32_t formalArgs = CountArgSlots(script, fun);
|
||||
|
||||
nslots_ = formalArgs + script->nfixed() + exprStack;
|
||||
slotsWritten_ = 0;
|
||||
nallocs_ = formalArgs + script->nfixed() + exprStack;
|
||||
allocWritten_ = 0;
|
||||
|
||||
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
|
||||
implicit, formalArgs - implicit, script->nfixed(), exprStack);
|
||||
|
||||
uint32_t pcoff = script->pcToOffset(pc);
|
||||
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nslots_);
|
||||
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_);
|
||||
writer_.writeUnsigned(pcoff);
|
||||
writer_.writeUnsigned(nslots_);
|
||||
writer_.writeUnsigned(nallocs_);
|
||||
}
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
|
@ -232,26 +550,26 @@ SnapshotWriter::trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId
|
|||
#endif
|
||||
|
||||
void
|
||||
SnapshotWriter::addSlot(const Slot &slot)
|
||||
SnapshotWriter::add(const RValueAllocation &alloc)
|
||||
{
|
||||
if (IonSpewEnabled(IonSpew_Snapshots)) {
|
||||
IonSpewHeader(IonSpew_Snapshots);
|
||||
fprintf(IonSpewFile, " slot %u: ", slotsWritten_);
|
||||
slot.dump(IonSpewFile);
|
||||
fprintf(IonSpewFile, " slot %u: ", allocWritten_);
|
||||
alloc.dump(IonSpewFile);
|
||||
fprintf(IonSpewFile, "\n");
|
||||
}
|
||||
|
||||
slotsWritten_++;
|
||||
JS_ASSERT(slotsWritten_ <= nslots_);
|
||||
slot.write(writer_);
|
||||
allocWritten_++;
|
||||
JS_ASSERT(allocWritten_ <= nallocs_);
|
||||
alloc.write(writer_);
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotWriter::endFrame()
|
||||
{
|
||||
// Check that the last write succeeded.
|
||||
JS_ASSERT(nslots_ == slotsWritten_);
|
||||
nslots_ = slotsWritten_ = 0;
|
||||
JS_ASSERT(nallocs_ == allocWritten_);
|
||||
nallocs_ = allocWritten_ = 0;
|
||||
framesWritten_++;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,65 +4,73 @@
|
|||
* 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/. */
|
||||
|
||||
#ifndef jit_Slot_h
|
||||
#define jit_Slot_h
|
||||
#ifndef jit_Snapshot_h
|
||||
#define jit_Snapshot_h
|
||||
|
||||
#include "jsbytecode.h"
|
||||
|
||||
#include "jit/CompactBuffer.h"
|
||||
#include "jit/IonTypes.h"
|
||||
#include "jit/Registers.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class CompactBufferReader;
|
||||
class CompactBufferWriter;
|
||||
|
||||
class Slot;
|
||||
class RValueAllocation;
|
||||
|
||||
class Location
|
||||
{
|
||||
friend class Slot;
|
||||
friend class RValueAllocation;
|
||||
|
||||
// An offset that is illegal for a local variable's stack allocation.
|
||||
static const int32_t InvalidStackSlot = -1;
|
||||
static const int32_t InvalidStackOffset = -1;
|
||||
|
||||
Register::Code reg_;
|
||||
int32_t stackSlot_;
|
||||
int32_t stackOffset_;
|
||||
|
||||
static Location From(const Register ®) {
|
||||
Location loc;
|
||||
loc.reg_ = reg.code();
|
||||
loc.stackSlot_ = InvalidStackSlot;
|
||||
loc.stackOffset_ = InvalidStackOffset;
|
||||
return loc;
|
||||
}
|
||||
static Location From(int32_t stackSlot) {
|
||||
JS_ASSERT(stackSlot != InvalidStackSlot);
|
||||
static Location From(int32_t stackOffset) {
|
||||
JS_ASSERT(stackOffset != InvalidStackOffset);
|
||||
Location loc;
|
||||
loc.reg_ = Register::Code(0); // Quell compiler warnings.
|
||||
loc.stackSlot_ = stackSlot;
|
||||
loc.stackOffset_ = stackOffset;
|
||||
return loc;
|
||||
}
|
||||
|
||||
public:
|
||||
Register reg() const {
|
||||
JS_ASSERT(!isStackSlot());
|
||||
JS_ASSERT(!isStackOffset());
|
||||
return Register::FromCode(reg_);
|
||||
}
|
||||
int32_t stackSlot() const {
|
||||
JS_ASSERT(isStackSlot());
|
||||
return stackSlot_;
|
||||
int32_t stackOffset() const {
|
||||
JS_ASSERT(isStackOffset());
|
||||
return stackOffset_;
|
||||
}
|
||||
bool isStackSlot() const {
|
||||
return stackSlot_ != InvalidStackSlot;
|
||||
bool isStackOffset() const {
|
||||
return stackOffset_ != InvalidStackOffset;
|
||||
}
|
||||
|
||||
void dump(FILE *fp) const;
|
||||
|
||||
public:
|
||||
bool operator==(const Location &l) const {
|
||||
return reg_ == l.reg_ && stackSlot_ == l.stackSlot_;
|
||||
return reg_ == l.reg_ && stackOffset_ == l.stackOffset_;
|
||||
}
|
||||
};
|
||||
|
||||
class Slot
|
||||
// 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
|
||||
// an Ion frame.
|
||||
//
|
||||
// It is used with the SnapshotIterator to recover a Value from the stack,
|
||||
// spilled registers or the list of constant of the compiled script.
|
||||
class RValueAllocation
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
|
@ -130,32 +138,32 @@ class Slot
|
|||
int32_t value_;
|
||||
};
|
||||
|
||||
Slot(Mode mode, JSValueType type, const Location &loc)
|
||||
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;
|
||||
}
|
||||
Slot(Mode mode, const FloatRegister ®)
|
||||
RValueAllocation(Mode mode, const FloatRegister ®)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_REG || mode == DOUBLE_REG);
|
||||
fpu_ = reg.code();
|
||||
}
|
||||
Slot(Mode mode, const Location &loc)
|
||||
RValueAllocation(Mode mode, const Location &loc)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == FLOAT32_STACK);
|
||||
known_type_.payload = loc;
|
||||
}
|
||||
Slot(Mode mode, int32_t index)
|
||||
RValueAllocation(Mode mode, int32_t index)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
|
||||
value_ = index;
|
||||
}
|
||||
Slot(Mode mode)
|
||||
RValueAllocation(Mode mode)
|
||||
: mode_(mode)
|
||||
{
|
||||
JS_ASSERT(mode == JS_UNDEFINED || mode == JS_NULL ||
|
||||
|
@ -163,103 +171,103 @@ class Slot
|
|||
}
|
||||
|
||||
public:
|
||||
Slot()
|
||||
RValueAllocation()
|
||||
: mode_(INVALID)
|
||||
{ }
|
||||
|
||||
// DOUBLE_REG
|
||||
static Slot DoubleSlot(const FloatRegister ®) {
|
||||
return Slot(DOUBLE_REG, reg);
|
||||
static RValueAllocation Double(const FloatRegister ®) {
|
||||
return RValueAllocation(DOUBLE_REG, reg);
|
||||
}
|
||||
|
||||
// FLOAT32_REG or FLOAT32_STACK
|
||||
static Slot Float32Slot(const FloatRegister ®) {
|
||||
return Slot(FLOAT32_REG, reg);
|
||||
static RValueAllocation Float32(const FloatRegister ®) {
|
||||
return RValueAllocation(FLOAT32_REG, reg);
|
||||
}
|
||||
static Slot Float32Slot(int32_t stackIndex) {
|
||||
return Slot(FLOAT32_STACK, Location::From(stackIndex));
|
||||
static RValueAllocation Float32(int32_t stackIndex) {
|
||||
return RValueAllocation(FLOAT32_STACK, Location::From(stackIndex));
|
||||
}
|
||||
|
||||
// TYPED_REG or TYPED_STACK
|
||||
static Slot TypedSlot(JSValueType type, const Register ®) {
|
||||
static RValueAllocation Typed(JSValueType type, const Register ®) {
|
||||
JS_ASSERT(type != JSVAL_TYPE_DOUBLE &&
|
||||
type != JSVAL_TYPE_MAGIC &&
|
||||
type != JSVAL_TYPE_NULL &&
|
||||
type != JSVAL_TYPE_UNDEFINED);
|
||||
return Slot(TYPED_REG, type, Location::From(reg));
|
||||
return RValueAllocation(TYPED_REG, type, Location::From(reg));
|
||||
}
|
||||
static Slot TypedSlot(JSValueType type, int32_t stackIndex) {
|
||||
static RValueAllocation Typed(JSValueType type, int32_t stackIndex) {
|
||||
JS_ASSERT(type != JSVAL_TYPE_MAGIC &&
|
||||
type != JSVAL_TYPE_NULL &&
|
||||
type != JSVAL_TYPE_UNDEFINED);
|
||||
return Slot(TYPED_STACK, type, Location::From(stackIndex));
|
||||
return RValueAllocation(TYPED_STACK, type, Location::From(stackIndex));
|
||||
}
|
||||
|
||||
// UNTYPED
|
||||
#if defined(JS_NUNBOX32)
|
||||
static Slot UntypedSlot(const Register &type, const Register &payload) {
|
||||
Slot slot(UNTYPED_REG_REG);
|
||||
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;
|
||||
}
|
||||
|
||||
static Slot UntypedSlot(const Register &type, int32_t payloadStackIndex) {
|
||||
Slot slot(UNTYPED_REG_STACK);
|
||||
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 Slot UntypedSlot(int32_t typeStackIndex, const Register &payload) {
|
||||
Slot slot(UNTYPED_STACK_REG);
|
||||
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 Slot UntypedSlot(int32_t typeStackIndex, int32_t payloadStackIndex) {
|
||||
Slot slot(UNTYPED_STACK_STACK);
|
||||
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;
|
||||
}
|
||||
|
||||
#elif defined(JS_PUNBOX64)
|
||||
static Slot UntypedSlot(const Register &value) {
|
||||
Slot slot(UNTYPED_REG);
|
||||
static RValueAllocation Untyped(const Register &value) {
|
||||
RValueAllocation slot(UNTYPED_REG);
|
||||
slot.unknown_type_.value = Location::From(value);
|
||||
return slot;
|
||||
}
|
||||
|
||||
static Slot UntypedSlot(int32_t valueStackSlot) {
|
||||
Slot slot(UNTYPED_STACK);
|
||||
slot.unknown_type_.value = Location::From(valueStackSlot);
|
||||
static RValueAllocation Untyped(int32_t stackOffset) {
|
||||
RValueAllocation slot(UNTYPED_STACK);
|
||||
slot.unknown_type_.value = Location::From(stackOffset);
|
||||
return slot;
|
||||
}
|
||||
#endif
|
||||
|
||||
// common constants.
|
||||
static Slot UndefinedSlot() {
|
||||
return Slot(JS_UNDEFINED);
|
||||
static RValueAllocation Undefined() {
|
||||
return RValueAllocation(JS_UNDEFINED);
|
||||
}
|
||||
static Slot NullSlot() {
|
||||
return Slot(JS_NULL);
|
||||
static RValueAllocation Null() {
|
||||
return RValueAllocation(JS_NULL);
|
||||
}
|
||||
|
||||
// JS_INT32
|
||||
static Slot Int32Slot(int32_t value) {
|
||||
return Slot(JS_INT32, value);
|
||||
static RValueAllocation Int32(int32_t value) {
|
||||
return RValueAllocation(JS_INT32, value);
|
||||
}
|
||||
|
||||
// CONSTANT's index
|
||||
static Slot ConstantPoolSlot(uint32_t index) {
|
||||
return Slot(CONSTANT, int32_t(index));
|
||||
static RValueAllocation ConstantPool(uint32_t index) {
|
||||
return RValueAllocation(CONSTANT, int32_t(index));
|
||||
}
|
||||
|
||||
void writeSlotHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
|
||||
void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
|
||||
public:
|
||||
static Slot read(CompactBufferReader &reader);
|
||||
static RValueAllocation read(CompactBufferReader &reader);
|
||||
void write(CompactBufferWriter &writer) const;
|
||||
|
||||
public:
|
||||
|
@ -286,9 +294,9 @@ class Slot
|
|||
JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
|
||||
return FloatRegister::FromCode(fpu_);
|
||||
}
|
||||
int32_t stackSlot() const {
|
||||
int32_t stackOffset() const {
|
||||
JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
|
||||
return known_type_.payload.stackSlot();
|
||||
return known_type_.payload.stackOffset();
|
||||
}
|
||||
#if defined(JS_NUNBOX32)
|
||||
Location payload() const {
|
||||
|
@ -312,7 +320,7 @@ class Slot
|
|||
void dump() const;
|
||||
|
||||
public:
|
||||
bool operator==(const Slot &s) const {
|
||||
bool operator==(const RValueAllocation &s) const {
|
||||
if (mode_ != s.mode_)
|
||||
return false;
|
||||
|
||||
|
@ -346,7 +354,110 @@ class Slot
|
|||
}
|
||||
};
|
||||
|
||||
// Collects snapshots in a contiguous buffer, which is copied into IonScript
|
||||
// memory after code generation.
|
||||
class SnapshotWriter
|
||||
{
|
||||
CompactBufferWriter writer_;
|
||||
|
||||
// These are only used to assert sanity.
|
||||
uint32_t nallocs_;
|
||||
uint32_t allocWritten_;
|
||||
uint32_t nframes_;
|
||||
uint32_t framesWritten_;
|
||||
SnapshotOffset lastStart_;
|
||||
|
||||
public:
|
||||
SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
|
||||
void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
void trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
|
||||
uint32_t lirOpcode, uint32_t lirId);
|
||||
#endif
|
||||
void endFrame();
|
||||
|
||||
void add(const RValueAllocation &slot);
|
||||
|
||||
void endSnapshot();
|
||||
|
||||
bool oom() const {
|
||||
return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return writer_.length();
|
||||
}
|
||||
const uint8_t *buffer() const {
|
||||
return writer_.buffer();
|
||||
}
|
||||
};
|
||||
|
||||
// A snapshot reader reads the entries out of the compressed snapshot buffer in
|
||||
// a script. These entries describe the equivalent interpreter frames at a given
|
||||
// position in JIT code. Each entry is an Ion's value allocations, used to
|
||||
// recover the corresponding Value from an Ion frame.
|
||||
class SnapshotReader
|
||||
{
|
||||
CompactBufferReader reader_;
|
||||
|
||||
uint32_t pcOffset_; // Offset from script->code.
|
||||
uint32_t allocCount_; // Number of slots.
|
||||
uint32_t frameCount_;
|
||||
BailoutKind bailoutKind_;
|
||||
uint32_t framesRead_; // Number of frame headers that have been read.
|
||||
uint32_t allocRead_; // Number of slots that have been read.
|
||||
bool resumeAfter_;
|
||||
|
||||
#ifdef TRACK_SNAPSHOTS
|
||||
private:
|
||||
uint32_t pcOpcode_;
|
||||
uint32_t mirOpcode_;
|
||||
uint32_t mirId_;
|
||||
uint32_t lirOpcode_;
|
||||
uint32_t lirId_;
|
||||
|
||||
public:
|
||||
void spewBailingFrom() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void readSnapshotHeader();
|
||||
void readFrameHeader();
|
||||
|
||||
public:
|
||||
SnapshotReader(const uint8_t *buffer, const uint8_t *end);
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
}
|
||||
uint32_t allocations() const {
|
||||
return allocCount_;
|
||||
}
|
||||
BailoutKind bailoutKind() const {
|
||||
return bailoutKind_;
|
||||
}
|
||||
bool resumeAfter() const {
|
||||
if (moreFrames())
|
||||
return false;
|
||||
return resumeAfter_;
|
||||
}
|
||||
bool moreFrames() const {
|
||||
return framesRead_ < frameCount_;
|
||||
}
|
||||
void nextFrame() {
|
||||
readFrameHeader();
|
||||
}
|
||||
RValueAllocation readAllocation();
|
||||
|
||||
bool moreAllocations() const {
|
||||
return allocRead_ < allocCount_;
|
||||
}
|
||||
uint32_t frameCount() const {
|
||||
return frameCount_;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // jit_Slot_h
|
||||
#endif /* jit_Snapshot_h */
|
|
@ -131,14 +131,14 @@ ToStackIndex(LAllocation *a)
|
|||
}
|
||||
|
||||
bool
|
||||
CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
||||
CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint,
|
||||
uint32_t *startIndex)
|
||||
{
|
||||
IonSpew(IonSpew_Codegen, "Encoding %u of resume point %p's operands starting from %u",
|
||||
resumePoint->numOperands(), (void *) resumePoint, *startIndex);
|
||||
for (uint32_t slotno = 0, e = resumePoint->numOperands(); slotno < e; slotno++) {
|
||||
uint32_t i = slotno + *startIndex;
|
||||
MDefinition *mir = resumePoint->getOperand(slotno);
|
||||
for (uint32_t allocno = 0, e = resumePoint->numOperands(); allocno < e; allocno++) {
|
||||
uint32_t i = allocno + *startIndex;
|
||||
MDefinition *mir = resumePoint->getOperand(allocno);
|
||||
|
||||
if (mir->isBox())
|
||||
mir = mir->toBox()->getOperand(0);
|
||||
|
@ -147,14 +147,14 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
? MIRType_Undefined
|
||||
: mir->type();
|
||||
|
||||
Slot s;
|
||||
RValueAllocation alloc;
|
||||
|
||||
switch (type) {
|
||||
case MIRType_Undefined:
|
||||
s = Slot::UndefinedSlot();
|
||||
alloc = RValueAllocation::Undefined();
|
||||
break;
|
||||
case MIRType_Null:
|
||||
s = Slot::NullSlot();
|
||||
alloc = RValueAllocation::Null();
|
||||
break;
|
||||
case MIRType_Int32:
|
||||
case MIRType_String:
|
||||
|
@ -167,29 +167,29 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
JSValueType valueType = ValueTypeFromMIRType(type);
|
||||
if (payload->isMemory()) {
|
||||
if (type == MIRType_Float32)
|
||||
s = Slot::Float32Slot(ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Float32(ToStackIndex(payload));
|
||||
else
|
||||
s = Slot::TypedSlot(valueType, ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Typed(valueType, ToStackIndex(payload));
|
||||
} else if (payload->isGeneralReg()) {
|
||||
s = Slot::TypedSlot(valueType, ToRegister(payload));
|
||||
alloc = RValueAllocation::Typed(valueType, ToRegister(payload));
|
||||
} else if (payload->isFloatReg()) {
|
||||
FloatRegister reg = ToFloatRegister(payload);
|
||||
if (type == MIRType_Float32)
|
||||
s = Slot::Float32Slot(reg);
|
||||
alloc = RValueAllocation::Float32(reg);
|
||||
else
|
||||
s = Slot::DoubleSlot(reg);
|
||||
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) {
|
||||
s = Slot::Int32Slot(v.toInt32());
|
||||
alloc = RValueAllocation::Int32(v.toInt32());
|
||||
} else {
|
||||
uint32_t index;
|
||||
if (!graph.addConstantToPool(constant->value(), &index))
|
||||
return false;
|
||||
s = Slot::ConstantPoolSlot(index);
|
||||
alloc = RValueAllocation::ConstantPool(index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -199,7 +199,7 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
uint32_t index;
|
||||
if (!graph.addConstantToPool(MagicValue(JS_OPTIMIZED_ARGUMENTS), &index))
|
||||
return false;
|
||||
s = Slot::ConstantPoolSlot(index);
|
||||
alloc = RValueAllocation::ConstantPool(index);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -210,26 +210,26 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
|
|||
LAllocation *type = snapshot->typeOfSlot(i);
|
||||
if (type->isRegister()) {
|
||||
if (payload->isRegister())
|
||||
s = Slot::UntypedSlot(ToRegister(type), ToRegister(payload));
|
||||
alloc = RValueAllocation::Untyped(ToRegister(type), ToRegister(payload));
|
||||
else
|
||||
s = Slot::UntypedSlot(ToRegister(type), ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Untyped(ToRegister(type), ToStackIndex(payload));
|
||||
} else {
|
||||
if (payload->isRegister())
|
||||
s = Slot::UntypedSlot(ToStackIndex(type), ToRegister(payload));
|
||||
alloc = RValueAllocation::Untyped(ToStackIndex(type), ToRegister(payload));
|
||||
else
|
||||
s = Slot::UntypedSlot(ToStackIndex(type), ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Untyped(ToStackIndex(type), ToStackIndex(payload));
|
||||
}
|
||||
#elif JS_PUNBOX64
|
||||
if (payload->isRegister())
|
||||
s = Slot::UntypedSlot(ToRegister(payload));
|
||||
alloc = RValueAllocation::Untyped(ToRegister(payload));
|
||||
else
|
||||
s = Slot::UntypedSlot(ToStackIndex(payload));
|
||||
alloc = RValueAllocation::Untyped(ToStackIndex(payload));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snapshots_.addSlot(s);
|
||||
snapshots_.add(alloc);
|
||||
}
|
||||
|
||||
*startIndex += resumePoint->numOperands();
|
||||
|
@ -332,7 +332,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
|
|||
snapshots_.trackFrame(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
|
||||
#endif
|
||||
|
||||
if (!encodeSlots(snapshot, mir, &startIndex))
|
||||
if (!encodeAllocations(snapshot, mir, &startIndex))
|
||||
return false;
|
||||
snapshots_.endFrame();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "jit/MIRGenerator.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
#include "jit/Safepoints.h"
|
||||
#include "jit/SnapshotWriter.h"
|
||||
#include "jit/Snapshots.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
|
||||
|
@ -258,7 +258,7 @@ class CodeGeneratorShared : public LInstructionVisitor
|
|||
// Encodes an LSnapshot into the compressed snapshot buffer, returning
|
||||
// false on failure.
|
||||
bool encode(LSnapshot *snapshot);
|
||||
bool encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);
|
||||
bool encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);
|
||||
|
||||
// Attempts to assign a BailoutId to a snapshot, if one isn't already set.
|
||||
// If the bailout table is full, this returns false, which is not a fatal
|
||||
|
|
|
@ -41,7 +41,7 @@ UNIFIED_SOURCES += [
|
|||
'testIntern.cpp',
|
||||
'testIntString.cpp',
|
||||
'testIntTypesABI.cpp',
|
||||
'testJitSlot.cpp',
|
||||
'testJitRValueAlloc.cpp',
|
||||
'testJSEvaluateScript.cpp',
|
||||
'testLookup.cpp',
|
||||
'testLooselyEqual.cpp',
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* 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 "jit/CompactBuffer.h"
|
||||
#include "jit/Slot.h"
|
||||
#include "jit/Snapshots.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
|
@ -16,53 +15,53 @@ using namespace js::jit;
|
|||
// These tests are checking that all slots of the current architecture can all
|
||||
// be encoded and decoded correctly. We iterate on all registers and on many
|
||||
// fake stack locations (Fibonacci).
|
||||
static Slot
|
||||
ReadSlot(const Slot &slot)
|
||||
static RValueAllocation
|
||||
Read(const RValueAllocation &slot)
|
||||
{
|
||||
CompactBufferWriter writer;
|
||||
slot.write(writer);
|
||||
|
||||
CompactBufferReader reader(writer);
|
||||
return Slot::read(reader);
|
||||
return RValueAllocation::read(reader);
|
||||
}
|
||||
|
||||
BEGIN_TEST(testJitSlot_Double)
|
||||
BEGIN_TEST(testJitRValueAlloc_Double)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
|
||||
s = Slot::DoubleSlot(FloatRegister::FromCode(i));
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Double(FloatRegister::FromCode(i));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_Double)
|
||||
END_TEST(testJitRValueAlloc_Double)
|
||||
|
||||
BEGIN_TEST(testJitSlot_FloatReg)
|
||||
BEGIN_TEST(testJitRValueAlloc_FloatReg)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
|
||||
s = Slot::Float32Slot(FloatRegister::FromCode(i));
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Float32(FloatRegister::FromCode(i));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_FloatReg)
|
||||
END_TEST(testJitRValueAlloc_FloatReg)
|
||||
|
||||
BEGIN_TEST(testJitSlot_FloatStack)
|
||||
BEGIN_TEST(testJitRValueAlloc_FloatStack)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = Slot::Float32Slot(i);
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Float32(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_FloatStack)
|
||||
END_TEST(testJitRValueAlloc_FloatStack)
|
||||
|
||||
BEGIN_TEST(testJitSlot_TypedReg)
|
||||
BEGIN_TEST(testJitRValueAlloc_TypedReg)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
#define FOR_EACH_JSVAL(_) \
|
||||
/* _(JSVAL_TYPE_DOUBLE) */ \
|
||||
|
@ -75,8 +74,8 @@ BEGIN_TEST(testJitSlot_TypedReg)
|
|||
_(JSVAL_TYPE_OBJECT)
|
||||
|
||||
#define CHECK_WITH_JSVAL(jsval) \
|
||||
s = Slot::TypedSlot(jsval, Register::FromCode(i)); \
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Typed(jsval, Register::FromCode(i)); \
|
||||
CHECK(s == Read(s));
|
||||
|
||||
FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
|
||||
#undef CHECK_WITH_JSVAL
|
||||
|
@ -84,11 +83,11 @@ BEGIN_TEST(testJitSlot_TypedReg)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_TypedReg)
|
||||
END_TEST(testJitRValueAlloc_TypedReg)
|
||||
|
||||
BEGIN_TEST(testJitSlot_TypedStack)
|
||||
BEGIN_TEST(testJitRValueAlloc_TypedStack)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
#define FOR_EACH_JSVAL(_) \
|
||||
|
@ -102,8 +101,8 @@ BEGIN_TEST(testJitSlot_TypedStack)
|
|||
_(JSVAL_TYPE_OBJECT)
|
||||
|
||||
#define CHECK_WITH_JSVAL(jsval) \
|
||||
s = Slot::TypedSlot(jsval, i); \
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Typed(jsval, i); \
|
||||
CHECK(s == Read(s));
|
||||
|
||||
FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
|
||||
#undef CHECK_WITH_JSVAL
|
||||
|
@ -111,127 +110,127 @@ BEGIN_TEST(testJitSlot_TypedStack)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_TypedStack)
|
||||
END_TEST(testJitRValueAlloc_TypedStack)
|
||||
|
||||
#if defined(JS_NUNBOX32)
|
||||
|
||||
BEGIN_TEST(testJitSlot_UntypedRegReg)
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedRegReg)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
for (uint32_t j = 0; j < Registers::Total; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
s = Slot::UntypedSlot(Register::FromCode(i), Register::FromCode(j));
|
||||
MOZ_ASSERT(s == ReadSlot(s));
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Untyped(Register::FromCode(i), Register::FromCode(j));
|
||||
MOZ_ASSERT(s == Read(s));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_UntypedRegReg)
|
||||
END_TEST(testJitRValueAlloc_UntypedRegReg)
|
||||
|
||||
BEGIN_TEST(testJitSlot_UntypedRegStack)
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedRegStack)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
int32_t j, last = 0, tmp;
|
||||
for (j = 0; j > 0; tmp = j, j += last, last = tmp) {
|
||||
s = Slot::UntypedSlot(Register::FromCode(i), j);
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Untyped(Register::FromCode(i), j);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_UntypedRegStack)
|
||||
END_TEST(testJitRValueAlloc_UntypedRegStack)
|
||||
|
||||
BEGIN_TEST(testJitSlot_UntypedStackReg)
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedStackReg)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
for (uint32_t j = 0; j < Registers::Total; j++) {
|
||||
s = Slot::UntypedSlot(i, Register::FromCode(j));
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Untyped(i, Register::FromCode(j));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_UntypedStackReg)
|
||||
END_TEST(testJitRValueAlloc_UntypedStackReg)
|
||||
|
||||
BEGIN_TEST(testJitSlot_UntypedStackStack)
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedStackStack)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
int32_t i, li = 0, ti;
|
||||
for (i = 0; i > 0; ti = i, i += li, li = ti) {
|
||||
int32_t j, lj = 0, tj;
|
||||
for (j = 0; j > 0; tj = j, j += lj, lj = tj) {
|
||||
s = Slot::UntypedSlot(i, j);
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Untyped(i, j);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_UntypedStackStack)
|
||||
END_TEST(testJitRValueAlloc_UntypedStackStack)
|
||||
|
||||
#else
|
||||
|
||||
BEGIN_TEST(testJitSlot_UntypedReg)
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedReg)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
for (uint32_t i = 0; i < Registers::Total; i++) {
|
||||
s = Slot::UntypedSlot(Register::FromCode(i));
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Untyped(Register::FromCode(i));
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_UntypedReg)
|
||||
END_TEST(testJitRValueAlloc_UntypedReg)
|
||||
|
||||
BEGIN_TEST(testJitSlot_UntypedStack)
|
||||
BEGIN_TEST(testJitRValueAlloc_UntypedStack)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = Slot::UntypedSlot(i);
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Untyped(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_UntypedStack)
|
||||
END_TEST(testJitRValueAlloc_UntypedStack)
|
||||
|
||||
#endif
|
||||
|
||||
BEGIN_TEST(testJitSlot_UndefinedAndNull)
|
||||
BEGIN_TEST(testJitRValueAlloc_UndefinedAndNull)
|
||||
{
|
||||
Slot s;
|
||||
s = Slot::UndefinedSlot();
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = Slot::NullSlot();
|
||||
CHECK(s == ReadSlot(s));
|
||||
RValueAllocation s;
|
||||
s = RValueAllocation::Undefined();
|
||||
CHECK(s == Read(s));
|
||||
s = RValueAllocation::Null();
|
||||
CHECK(s == Read(s));
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_UndefinedAndNull)
|
||||
END_TEST(testJitRValueAlloc_UndefinedAndNull)
|
||||
|
||||
BEGIN_TEST(testJitSlot_Int32)
|
||||
BEGIN_TEST(testJitRValueAlloc_Int32)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = Slot::Int32Slot(i);
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::Int32(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_Int32)
|
||||
END_TEST(testJitRValueAlloc_Int32)
|
||||
|
||||
BEGIN_TEST(testJitSlot_ConstantPool)
|
||||
BEGIN_TEST(testJitRValueAlloc_ConstantPool)
|
||||
{
|
||||
Slot s;
|
||||
RValueAllocation s;
|
||||
int32_t i, last = 0, tmp;
|
||||
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
|
||||
s = Slot::ConstantPoolSlot(i);
|
||||
CHECK(s == ReadSlot(s));
|
||||
s = RValueAllocation::ConstantPool(i);
|
||||
CHECK(s == Read(s));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitSlot_ConstantPool)
|
||||
END_TEST(testJitRValueAlloc_ConstantPool)
|
|
@ -273,7 +273,6 @@ if CONFIG['ENABLE_ION']:
|
|||
'jit/shared/BaselineCompiler-shared.cpp',
|
||||
'jit/shared/CodeGenerator-shared.cpp',
|
||||
'jit/shared/Lowering-shared.cpp',
|
||||
'jit/Slot.cpp',
|
||||
'jit/Snapshots.cpp',
|
||||
'jit/StupidAllocator.cpp',
|
||||
'jit/TypePolicy.cpp',
|
||||
|
|
|
@ -1175,8 +1175,10 @@ ScriptFrameIter::numFrameSlots() const
|
|||
break;
|
||||
case JIT: {
|
||||
#ifdef JS_ION
|
||||
if (data_.ionFrames_.isOptimizedJS())
|
||||
return ionInlineFrames_.snapshotIterator().slots() - ionInlineFrames_.script()->nfixed();
|
||||
if (data_.ionFrames_.isOptimizedJS()) {
|
||||
return ionInlineFrames_.snapshotIterator().allocations() -
|
||||
ionInlineFrames_.script()->nfixed();
|
||||
}
|
||||
jit::BaselineFrame *frame = data_.ionFrames_.baselineFrame();
|
||||
return frame->numValueSlots() - data_.ionFrames_.script()->nfixed();
|
||||
#else
|
||||
|
@ -1201,7 +1203,7 @@ ScriptFrameIter::frameSlotValue(size_t index) const
|
|||
if (data_.ionFrames_.isOptimizedJS()) {
|
||||
jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
|
||||
index += ionInlineFrames_.script()->nfixed();
|
||||
return si.maybeReadSlotByIndex(index);
|
||||
return si.maybeReadAllocByIndex(index);
|
||||
}
|
||||
|
||||
index += data_.ionFrames_.script()->nfixed();
|
||||
|
|
Загрузка…
Ссылка в новой задаче