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:
Nicolas B. Pierron 2014-02-10 06:21:46 -08:00
Родитель 226cc7f3b7
Коммит 2aadd38210
18 изменённых файлов: 741 добавлений и 850 удалений

Просмотреть файл

@ -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 &reg) {
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 &reg)
RValueAllocation(Mode mode, const FloatRegister &reg)
: 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 &reg) {
return Slot(DOUBLE_REG, reg);
static RValueAllocation Double(const FloatRegister &reg) {
return RValueAllocation(DOUBLE_REG, reg);
}
// FLOAT32_REG or FLOAT32_STACK
static Slot Float32Slot(const FloatRegister &reg) {
return Slot(FLOAT32_REG, reg);
static RValueAllocation Float32(const FloatRegister &reg) {
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 &reg) {
static RValueAllocation Typed(JSValueType type, const Register &reg) {
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,
uint32_t *startIndex)
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) */ \
@ -74,9 +73,9 @@ BEGIN_TEST(testJitSlot_TypedReg)
/* _(JSVAL_TYPE_NULL) */ \
_(JSVAL_TYPE_OBJECT)
#define CHECK_WITH_JSVAL(jsval) \
s = Slot::TypedSlot(jsval, Register::FromCode(i)); \
CHECK(s == ReadSlot(s));
#define CHECK_WITH_JSVAL(jsval) \
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(_) \
@ -101,9 +100,9 @@ BEGIN_TEST(testJitSlot_TypedStack)
/* _(JSVAL_TYPE_NULL) */ \
_(JSVAL_TYPE_OBJECT)
#define CHECK_WITH_JSVAL(jsval) \
s = Slot::TypedSlot(jsval, i); \
CHECK(s == ReadSlot(s));
#define CHECK_WITH_JSVAL(jsval) \
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',

Просмотреть файл

@ -1173,10 +1173,12 @@ ScriptFrameIter::numFrameSlots() const
switch (data_.state_) {
case DONE:
break;
case JIT: {
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();