Bug 962555 part 1 - Extract SnapshotReader::Slot. r=h4writer

This commit is contained in:
Nicolas B. Pierron 2014-02-10 06:21:43 -08:00
parent 8035e0d726
commit 4bcd603d12
11 changed files with 1003 additions and 502 deletions

View File

@ -237,8 +237,8 @@ class SnapshotIterator : public SnapshotReader
IonScript *ionScript_;
private:
bool hasLocation(const SnapshotReader::Location &loc);
uintptr_t fromLocation(const SnapshotReader::Location &loc);
bool hasLocation(const Location &loc);
uintptr_t fromLocation(const Location &loc);
Value slotValue(const Slot &slot);
bool slotReadable(const Slot &slot);

View File

@ -1319,13 +1319,13 @@ SnapshotIterator::SnapshotIterator()
}
bool
SnapshotIterator::hasLocation(const SnapshotReader::Location &loc)
SnapshotIterator::hasLocation(const Location &loc)
{
return loc.isStackSlot() || machine_.has(loc.reg());
}
uintptr_t
SnapshotIterator::fromLocation(const SnapshotReader::Location &loc)
SnapshotIterator::fromLocation(const Location &loc)
{
if (loc.isStackSlot())
return ReadFrameSlot(fp_, loc.stackSlot());
@ -1365,13 +1365,13 @@ bool
SnapshotIterator::slotReadable(const Slot &slot)
{
switch (slot.mode()) {
case SnapshotReader::DOUBLE_REG:
case Slot::DOUBLE_REG:
return machine_.has(slot.floatReg());
case SnapshotReader::TYPED_REG:
case Slot::TYPED_REG:
return machine_.has(slot.reg());
case SnapshotReader::UNTYPED:
case Slot::UNTYPED:
#if defined(JS_NUNBOX32)
return hasLocation(slot.type()) && hasLocation(slot.payload());
#elif defined(JS_PUNBOX64)
@ -1387,10 +1387,10 @@ Value
SnapshotIterator::slotValue(const Slot &slot)
{
switch (slot.mode()) {
case SnapshotReader::DOUBLE_REG:
case Slot::DOUBLE_REG:
return DoubleValue(machine_.read(slot.floatReg()));
case SnapshotReader::FLOAT32_REG:
case Slot::FLOAT32_REG:
{
union {
double d;
@ -1402,13 +1402,13 @@ SnapshotIterator::slotValue(const Slot &slot)
return Float32Value(pun.f);
}
case SnapshotReader::FLOAT32_STACK:
case Slot::FLOAT32_STACK:
return Float32Value(ReadFrameFloat32Slot(fp_, slot.stackSlot()));
case SnapshotReader::TYPED_REG:
case Slot::TYPED_REG:
return FromTypedPayload(slot.knownType(), machine_.read(slot.reg()));
case SnapshotReader::TYPED_STACK:
case Slot::TYPED_STACK:
{
switch (slot.knownType()) {
case JSVAL_TYPE_DOUBLE:
@ -1426,7 +1426,7 @@ SnapshotIterator::slotValue(const Slot &slot)
}
}
case SnapshotReader::UNTYPED:
case Slot::UNTYPED:
{
jsval_layout layout;
#if defined(JS_NUNBOX32)
@ -1438,16 +1438,16 @@ SnapshotIterator::slotValue(const Slot &slot)
return IMPL_TO_JSVAL(layout);
}
case SnapshotReader::JS_UNDEFINED:
case Slot::JS_UNDEFINED:
return UndefinedValue();
case SnapshotReader::JS_NULL:
case Slot::JS_NULL:
return NullValue();
case SnapshotReader::JS_INT32:
case Slot::JS_INT32:
return Int32Value(slot.int32Value());
case SnapshotReader::CONSTANT:
case Slot::CONSTANT:
return ionScript_->getConstant(slot.constantIndex());
default:

380
js/src/jit/Slot.cpp Normal file
View File

@ -0,0 +1,380 @@
/* -*- 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;
}
case UNTYPED: {
#if defined(JS_NUNBOX32)
uint32_t code = 0;
if (type().isStackSlot()) {
if (payload().isStackSlot())
code = NUNBOX32_STACK_STACK;
else
code = NUNBOX32_STACK_REG;
} else {
if (payload().isStackSlot())
code = NUNBOX32_REG_STACK;
else
code = NUNBOX32_REG_REG;
}
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, code);
if (type().isStackSlot())
writer.writeSigned(type().stackSlot());
else
writer.writeByte(type().reg().code());
if (payload().isStackSlot())
writer.writeSigned(payload().stackSlot());
else
writer.writeByte(payload().reg().code());
#elif defined(JS_PUNBOX64)
if (value().isStackSlot()) {
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
writer.writeSigned(value().stackSlot());
} else {
writeSlotHeader(writer, JSVAL_TYPE_MAGIC, value().reg().code());
}
#endif
break;
}
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;
case UNTYPED: {
fprintf(fp, "value (");
#if defined(JS_NUNBOX32)
fprintf(fp, "type = ");
type().dump(fp);
fprintf(fp, ", payload = ");
payload().dump(fp);
#elif defined(JS_PUNBOX64)
value().dump(fp);
#endif
fprintf(fp, ")");
break;
}
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;
}
}

325
js/src/jit/Slot.h Normal file
View File

@ -0,0 +1,325 @@
/* -*- 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_Slot_h
#define jit_Slot_h
#include "jit/Registers.h"
namespace js {
namespace jit {
class CompactBufferReader;
class CompactBufferWriter;
class Slot;
class Location
{
friend class Slot;
// An offset that is illegal for a local variable's stack allocation.
static const int32_t InvalidStackSlot = -1;
Register::Code reg_;
int32_t stackSlot_;
static Location From(const Register &reg) {
Location loc;
loc.reg_ = reg.code();
loc.stackSlot_ = InvalidStackSlot;
return loc;
}
static Location From(int32_t stackSlot) {
JS_ASSERT(stackSlot != InvalidStackSlot);
Location loc;
loc.reg_ = Register::Code(0); // Quell compiler warnings.
loc.stackSlot_ = stackSlot;
return loc;
}
public:
Register reg() const {
JS_ASSERT(!isStackSlot());
return Register::FromCode(reg_);
}
int32_t stackSlot() const {
JS_ASSERT(isStackSlot());
return stackSlot_;
}
bool isStackSlot() const {
return stackSlot_ != InvalidStackSlot;
}
void dump(FILE *fp) const;
public:
bool operator==(const Location &l) const {
return reg_ == l.reg_ && stackSlot_ == l.stackSlot_;
}
};
class Slot
{
public:
enum Mode
{
CONSTANT, // An index into the constant pool.
DOUBLE_REG, // Type is double, payload is in a register.
FLOAT32_REG, // Type is float32, payload is in a register.
FLOAT32_STACK, // Type is float32, payload is on the stack.
TYPED_REG, // Type is constant, payload is in a register.
TYPED_STACK, // Type is constant, payload is on the stack.
UNTYPED, // Type is not known.
JS_UNDEFINED, // UndefinedValue()
JS_NULL, // NullValue()
JS_INT32, // Int32Value(n)
INVALID
};
private:
Mode mode_;
union {
// DOUBLE_REG or FLOAT32_REG
FloatRegister::Code fpu_;
// TYPED_REG or TYPED_STACK or FLOAT32_STACK
struct {
JSValueType type;
Location payload;
} known_type_;
// UNTYPED
#if defined(JS_NUNBOX32)
struct {
Location type;
Location payload;
} unknown_type_;
#elif defined(JS_PUNBOX64)
struct {
Location value;
} unknown_type_;
#endif
// CONSTANT's index or JS_INT32
int32_t value_;
};
Slot(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)
: mode_(mode)
{
JS_ASSERT(mode == FLOAT32_REG || mode == DOUBLE_REG);
fpu_ = reg.code();
}
Slot(Mode mode, const Location &loc)
: mode_(mode)
{
JS_ASSERT(mode == FLOAT32_STACK);
known_type_.payload = loc;
}
Slot(Mode mode, int32_t index)
: mode_(mode)
{
JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
value_ = index;
}
Slot(Mode mode)
: mode_(mode)
{
JS_ASSERT(mode == JS_UNDEFINED || mode == JS_NULL || mode == UNTYPED);
}
public:
Slot()
: mode_(INVALID)
{ }
// DOUBLE_REG
static Slot DoubleSlot(const FloatRegister &reg) {
return Slot(DOUBLE_REG, reg);
}
// FLOAT32_REG or FLOAT32_STACK
static Slot Float32Slot(const FloatRegister &reg) {
return Slot(FLOAT32_REG, reg);
}
static Slot Float32Slot(int32_t stackIndex) {
return Slot(FLOAT32_STACK, Location::From(stackIndex));
}
// TYPED_REG or TYPED_STACK
static Slot TypedSlot(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));
}
static Slot TypedSlot(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));
}
// UNTYPED
#if defined(JS_NUNBOX32)
static Slot UntypedSlot(const Register &type, const Register &payload) {
Slot slot(UNTYPED);
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);
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);
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);
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);
slot.unknown_type_.value = Location::From(value);
return slot;
}
static Slot UntypedSlot(int32_t valueStackSlot) {
Slot slot(UNTYPED);
slot.unknown_type_.value = Location::From(valueStackSlot);
return slot;
}
#endif
// common constants.
static Slot UndefinedSlot() {
return Slot(JS_UNDEFINED);
}
static Slot NullSlot() {
return Slot(JS_NULL);
}
// JS_INT32
static Slot Int32Slot(int32_t value) {
return Slot(JS_INT32, value);
}
// CONSTANT's index
static Slot ConstantPoolSlot(uint32_t index) {
return Slot(CONSTANT, int32_t(index));
}
void writeSlotHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
public:
static Slot read(CompactBufferReader &reader);
void write(CompactBufferWriter &writer) const;
public:
Mode mode() const {
return mode_;
}
uint32_t constantIndex() const {
JS_ASSERT(mode() == CONSTANT);
return value_;
}
int32_t int32Value() const {
JS_ASSERT(mode() == JS_INT32);
return value_;
}
JSValueType knownType() const {
JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
return known_type_.type;
}
Register reg() const {
JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
return known_type_.payload.reg();
}
FloatRegister floatReg() const {
JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
return FloatRegister::FromCode(fpu_);
}
int32_t stackSlot() const {
JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
return known_type_.payload.stackSlot();
}
#if defined(JS_NUNBOX32)
Location payload() const {
JS_ASSERT(mode() == UNTYPED);
return unknown_type_.payload;
}
Location type() const {
JS_ASSERT(mode() == UNTYPED);
return unknown_type_.type;
}
#elif defined(JS_PUNBOX64)
Location value() const {
JS_ASSERT(mode() == UNTYPED);
return unknown_type_.value;
}
#endif
public:
const char *modeToString() const;
void dump(FILE *fp) const;
void dump() const;
public:
bool operator==(const Slot &s) const {
if (mode_ != s.mode_)
return false;
switch (mode_) {
case DOUBLE_REG:
case FLOAT32_REG:
return fpu_ == s.fpu_;
case TYPED_REG:
case TYPED_STACK:
case FLOAT32_STACK:
return known_type_.type == s.known_type_.type &&
known_type_.payload == s.known_type_.payload;
case UNTYPED:
#if defined(JS_NUNBOX32)
return unknown_type_.type == s.unknown_type_.type &&
unknown_type_.payload == s.unknown_type_.payload;
#else
return unknown_type_.value == s.unknown_type_.value;
#endif
case CONSTANT:
case JS_INT32:
return value_ == s.value_;
default:
return true;
}
}
};
}
}
#endif // jit_Slot_h

View File

@ -11,6 +11,7 @@
#include "jit/IonCode.h"
#include "jit/IonTypes.h"
#include "jit/Registers.h"
#include "jit/Slot.h"
namespace js {
namespace jit {
@ -50,162 +51,6 @@ class SnapshotReader
void readSnapshotHeader();
void readFrameHeader();
public:
enum SlotMode
{
CONSTANT, // An index into the constant pool.
DOUBLE_REG, // Type is double, payload is in a register.
FLOAT32_REG, // Type is float32, payload is in a register.
FLOAT32_STACK, // Type is float32, payload is on the stack.
TYPED_REG, // Type is constant, payload is in a register.
TYPED_STACK, // Type is constant, payload is on the stack.
UNTYPED, // Type is not known.
JS_UNDEFINED, // UndefinedValue()
JS_NULL, // NullValue()
JS_INT32 // Int32Value(n)
};
class Location
{
friend class SnapshotReader;
// An offset that is illegal for a local variable's stack allocation.
static const int32_t InvalidStackSlot = -1;
Register::Code reg_;
int32_t stackSlot_;
static Location From(const Register &reg) {
Location loc;
loc.reg_ = reg.code();
loc.stackSlot_ = InvalidStackSlot;
return loc;
}
static Location From(int32_t stackSlot) {
JS_ASSERT(stackSlot != InvalidStackSlot);
Location loc;
loc.reg_ = Register::Code(0); // Quell compiler warnings.
loc.stackSlot_ = stackSlot;
return loc;
}
public:
Register reg() const {
JS_ASSERT(!isStackSlot());
return Register::FromCode(reg_);
}
int32_t stackSlot() const {
JS_ASSERT(isStackSlot());
return stackSlot_;
}
bool isStackSlot() const {
return stackSlot_ != InvalidStackSlot;
}
};
class Slot
{
friend class SnapshotReader;
SlotMode mode_;
union {
FloatRegister::Code fpu_;
struct {
JSValueType type;
Location payload;
} known_type_;
#if defined(JS_NUNBOX32)
struct {
Location type;
Location payload;
} unknown_type_;
#elif defined(JS_PUNBOX64)
struct {
Location value;
} unknown_type_;
#endif
int32_t value_;
};
Slot(SlotMode mode, JSValueType type, const Location &loc)
: mode_(mode)
{
known_type_.type = type;
known_type_.payload = loc;
}
Slot(const FloatRegister &reg)
: mode_(DOUBLE_REG)
{
fpu_ = reg.code();
}
Slot(SlotMode mode, const FloatRegister &reg)
: mode_(mode)
{
JS_ASSERT(mode == FLOAT32_REG);
fpu_ = reg.code();
}
Slot(SlotMode mode, const Location &loc)
: mode_(mode)
{
JS_ASSERT(mode == FLOAT32_STACK);
known_type_.payload = loc;
}
Slot(SlotMode mode)
: mode_(mode)
{ }
Slot(SlotMode mode, uint32_t index)
: mode_(mode)
{
JS_ASSERT(mode == CONSTANT || mode == JS_INT32);
value_ = index;
}
public:
SlotMode mode() const {
return mode_;
}
uint32_t constantIndex() const {
JS_ASSERT(mode() == CONSTANT);
return value_;
}
int32_t int32Value() const {
JS_ASSERT(mode() == JS_INT32);
return value_;
}
JSValueType knownType() const {
JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
return known_type_.type;
}
Register reg() const {
JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
return known_type_.payload.reg();
}
FloatRegister floatReg() const {
JS_ASSERT(mode() == DOUBLE_REG || mode() == FLOAT32_REG);
return FloatRegister::FromCode(fpu_);
}
int32_t stackSlot() const {
JS_ASSERT(mode() == TYPED_STACK || mode() == FLOAT32_STACK);
return known_type_.payload.stackSlot();
}
#if defined(JS_NUNBOX32)
Location payload() const {
JS_ASSERT(mode() == UNTYPED);
return unknown_type_.payload;
}
Location type() const {
JS_ASSERT(mode() == UNTYPED);
return unknown_type_.type;
}
#elif defined(JS_PUNBOX64)
Location value() const {
JS_ASSERT(mode() == UNTYPED);
return unknown_type_.value;
}
#endif
};
public:
SnapshotReader(const uint8_t *buffer, const uint8_t *end);

View File

@ -40,24 +40,8 @@ class SnapshotWriter
#endif
void endFrame();
void addSlot(const FloatRegister &reg);
void addSlot(JSValueType type, const Register &reg);
void addSlot(JSValueType type, int32_t stackIndex);
void addUndefinedSlot();
void addNullSlot();
void addInt32Slot(int32_t value);
void addFloat32Slot(const FloatRegister &reg);
void addFloat32Slot(int32_t stackIndex);
void addConstantPoolSlot(uint32_t index);
#if defined(JS_NUNBOX32)
void addSlot(const Register &type, const Register &payload);
void addSlot(const Register &type, int32_t payloadStackIndex);
void addSlot(int32_t typeStackIndex, const Register &payload);
void addSlot(int32_t typeStackIndex, int32_t payloadStackIndex);
#elif defined(JS_PUNBOX64)
void addSlot(const Register &value);
void addSlot(int32_t valueStackSlot);
#endif
void addSlot(const Slot &slot);
void endSnapshot();
bool oom() const {

View File

@ -90,7 +90,7 @@ using namespace js::jit;
// offset containing a Value.
//
// Otherwise, "reg" is a register containing a Value.
//
//
SnapshotReader::SnapshotReader(const uint8_t *buffer, const uint8_t *end)
: reader_(buffer, end),
@ -163,116 +163,13 @@ SnapshotReader::spewBailingFrom() const
}
#endif
#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;
SnapshotReader::Slot
Slot
SnapshotReader::readSlot()
{
JS_ASSERT(slotsRead_ < slotCount_);
IonSpew(IonSpew_Snapshots, "Reading slot %u", slotsRead_);
slotsRead_++;
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 Slot(FloatRegister::FromCode(code));
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
return Slot(TYPED_STACK, type, Location::From(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 Slot(TYPED_REG, type, Location::From(Register::FromCode(code)));
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
return Slot(TYPED_STACK, type, Location::From(reader_.readSigned()));
case JSVAL_TYPE_NULL:
if (code == ESC_REG_FIELD_CONST)
return Slot(JS_NULL);
if (code == ESC_REG_FIELD_INDEX)
return Slot(JS_INT32, reader_.readSigned());
if (code == ESC_REG_FIELD_FLOAT32_REG)
return Slot(FLOAT32_REG, FloatRegister::FromCode(reader_.readUnsigned()));
if (code == ESC_REG_FIELD_FLOAT32_STACK)
return Slot(FLOAT32_STACK, Location::From(reader_.readSigned()));
return Slot(JS_INT32, code);
case JSVAL_TYPE_UNDEFINED:
if (code == ESC_REG_FIELD_CONST)
return Slot(JS_UNDEFINED);
if (code == ESC_REG_FIELD_INDEX)
return Slot(CONSTANT, reader_.readUnsigned());
return Slot(CONSTANT, code);
default:
{
JS_ASSERT(type == JSVAL_TYPE_MAGIC);
if (code == ESC_REG_FIELD_CONST) {
uint8_t reg2 = reader_.readUnsigned();
Location loc;
if (reg2 != ESC_REG_FIELD_INDEX)
loc = Location::From(Register::FromCode(reg2));
else
loc = Location::From(reader_.readSigned());
return Slot(TYPED_REG, type, loc);
}
Slot slot(UNTYPED);
#ifdef JS_NUNBOX32
switch (code) {
case NUNBOX32_STACK_STACK:
slot.unknown_type_.type = Location::From(reader_.readSigned());
slot.unknown_type_.payload = Location::From(reader_.readSigned());
return slot;
case NUNBOX32_STACK_REG:
slot.unknown_type_.type = Location::From(reader_.readSigned());
slot.unknown_type_.payload = Location::From(Register::FromCode(reader_.readByte()));
return slot;
case NUNBOX32_REG_STACK:
slot.unknown_type_.type = Location::From(Register::FromCode(reader_.readByte()));
slot.unknown_type_.payload = Location::From(reader_.readSigned());
return slot;
default:
JS_ASSERT(code == NUNBOX32_REG_REG);
slot.unknown_type_.type = Location::From(Register::FromCode(reader_.readByte()));
slot.unknown_type_.payload = Location::From(Register::FromCode(reader_.readByte()));
return slot;
}
#elif JS_PUNBOX64
if (code < MIN_REG_FIELD_ESC) {
slot.unknown_type_.value = Location::From(Register::FromCode(code));
} else {
JS_ASSERT(code == ESC_REG_FIELD_INDEX);
slot.unknown_type_.value = Location::From(reader_.readSigned());
}
return slot;
#endif
}
}
MOZ_ASSUME_UNREACHABLE("huh?");
return Slot::read(reader_);
}
SnapshotOffset
@ -334,6 +231,21 @@ SnapshotWriter::trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId
}
#endif
void
SnapshotWriter::addSlot(const Slot &slot)
{
if (IonSpewEnabled(IonSpew_Snapshots)) {
IonSpewHeader(IonSpew_Snapshots);
fprintf(IonSpewFile, " slot %u: ", slotsWritten_);
slot.dump(IonSpewFile);
fprintf(IonSpewFile, "\n");
}
slotsWritten_++;
JS_ASSERT(slotsWritten_ <= nslots_);
slot.write(writer_);
}
void
SnapshotWriter::endFrame()
{
@ -343,150 +255,6 @@ SnapshotWriter::endFrame()
framesWritten_++;
}
void
SnapshotWriter::writeSlotHeader(JSValueType type, uint32_t regCode)
{
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);
slotsWritten_++;
JS_ASSERT(slotsWritten_ <= nslots_);
}
void
SnapshotWriter::addSlot(const FloatRegister &reg)
{
JS_ASSERT(uint32_t(reg.code()) < MIN_REG_FIELD_ESC);
IonSpew(IonSpew_Snapshots, " slot %u: double (reg %s)", slotsWritten_, reg.name());
writeSlotHeader(JSVAL_TYPE_DOUBLE, reg.code());
}
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
SnapshotWriter::addSlot(JSValueType type, const Register &reg)
{
IonSpew(IonSpew_Snapshots, " slot %u: %s (%s)",
slotsWritten_, ValTypeToString(type), reg.name());
JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
writeSlotHeader(type, reg.code());
}
void
SnapshotWriter::addSlot(JSValueType type, int32_t stackIndex)
{
IonSpew(IonSpew_Snapshots, " slot %u: %s (stack %d)",
slotsWritten_, ValTypeToString(type), stackIndex);
writeSlotHeader(type, ESC_REG_FIELD_INDEX);
writer_.writeSigned(stackIndex);
}
#if defined(JS_NUNBOX32)
void
SnapshotWriter::addSlot(const Register &type, const Register &payload)
{
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%s, d=%s)",
slotsWritten_, type.name(), payload.name());
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
writer_.writeByte(type.code());
writer_.writeByte(payload.code());
}
void
SnapshotWriter::addSlot(const Register &type, int32_t payloadStackIndex)
{
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%s, d=%d)",
slotsWritten_, type.name(), payloadStackIndex);
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_REG_STACK);
writer_.writeByte(type.code());
writer_.writeSigned(payloadStackIndex);
}
void
SnapshotWriter::addSlot(int32_t typeStackIndex, const Register &payload)
{
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%d, d=%s)",
slotsWritten_, typeStackIndex, payload.name());
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_STACK_REG);
writer_.writeSigned(typeStackIndex);
writer_.writeByte(payload.code());
}
void
SnapshotWriter::addSlot(int32_t typeStackIndex, int32_t payloadStackIndex)
{
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%d, d=%d)",
slotsWritten_, typeStackIndex, payloadStackIndex);
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_STACK_STACK);
writer_.writeSigned(typeStackIndex);
writer_.writeSigned(payloadStackIndex);
}
#elif defined(JS_PUNBOX64)
void
SnapshotWriter::addSlot(const Register &value)
{
IonSpew(IonSpew_Snapshots, " slot %u: value (reg %s)", slotsWritten_, value.name());
writeSlotHeader(JSVAL_TYPE_MAGIC, value.code());
}
void
SnapshotWriter::addSlot(int32_t valueStackSlot)
{
IonSpew(IonSpew_Snapshots, " slot %u: value (stack %d)", slotsWritten_, valueStackSlot);
writeSlotHeader(JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
writer_.writeSigned(valueStackSlot);
}
#endif
void
SnapshotWriter::addUndefinedSlot()
{
IonSpew(IonSpew_Snapshots, " slot %u: undefined", slotsWritten_);
writeSlotHeader(JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_CONST);
}
void
SnapshotWriter::addNullSlot()
{
IonSpew(IonSpew_Snapshots, " slot %u: null", slotsWritten_);
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_CONST);
}
void
SnapshotWriter::endSnapshot()
{
@ -500,47 +268,3 @@ SnapshotWriter::endSnapshot()
IonSpew(IonSpew_Snapshots, "ending snapshot total size: %u bytes (start %u)",
uint32_t(writer_.length() - lastStart_), lastStart_);
}
void
SnapshotWriter::addInt32Slot(int32_t value)
{
IonSpew(IonSpew_Snapshots, " slot %u: int32_t %d", slotsWritten_, value);
if (value >= 0 && uint32_t(value) < MIN_REG_FIELD_ESC) {
writeSlotHeader(JSVAL_TYPE_NULL, value);
} else {
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_INDEX);
writer_.writeSigned(value);
}
}
void
SnapshotWriter::addFloat32Slot(const FloatRegister &reg)
{
JS_ASSERT(uint32_t(reg.code()) < MIN_REG_FIELD_ESC);
IonSpew(IonSpew_Snapshots, " slot %u: float32 (reg %s)", slotsWritten_, reg.name());
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_REG);
writer_.writeUnsigned(reg.code());
}
void
SnapshotWriter::addFloat32Slot(int32_t stackIndex)
{
IonSpew(IonSpew_Snapshots, " slot %u: float32 (stack %d)", slotsWritten_, stackIndex);
writeSlotHeader(JSVAL_TYPE_NULL, ESC_REG_FIELD_FLOAT32_STACK);
writer_.writeSigned(stackIndex);
}
void
SnapshotWriter::addConstantPoolSlot(uint32_t index)
{
IonSpew(IonSpew_Snapshots, " slot %u: constant pool index %u", slotsWritten_, index);
if (index < MIN_REG_FIELD_ESC) {
writeSlotHeader(JSVAL_TYPE_UNDEFINED, index);
} else {
writeSlotHeader(JSVAL_TYPE_UNDEFINED, ESC_REG_FIELD_INDEX);
writer_.writeUnsigned(index);
}
}

View File

@ -147,12 +147,14 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
? MIRType_Undefined
: mir->type();
Slot s;
switch (type) {
case MIRType_Undefined:
snapshots_.addUndefinedSlot();
s = Slot::UndefinedSlot();
break;
case MIRType_Null:
snapshots_.addNullSlot();
s = Slot::NullSlot();
break;
case MIRType_Int32:
case MIRType_String:
@ -165,29 +167,29 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
JSValueType valueType = ValueTypeFromMIRType(type);
if (payload->isMemory()) {
if (type == MIRType_Float32)
snapshots_.addFloat32Slot(ToStackIndex(payload));
s = Slot::Float32Slot(ToStackIndex(payload));
else
snapshots_.addSlot(valueType, ToStackIndex(payload));
s = Slot::TypedSlot(valueType, ToStackIndex(payload));
} else if (payload->isGeneralReg()) {
snapshots_.addSlot(valueType, ToRegister(payload));
s = Slot::TypedSlot(valueType, ToRegister(payload));
} else if (payload->isFloatReg()) {
FloatRegister reg = ToFloatRegister(payload);
if (type == MIRType_Float32)
snapshots_.addFloat32Slot(reg);
s = Slot::Float32Slot(reg);
else
snapshots_.addSlot(reg);
s = Slot::DoubleSlot(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) {
snapshots_.addInt32Slot(v.toInt32());
s = Slot::Int32Slot(v.toInt32());
} else {
uint32_t index;
if (!graph.addConstantToPool(constant->value(), &index))
return false;
snapshots_.addConstantPoolSlot(index);
s = Slot::ConstantPoolSlot(index);
}
}
break;
@ -197,7 +199,7 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
uint32_t index;
if (!graph.addConstantToPool(MagicValue(JS_OPTIMIZED_ARGUMENTS), &index))
return false;
snapshots_.addConstantPoolSlot(index);
s = Slot::ConstantPoolSlot(index);
break;
}
default:
@ -208,24 +210,26 @@ CodeGeneratorShared::encodeSlots(LSnapshot *snapshot, MResumePoint *resumePoint,
LAllocation *type = snapshot->typeOfSlot(i);
if (type->isRegister()) {
if (payload->isRegister())
snapshots_.addSlot(ToRegister(type), ToRegister(payload));
s = Slot::UntypedSlot(ToRegister(type), ToRegister(payload));
else
snapshots_.addSlot(ToRegister(type), ToStackIndex(payload));
s = Slot::UntypedSlot(ToRegister(type), ToStackIndex(payload));
} else {
if (payload->isRegister())
snapshots_.addSlot(ToStackIndex(type), ToRegister(payload));
s = Slot::UntypedSlot(ToStackIndex(type), ToRegister(payload));
else
snapshots_.addSlot(ToStackIndex(type), ToStackIndex(payload));
s = Slot::UntypedSlot(ToStackIndex(type), ToStackIndex(payload));
}
#elif JS_PUNBOX64
if (payload->isRegister())
snapshots_.addSlot(ToRegister(payload));
s = Slot::UntypedSlot(ToRegister(payload));
else
snapshots_.addSlot(ToStackIndex(payload));
s = Slot::UntypedSlot(ToStackIndex(payload));
#endif
break;
}
}
}
snapshots_.addSlot(s);
}
*startIndex += resumePoint->numOperands();

View File

@ -41,6 +41,7 @@ UNIFIED_SOURCES += [
'testIntern.cpp',
'testIntString.cpp',
'testIntTypesABI.cpp',
'testJitSlot.cpp',
'testJSEvaluateScript.cpp',
'testLookup.cpp',
'testLooselyEqual.cpp',

View File

@ -0,0 +1,237 @@
/* -*- 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/CompactBuffer.h"
#include "jit/Slot.h"
#include "jsapi-tests/tests.h"
using namespace js;
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)
{
CompactBufferWriter writer;
slot.write(writer);
CompactBufferReader reader(writer);
return Slot::read(reader);
}
BEGIN_TEST(testJitSlot_Double)
{
Slot s;
for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
s = Slot::DoubleSlot(FloatRegister::FromCode(i));
CHECK(s == ReadSlot(s));
}
return true;
}
END_TEST(testJitSlot_Double)
BEGIN_TEST(testJitSlot_FloatReg)
{
Slot s;
for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
s = Slot::Float32Slot(FloatRegister::FromCode(i));
CHECK(s == ReadSlot(s));
}
return true;
}
END_TEST(testJitSlot_FloatReg)
BEGIN_TEST(testJitSlot_FloatStack)
{
Slot 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));
}
return true;
}
END_TEST(testJitSlot_FloatStack)
BEGIN_TEST(testJitSlot_TypedReg)
{
Slot s;
for (uint32_t i = 0; i < Registers::Total; i++) {
#define FOR_EACH_JSVAL(_) \
/* _(JSVAL_TYPE_DOUBLE) */ \
_(JSVAL_TYPE_INT32) \
/* _(JSVAL_TYPE_UNDEFINED) */ \
_(JSVAL_TYPE_BOOLEAN) \
/* _(JSVAL_TYPE_MAGIC) */ \
_(JSVAL_TYPE_STRING) \
/* _(JSVAL_TYPE_NULL) */ \
_(JSVAL_TYPE_OBJECT)
#define CHECK_WITH_JSVAL(jsval) \
s = Slot::TypedSlot(jsval, Register::FromCode(i)); \
CHECK(s == ReadSlot(s));
FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
#undef CHECK_WITH_JSVAL
#undef FOR_EACH_JSVAL
}
return true;
}
END_TEST(testJitSlot_TypedReg)
BEGIN_TEST(testJitSlot_TypedStack)
{
Slot s;
int32_t i, last = 0, tmp;
for (i = 0; i > 0; tmp = i, i += last, last = tmp) {
#define FOR_EACH_JSVAL(_) \
_(JSVAL_TYPE_DOUBLE) \
_(JSVAL_TYPE_INT32) \
/* _(JSVAL_TYPE_UNDEFINED) */ \
_(JSVAL_TYPE_BOOLEAN) \
/* _(JSVAL_TYPE_MAGIC) */ \
_(JSVAL_TYPE_STRING) \
/* _(JSVAL_TYPE_NULL) */ \
_(JSVAL_TYPE_OBJECT)
#define CHECK_WITH_JSVAL(jsval) \
s = Slot::TypedSlot(jsval, i); \
CHECK(s == ReadSlot(s));
FOR_EACH_JSVAL(CHECK_WITH_JSVAL)
#undef CHECK_WITH_JSVAL
#undef FOR_EACH_JSVAL
}
return true;
}
END_TEST(testJitSlot_TypedStack)
#if defined(JS_NUNBOX32)
BEGIN_TEST(testJitSlot_UntypedRegReg)
{
Slot 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));
}
}
return true;
}
END_TEST(testJitSlot_UntypedRegReg)
BEGIN_TEST(testJitSlot_UntypedRegStack)
{
Slot 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));
}
}
return true;
}
END_TEST(testJitSlot_UntypedRegStack)
BEGIN_TEST(testJitSlot_UntypedStackReg)
{
Slot 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));
}
}
return true;
}
END_TEST(testJitSlot_UntypedStackReg)
BEGIN_TEST(testJitSlot_UntypedStackStack)
{
Slot 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));
}
}
return true;
}
END_TEST(testJitSlot_UntypedStackStack)
#else
BEGIN_TEST(testJitSlot_UntypedReg)
{
Slot s;
for (uint32_t i = 0; i < Registers::Total; i++) {
s = Slot::UntypedSlot(Register::FromCode(i));
CHECK(s == ReadSlot(s));
}
return true;
}
END_TEST(testJitSlot_UntypedReg)
BEGIN_TEST(testJitSlot_UntypedStack)
{
Slot 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));
}
return true;
}
END_TEST(testJitSlot_UntypedStack)
#endif
BEGIN_TEST(testJitSlot_UndefinedAndNull)
{
Slot s;
s = Slot::UndefinedSlot();
CHECK(s == ReadSlot(s));
s = Slot::NullSlot();
CHECK(s == ReadSlot(s));
return true;
}
END_TEST(testJitSlot_UndefinedAndNull)
BEGIN_TEST(testJitSlot_Int32)
{
Slot 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));
}
return true;
}
END_TEST(testJitSlot_Int32)
BEGIN_TEST(testJitSlot_ConstantPool)
{
Slot 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));
}
return true;
}
END_TEST(testJitSlot_ConstantPool)

View File

@ -273,6 +273,7 @@ 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',