Bug 645416, part 6 - JIT support for symbol values. r=jandem.

Symbols are not yet supported as property keys at this point in the stack. The
work here is to pass symbol pointers around in Ion JIT code unboxed.

The baseline compiler doesn't need much new code. A few kinds of ICs need to
know all the primitive types.

--HG--
extra : rebase_source : 3addcd18e913e5879b0ee3700ecf9660b14b1e05
This commit is contained in:
Jason Orendorff 2014-06-23 10:56:18 -05:00
parent db7aa8370b
commit 245965f7f0
30 changed files with 377 additions and 111 deletions

View File

@ -0,0 +1,8 @@
// ToString(symbol) throws a TypeError.
var obj;
for (var i = 0; i < 10; i++) {
try {
obj = new String(Symbol());
} catch (exc) {}
}

View File

@ -0,0 +1,9 @@
var a = [0, 0, 0, 0, 0, Symbol(), Symbol()];
var b = [];
function f(i, v) {
b[i] = typeof v;
}
for (var i = 0; i < a.length; i++)
f(i, a[i]);
assertEq(b[b.length - 2], "symbol");
assertEq(b[b.length - 1], "symbol");

View File

@ -1693,6 +1693,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
case Bailout_NonBooleanInput:
case Bailout_NonObjectInput:
case Bailout_NonStringInput:
case Bailout_NonSymbolInput:
case Bailout_GuardThreadExclusive:
case Bailout_InitialState:
// Do nothing.

View File

@ -1341,6 +1341,9 @@ ICTypeMonitor_PrimitiveSet::Compiler::generateStubCode(MacroAssembler &masm)
if (flags_ & TypeToFlag(JSVAL_TYPE_STRING))
masm.branchTestString(Assembler::Equal, R0, &success);
if (flags_ & TypeToFlag(JSVAL_TYPE_SYMBOL))
masm.branchTestSymbol(Assembler::Equal, R0, &success);
// Currently, we will never generate primitive stub checks for object. However,
// when we do get to the point where we want to collapse our monitor chains of
// objects and singletons down (when they get too long) to a generic "any object"
@ -1563,6 +1566,9 @@ ICTypeUpdate_PrimitiveSet::Compiler::generateStubCode(MacroAssembler &masm)
if (flags_ & TypeToFlag(JSVAL_TYPE_STRING))
masm.branchTestString(Assembler::Equal, R0, &success);
if (flags_ & TypeToFlag(JSVAL_TYPE_SYMBOL))
masm.branchTestSymbol(Assembler::Equal, R0, &success);
// Currently, we will never generate primitive stub checks for object. However,
// when we do get to the point where we want to collapse our monitor chains of
// objects and singletons down (when they get too long) to a generic "any object"
@ -6287,6 +6293,9 @@ TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc
if (val.isString()) {
primitiveType = JSVAL_TYPE_STRING;
proto = GlobalObject::getOrCreateStringPrototype(cx, global);
} else if (val.isSymbol()) {
primitiveType = JSVAL_TYPE_SYMBOL;
proto = GlobalObject::getOrCreateSymbolPrototype(cx, global);
} else if (val.isNumber()) {
primitiveType = JSVAL_TYPE_DOUBLE;
proto = GlobalObject::getOrCreateNumberPrototype(cx, global);
@ -6529,6 +6538,9 @@ ICGetProp_Primitive::Compiler::generateStubCode(MacroAssembler &masm)
case JSVAL_TYPE_STRING:
masm.branchTestString(Assembler::NotEqual, R0, &failure);
break;
case JSVAL_TYPE_SYMBOL:
masm.branchTestSymbol(Assembler::NotEqual, R0, &failure);
break;
case JSVAL_TYPE_DOUBLE: // Also used for int32.
masm.branchTestNumber(Assembler::NotEqual, R0, &failure);
break;
@ -9754,6 +9766,10 @@ ICTypeOf_Typed::Compiler::generateStubCode(MacroAssembler &masm)
masm.branchTestBoolean(Assembler::NotEqual, R0, &failure);
break;
case JSTYPE_SYMBOL:
masm.branchTestSymbol(Assembler::NotEqual, R0, &failure);
break;
default:
MOZ_ASSUME_UNREACHABLE("Unexpected type");
}

View File

@ -526,10 +526,11 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand &value,
bool mightBeInt32 = valueMIR->mightBeType(MIRType_Int32);
bool mightBeObject = valueMIR->mightBeType(MIRType_Object);
bool mightBeString = valueMIR->mightBeType(MIRType_String);
bool mightBeSymbol = valueMIR->mightBeType(MIRType_Symbol);
bool mightBeDouble = valueMIR->mightBeType(MIRType_Double);
int tagCount = int(mightBeUndefined) + int(mightBeNull) +
int(mightBeBoolean) + int(mightBeInt32) + int(mightBeObject) +
int(mightBeString) + int(mightBeDouble);
int(mightBeString) + int(mightBeSymbol) + int(mightBeDouble);
MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0);
@ -619,6 +620,15 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand &value,
--tagCount;
}
if (mightBeSymbol) {
// All symbols are truthy.
MOZ_ASSERT(tagCount != 0);
if (tagCount != 1)
masm.branchTestSymbol(Assembler::Equal, tag, ifTruthy);
// Else fall through to ifTruthy.
--tagCount;
}
if (mightBeDouble) {
MOZ_ASSERT(tagCount == 1);
// If we reach here the value is a double.
@ -944,6 +954,10 @@ CodeGenerator::visitValueToString(LValueToString *lir)
return false;
}
// Symbol
if (lir->mir()->input()->mightBeType(MIRType_Symbol))
masm.branchTestSymbol(Assembler::Equal, tag, ool->entry());
#ifdef DEBUG
masm.assumeUnreachable("Unexpected type for MValueToString.");
#endif
@ -3209,7 +3223,9 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi
masm.passABIArg(output);
masm.callWithABINoProfiling(mir->type() == MIRType_Object
? JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectPtr)
: JS_FUNC_TO_DATA_PTR(void *, AssertValidStringPtr));
: mir->type() == MIRType_String
? JS_FUNC_TO_DATA_PTR(void *, AssertValidStringPtr)
: JS_FUNC_TO_DATA_PTR(void *, AssertValidSymbolPtr));
restoreVolatile();
}
@ -3290,6 +3306,7 @@ CodeGenerator::emitDebugResultChecks(LInstruction *ins)
switch (mir->type()) {
case MIRType_Object:
case MIRType_String:
case MIRType_Symbol:
return emitObjectOrStringResultChecks(ins, mir);
case MIRType_Value:
return emitValueResultChecks(ins, mir);
@ -7654,7 +7671,19 @@ CodeGenerator::visitTypeOfV(LTypeOfV *lir)
masm.jump(&done);
masm.bind(&notBoolean);
Label notString;
masm.branchTestString(Assembler::NotEqual, tag, &notString);
masm.movePtr(ImmGCPtr(names.string), output);
masm.jump(&done);
masm.bind(&notString);
#ifdef DEBUG
Label isSymbol;
masm.branchTestSymbol(Assembler::Equal, tag, &isSymbol);
masm.assumeUnreachable("Unexpected type for TypeOfV");
masm.bind(&isSymbol);
#endif
masm.movePtr(ImmGCPtr(names.symbol), output);
masm.bind(&done);
if (ool)

View File

@ -1075,6 +1075,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction **def_,
case MIRType_Int32:
case MIRType_Double:
case MIRType_String:
case MIRType_Symbol:
case MIRType_Object:
if (type != def->type()) {
MUnbox *unbox = MUnbox::New(alloc(), def, type, MUnbox::Fallible);
@ -6199,6 +6200,10 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
key = JSProto_String;
break;
case MIRType_Symbol:
key = JSProto_Symbol;
break;
case MIRType_Int32:
case MIRType_Double:
key = JSProto_Number;
@ -6501,6 +6506,7 @@ jit::TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *input
case MIRType_Double:
case MIRType_Float32:
case MIRType_String:
case MIRType_Symbol:
case MIRType_MagicOptimizedArguments:
return types->hasType(types::Type::PrimitiveType(ValueTypeFromMIRType(input)));
@ -7246,9 +7252,13 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
if (obj->mightBeType(MIRType_String))
return true;
// Index should be integer or string
if (!index->mightBeType(MIRType_Int32) && !index->mightBeType(MIRType_String))
// Index should be integer, string, or symbol
if (!index->mightBeType(MIRType_Int32) &&
!index->mightBeType(MIRType_String) &&
!index->mightBeType(MIRType_Symbol))
{
return true;
}
// Turn off cacheing if the element is int32 and we've seen non-native objects as the target
// of this getelem.
@ -7262,9 +7272,9 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj,
nullptr, types);
// Always add a barrier if the index might be a string, so that the cache
// can attach stubs for particular properties.
if (index->mightBeType(MIRType_String))
// Always add a barrier if the index might be a string or symbol, so that
// the cache can attach stubs for particular properties.
if (index->mightBeType(MIRType_String) || index->mightBeType(MIRType_Symbol))
barrier = BarrierKind::TypeSet;
// See note about always needing a barrier in jsop_getprop.
@ -7300,7 +7310,8 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
{
types::TemporaryTypeSet *types = bytecodeTypes(pc);
if (JSOp(*pc) == JSOP_CALLELEM && !index->mightBeType(MIRType_String)) {
MOZ_ASSERT(index->type() == MIRType_Int32 || index->type() == MIRType_Double);
if (JSOp(*pc) == JSOP_CALLELEM) {
// Indexed call on an element of an array. Populate the observed types
// with any objects that could be in the array, to avoid extraneous
// type barriers.
@ -7872,8 +7883,12 @@ IonBuilder::setElemTryCache(bool *emitted, MDefinition *object,
if (!object->mightBeType(MIRType_Object))
return true;
if (!index->mightBeType(MIRType_Int32) && !index->mightBeType(MIRType_String))
if (!index->mightBeType(MIRType_Int32) &&
!index->mightBeType(MIRType_String) &&
!index->mightBeType(MIRType_Symbol))
{
return true;
}
// TODO: Bug 876650: remove this check:
// Temporary disable the cache if non dense native,

View File

@ -3367,6 +3367,7 @@ GetElementIC::attachArgumentsElement(JSContext *cx, HandleScript outerScript, Io
JS_ASSERT(index().reg().type() == MIRType_Boolean ||
index().reg().type() == MIRType_Int32 ||
index().reg().type() == MIRType_String ||
index().reg().type() == MIRType_Symbol ||
index().reg().type() == MIRType_Object);
masm.branchTestMIRType(Assembler::NotEqual, elemIdx, index().reg().type(),
&failureRestoreIndex);

View File

@ -1451,6 +1451,12 @@ FromStringPayload(uintptr_t payload)
return StringValue(reinterpret_cast<JSString *>(payload));
}
static Value
FromSymbolPayload(uintptr_t payload)
{
return SymbolValue(reinterpret_cast<JS::Symbol *>(payload));
}
static Value
FromTypedPayload(JSValueType type, uintptr_t payload)
{
@ -1461,6 +1467,8 @@ FromTypedPayload(JSValueType type, uintptr_t payload)
return BooleanValue(!!payload);
case JSVAL_TYPE_STRING:
return FromStringPayload(payload);
case JSVAL_TYPE_SYMBOL:
return FromSymbolPayload(payload);
case JSVAL_TYPE_OBJECT:
return FromObjectPayload(payload);
default:
@ -1547,6 +1555,8 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset2()));
case JSVAL_TYPE_STRING:
return FromStringPayload(fromStack(alloc.stackOffset2()));
case JSVAL_TYPE_SYMBOL:
return FromSymbolPayload(fromStack(alloc.stackOffset2()));
case JSVAL_TYPE_OBJECT:
return FromObjectPayload(fromStack(alloc.stackOffset2()));
default:

View File

@ -76,11 +76,12 @@ MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types, Barrie
JS_ASSERT(!types->unknown());
Label matched;
types::Type tests[7] = {
types::Type tests[8] = {
types::Type::Int32Type(),
types::Type::UndefinedType(),
types::Type::BooleanType(),
types::Type::StringType(),
types::Type::SymbolType(),
types::Type::NullType(),
types::Type::MagicArgType(),
types::Type::AnyObjectType()
@ -97,7 +98,7 @@ MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types, Barrie
// Emit all typed tests.
BranchType lastBranch;
for (size_t i = 0; i < 7; i++) {
for (size_t i = 0; i < mozilla::ArrayLength(tests); i++) {
if (!types->hasType(tests[i]))
continue;
@ -1678,6 +1679,7 @@ MacroAssembler::convertTypedOrValueToFloatingPoint(TypedOrValueRegister src, Flo
break;
case MIRType_Object:
case MIRType_String:
case MIRType_Symbol:
jump(fail);
break;
case MIRType_Undefined:
@ -1754,7 +1756,7 @@ MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
jump(fail);
}
// The value is null or undefined in truncation contexts - just emit 0.
// The value is null, undefined, or a symbol in truncation contexts - just emit 0.
if (isNull.used())
bind(&isNull);
mov(ImmWord(0), output);
@ -1894,6 +1896,7 @@ MacroAssembler::convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister
convertDoubleToInt(temp, output, temp, nullptr, fail, behavior);
break;
case MIRType_String:
case MIRType_Symbol:
case MIRType_Object:
jump(fail);
break;
@ -1977,6 +1980,9 @@ MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, Reg
case MIRType_String:
branchTestString(Equal, tag, label);
break;
case MIRType_Symbol:
branchTestSymbol(Equal, tag, label);
break;
case MIRType_Object:
branchTestObject(Equal, tag, label);
break;

View File

@ -334,6 +334,7 @@ class MacroAssembler : public MacroAssemblerSpecific
case MIRType_Boolean: return branchTestBoolean(cond, val, label);
case MIRType_Int32: return branchTestInt32(cond, val, label);
case MIRType_String: return branchTestString(cond, val, label);
case MIRType_Symbol: return branchTestSymbol(cond, val, label);
case MIRType_Object: return branchTestObject(cond, val, label);
case MIRType_Double: return branchTestDouble(cond, val, label);
case MIRType_MagicOptimizedArguments: // Fall through.
@ -646,6 +647,7 @@ class MacroAssembler : public MacroAssemblerSpecific
void callPreBarrier(const T &address, MIRType type) {
JS_ASSERT(type == MIRType_Value ||
type == MIRType_String ||
type == MIRType_Symbol ||
type == MIRType_Object ||
type == MIRType_Shape);
Label done;
@ -671,6 +673,7 @@ class MacroAssembler : public MacroAssemblerSpecific
void patchableCallPreBarrier(const T &address, MIRType type) {
JS_ASSERT(type == MIRType_Value ||
type == MIRType_String ||
type == MIRType_Symbol ||
type == MIRType_Object ||
type == MIRType_Shape);

View File

@ -98,6 +98,7 @@ enum BailoutKind
Bailout_NonBooleanInput,
Bailout_NonObjectInput,
Bailout_NonStringInput,
Bailout_NonSymbolInput,
Bailout_GuardThreadExclusive,
@ -189,6 +190,8 @@ BailoutKindString(BailoutKind kind)
return "Bailout_NonObjectInput";
case Bailout_NonStringInput:
return "Bailout_NonStringInput";
case Bailout_NonSymbolInput:
return "Bailout_NonSymbolInput";
case Bailout_GuardThreadExclusive:
return "Bailout_GuardThreadExclusive";
case Bailout_InitialState:
@ -283,6 +286,8 @@ MIRTypeFromValueType(JSValueType type)
return MIRType_Undefined;
case JSVAL_TYPE_STRING:
return MIRType_String;
case JSVAL_TYPE_SYMBOL:
return MIRType_Symbol;
case JSVAL_TYPE_BOOLEAN:
return MIRType_Boolean;
case JSVAL_TYPE_NULL:
@ -313,6 +318,8 @@ ValueTypeFromMIRType(MIRType type)
return JSVAL_TYPE_DOUBLE;
case MIRType_String:
return JSVAL_TYPE_STRING;
case MIRType_Symbol:
return JSVAL_TYPE_SYMBOL;
case MIRType_MagicOptimizedArguments:
case MIRType_MagicOptimizedOut:
case MIRType_MagicHole:
@ -348,6 +355,8 @@ StringFromMIRType(MIRType type)
return "Float32";
case MIRType_String:
return "String";
case MIRType_Symbol:
return "Symbol";
case MIRType_Object:
return "Object";
case MIRType_MagicOptimizedArguments:

View File

@ -531,6 +531,7 @@ class LDefinition
static_assert(sizeof(bool) <= sizeof(int32_t), "bool doesn't fit in an int32 slot");
return LDefinition::INT32;
case MIRType_String:
case MIRType_Symbol:
case MIRType_Object:
return LDefinition::OBJECT;
case MIRType_Double:

View File

@ -657,7 +657,7 @@ LIRGenerator::visitTest(MTest *test)
// String is converted to length of string in the type analysis phase (see
// TestPolicy).
JS_ASSERT(opd->type() != MIRType_String);
MOZ_ASSERT(opd->type() != MIRType_String);
if (opd->type() == MIRType_Value) {
LDefinition temp0, temp1;
@ -688,6 +688,10 @@ LIRGenerator::visitTest(MTest *test)
if (opd->type() == MIRType_Undefined || opd->type() == MIRType_Null)
return add(new(alloc()) LGoto(ifFalse));
// All symbols are truthy.
if (opd->type() == MIRType_Symbol)
return add(new(alloc()) LGoto(ifTrue));
// Constant Double operand.
if (opd->type() == MIRType_Double && opd->isConstant()) {
bool result = opd->toConstant()->valueToBoolean();
@ -1825,9 +1829,10 @@ LIRGenerator::visitToInt32(MToInt32 *convert)
}
case MIRType_String:
case MIRType_Symbol:
case MIRType_Object:
case MIRType_Undefined:
// Objects might be effectful. Undefined coerces to NaN, not int32.
// Objects might be effectful. Undefined and symbols coerce to NaN, not int32.
MOZ_ASSUME_UNREACHABLE("ToInt32 invalid input type");
return false;
@ -1855,6 +1860,7 @@ LIRGenerator::visitTruncateToInt32(MTruncateToInt32 *truncate)
case MIRType_Null:
case MIRType_Undefined:
case MIRType_Symbol:
return define(new(alloc()) LInteger(0), truncate);
case MIRType_Int32:
@ -2457,6 +2463,8 @@ LIRGenerator::visitNot(MNot *ins)
case MIRType_Undefined:
case MIRType_Null:
return define(new(alloc()) LInteger(1), ins);
case MIRType_Symbol:
return define(new(alloc()) LInteger(0), ins);
case MIRType_Object: {
// Objects that don't emulate undefined can be constant-folded.
if (!ins->operandMightEmulateUndefined())

View File

@ -900,6 +900,7 @@ MUnbox::printOpcode(FILE *fp) const
case MIRType_Double: fprintf(fp, "to Double"); break;
case MIRType_Boolean: fprintf(fp, "to Boolean"); break;
case MIRType_String: fprintf(fp, "to String"); break;
case MIRType_Symbol: fprintf(fp, "to Symbol"); break;
case MIRType_Object: fprintf(fp, "to Object"); break;
default: break;
}
@ -1685,10 +1686,11 @@ MUrsh::fallible() const
}
static inline bool
KnownNonStringPrimitive(MDefinition *op)
SimpleArithOperand(MDefinition *op)
{
return !op->mightBeType(MIRType_Object)
&& !op->mightBeType(MIRType_String)
&& !op->mightBeType(MIRType_Symbol)
&& !op->mightBeType(MIRType_MagicOptimizedArguments)
&& !op->mightBeType(MIRType_MagicHole)
&& !op->mightBeType(MIRType_MagicIsConstructing);
@ -1707,9 +1709,9 @@ MBinaryArithInstruction::infer(TempAllocator &alloc, BaselineInspector *inspecto
if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object))
return;
// Anything complex - strings and objects - are not specialized
// Anything complex - strings, symbols, and objects - are not specialized
// unless baseline type hints suggest it might be profitable
if (!KnownNonStringPrimitive(getOperand(0)) || !KnownNonStringPrimitive(getOperand(1)))
if (!SimpleArithOperand(getOperand(0)) || !SimpleArithOperand(getOperand(1)))
return inferFallback(inspector, pc);
// Retrieve type information of lhs and rhs.
@ -1803,9 +1805,9 @@ MBinaryArithInstruction::inferFallback(BaselineInspector *inspector,
static bool
SafelyCoercesToDouble(MDefinition *op)
{
// Strings are unhandled -- visitToDouble() doesn't support them yet.
// Strings and symbols are unhandled -- visitToDouble() doesn't support them yet.
// Null is unhandled -- ToDouble(null) == 0, but (0 == null) is false.
return KnownNonStringPrimitive(op) && !op->mightBeType(MIRType_Null);
return SimpleArithOperand(op) && !op->mightBeType(MIRType_Null);
}
static bool
@ -1813,6 +1815,7 @@ ObjectOrSimplePrimitive(MDefinition *op)
{
// Return true if op is either undefined/null/boolean/int32 or an object.
return !op->mightBeType(MIRType_String)
&& !op->mightBeType(MIRType_Symbol)
&& !op->mightBeType(MIRType_Double)
&& !op->mightBeType(MIRType_Float32)
&& !op->mightBeType(MIRType_MagicOptimizedArguments)
@ -2120,6 +2123,9 @@ MTypeOf::foldsTo(TempAllocator &alloc, bool useValueNumbers)
case MIRType_String:
type = JSTYPE_STRING;
break;
case MIRType_Symbol:
type = JSTYPE_SYMBOL;
break;
case MIRType_Null:
type = JSTYPE_OBJECT;
break;
@ -2458,6 +2464,7 @@ MCompare::tryFold(bool *result)
case MIRType_Double:
case MIRType_Float32:
case MIRType_String:
case MIRType_Symbol:
case MIRType_Boolean:
*result = (op == JSOP_NE || op == JSOP_STRICTNE);
return true;
@ -2477,6 +2484,7 @@ MCompare::tryFold(bool *result)
case MIRType_Double:
case MIRType_Float32:
case MIRType_String:
case MIRType_Symbol:
case MIRType_Object:
case MIRType_Null:
case MIRType_Undefined:
@ -2501,6 +2509,7 @@ MCompare::tryFold(bool *result)
case MIRType_Int32:
case MIRType_Double:
case MIRType_Float32:
case MIRType_Symbol:
case MIRType_Object:
case MIRType_Null:
case MIRType_Undefined:
@ -3440,7 +3449,8 @@ TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *c
case MIRType_Boolean:
case MIRType_Int32:
case MIRType_Double:
case MIRType_String: {
case MIRType_String:
case MIRType_Symbol: {
// The property is a particular primitive type, guard by unboxing the
// value before the write.
if (!(*pvalue)->mightBeType(propertyType)) {

View File

@ -2480,6 +2480,7 @@ class MCompare
// Null compared to Boolean
// Double compared to Boolean
// String compared to Boolean
// Symbol compared to Boolean
// Object compared to Boolean
// Value compared to Boolean
Compare_Boolean,
@ -2703,6 +2704,7 @@ class MUnbox : public MUnaryInstruction, public BoxInputsPolicy
type == MIRType_Int32 ||
type == MIRType_Double ||
type == MIRType_String ||
type == MIRType_Symbol ||
type == MIRType_Object);
setResultType(type);
@ -2734,6 +2736,9 @@ class MUnbox : public MUnaryInstruction, public BoxInputsPolicy
case MIRType_String:
kind = Bailout_NonStringInput;
break;
case MIRType_Symbol:
kind = Bailout_NonSymbolInput;
break;
case MIRType_Object:
kind = Bailout_NonObjectInput;
break;

View File

@ -392,6 +392,8 @@ ValTypeToString(JSValueType type)
return "double";
case JSVAL_TYPE_STRING:
return "string";
case JSVAL_TYPE_SYMBOL:
return "symbol";
case JSVAL_TYPE_BOOLEAN:
return "boolean";
case JSVAL_TYPE_OBJECT:

View File

@ -76,9 +76,11 @@ ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
MInstruction *replace;
// If the input is a string or an object, the conversion is not
// possible, at least, we can't specialize. So box the input.
if (in->type() == MIRType_Object || in->type() == MIRType_String ||
// If the input is a string, symbol, or object, the conversion is not
// possible--at least, we can't specialize. So box the input.
if (in->type() == MIRType_Object ||
in->type() == MIRType_String ||
in->type() == MIRType_Symbol ||
(in->type() == MIRType_Undefined && specialization_ == MIRType_Int32))
{
in = boxAt(alloc, ins, in);
@ -327,6 +329,7 @@ TestPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
case MIRType_Int32:
case MIRType_Double:
case MIRType_Float32:
case MIRType_Symbol:
case MIRType_Object:
break;
@ -474,8 +477,12 @@ DoublePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
if (in->type() == MIRType_Double)
return true;
// Force a bailout. Objects may be effectful; strings are currently unhandled.
if (in->type() == MIRType_Object || in->type() == MIRType_String) {
// Force a bailout. Objects may be effectful; strings and symbols are
// currently unhandled.
if (in->type() == MIRType_Object ||
in->type() == MIRType_String ||
in->type() == MIRType_Symbol)
{
MBox *box = MBox::New(alloc, in);
def->block()->insertBefore(def, box);
@ -502,8 +509,12 @@ Float32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
if (in->type() == MIRType_Float32)
return true;
// Force a bailout. Objects may be effectful; strings are currently unhandled.
if (in->type() == MIRType_Object || in->type() == MIRType_String) {
// Force a bailout. Objects may be effectful; strings and symbols are
// currently unhandled.
if (in->type() == MIRType_Object ||
in->type() == MIRType_String ||
in->type() == MIRType_Symbol)
{
MToDouble *toDouble = MToDouble::New(alloc, in);
def->block()->insertBefore(def, toDouble);
@ -517,7 +528,6 @@ Float32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
def->block()->insertBefore(def, toFloat32);
def->replaceOperand(Op, unbox);
return true;
}
@ -581,8 +591,12 @@ bool
ToDoublePolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
MDefinition *in = ins->getOperand(0);
if (in->type() != MIRType_Object && in->type() != MIRType_String)
if (in->type() != MIRType_Object &&
in->type() != MIRType_String &&
in->type() != MIRType_Symbol)
{
return true;
}
in = boxAt(alloc, ins, in);
ins->replaceOperand(0, in);
@ -598,8 +612,9 @@ ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
switch (in->type()) {
case MIRType_Object:
case MIRType_String:
case MIRType_Symbol:
case MIRType_Undefined:
// Objects might be effectful. Undefined coerces to NaN, not int32.
// Objects might be effectful. Undefined and symbols coerce to NaN, not int32.
in = boxAt(alloc, ins, in);
ins->replaceOperand(0, in);
break;
@ -615,7 +630,8 @@ ToStringPolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
JS_ASSERT(ins->isToString());
if (ins->getOperand(0)->type() == MIRType_Object) {
MIRType type = ins->getOperand(0)->type();
if (type == MIRType_Object || type == MIRType_Symbol) {
ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
return true;
}
@ -726,6 +742,7 @@ StoreTypedArrayPolicy::adjustValueInput(TempAllocator &alloc, MInstruction *ins,
break;
case MIRType_Object:
case MIRType_String:
case MIRType_Symbol:
value = boxAt(alloc, ins, value);
break;
default:

View File

@ -1158,17 +1158,34 @@ AssertValidStringPtr(JSContext *cx, JSString *str)
JS_ASSERT(kind == gc::FINALIZE_STRING);
}
void
AssertValidSymbolPtr(JSContext *cx, JS::Symbol *sym)
{
// We can't closely inspect symbols from another runtime.
if (sym->runtimeFromAnyThread() != cx->runtime())
return;
JS_ASSERT(cx->runtime()->isAtomsZone(sym->tenuredZone()));
JS_ASSERT(sym->runtimeFromMainThread() == cx->runtime());
JS_ASSERT(sym->isAligned());
if (JSString *desc = sym->description()) {
JS_ASSERT(desc->isAtom());
AssertValidStringPtr(cx, desc);
}
JS_ASSERT(sym->tenuredGetAllocKind() == gc::FINALIZE_SYMBOL);
}
void
AssertValidValue(JSContext *cx, Value *v)
{
if (v->isObject()) {
if (v->isObject())
AssertValidObjectPtr(cx, &v->toObject());
return;
}
if (v->isString()) {
else if (v->isString())
AssertValidStringPtr(cx, v->toString());
return;
}
else if (v->isSymbol())
AssertValidSymbolPtr(cx, v->toSymbol());
}
#endif

View File

@ -688,6 +688,7 @@ bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue
#ifdef DEBUG
void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
void AssertValidStringPtr(JSContext *cx, JSString *str);
void AssertValidSymbolPtr(JSContext *cx, JS::Symbol *sym);
void AssertValidValue(JSContext *cx, Value *v);
#endif

View File

@ -2728,6 +2728,12 @@ MacroAssemblerARMCompat::testString(Assembler::Condition cond, const ValueOperan
return testString(cond, value.typeReg());
}
Assembler::Condition
MacroAssemblerARMCompat::testSymbol(Assembler::Condition cond, const ValueOperand &value)
{
return testSymbol(cond, value.typeReg());
}
Assembler::Condition
MacroAssemblerARMCompat::testObject(Assembler::Condition cond, const ValueOperand &value)
{
@ -2770,26 +2776,37 @@ MacroAssemblerARMCompat::testBoolean(Assembler::Condition cond, Register tag)
}
Assembler::Condition
MacroAssemblerARMCompat::testNull(Assembler::Condition cond, Register tag) {
MacroAssemblerARMCompat::testNull(Assembler::Condition cond, Register tag)
{
JS_ASSERT(cond == Equal || cond == NotEqual);
ma_cmp(tag, ImmTag(JSVAL_TAG_NULL));
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testUndefined(Assembler::Condition cond, Register tag) {
MacroAssemblerARMCompat::testUndefined(Assembler::Condition cond, Register tag)
{
JS_ASSERT(cond == Equal || cond == NotEqual);
ma_cmp(tag, ImmTag(JSVAL_TAG_UNDEFINED));
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testString(Assembler::Condition cond, Register tag) {
MacroAssemblerARMCompat::testString(Assembler::Condition cond, Register tag)
{
JS_ASSERT(cond == Equal || cond == NotEqual);
ma_cmp(tag, ImmTag(JSVAL_TAG_STRING));
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testSymbol(Assembler::Condition cond, Register tag)
{
JS_ASSERT(cond == Equal || cond == NotEqual);
ma_cmp(tag, ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testObject(Assembler::Condition cond, Register tag)
{
@ -2881,6 +2898,14 @@ MacroAssemblerARMCompat::testString(Condition cond, const Address &address)
return testString(cond, ScratchRegister);
}
Assembler::Condition
MacroAssemblerARMCompat::testSymbol(Condition cond, const Address &address)
{
JS_ASSERT(cond == Equal || cond == NotEqual);
extractTag(address, ScratchRegister);
return testSymbol(cond, ScratchRegister);
}
Assembler::Condition
MacroAssemblerARMCompat::testObject(Condition cond, const Address &address)
{
@ -2950,6 +2975,15 @@ MacroAssemblerARMCompat::testString(Condition cond, const BaseIndex &src)
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testSymbol(Condition cond, const BaseIndex &src)
{
JS_ASSERT(cond == Equal || cond == NotEqual);
extractTag(src, ScratchRegister);
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testInt32(Condition cond, const BaseIndex &src)
{
@ -3045,25 +3079,14 @@ MacroAssemblerARMCompat::branchTestValue(Condition cond, const Address &valaddr,
// unboxing code
void
MacroAssemblerARMCompat::unboxInt32(const ValueOperand &operand, Register dest)
MacroAssemblerARMCompat::unboxNonDouble(const ValueOperand &operand, Register dest)
{
ma_mov(operand.payloadReg(), dest);
if (operand.payloadReg() != dest)
ma_mov(operand.payloadReg(), dest);
}
void
MacroAssemblerARMCompat::unboxInt32(const Address &src, Register dest)
{
ma_ldr(payloadOf(src), dest);
}
void
MacroAssemblerARMCompat::unboxBoolean(const ValueOperand &operand, Register dest)
{
ma_mov(operand.payloadReg(), dest);
}
void
MacroAssemblerARMCompat::unboxBoolean(const Address &src, Register dest)
MacroAssemblerARMCompat::unboxNonDouble(const Address &src, Register dest)
{
ma_ldr(payloadOf(src), dest);
}
@ -3082,30 +3105,6 @@ MacroAssemblerARMCompat::unboxDouble(const Address &src, FloatRegister dest)
ma_vldr(Operand(src), dest);
}
void
MacroAssemblerARMCompat::unboxString(const ValueOperand &operand, Register dest)
{
ma_mov(operand.payloadReg(), dest);
}
void
MacroAssemblerARMCompat::unboxString(const Address &src, Register dest)
{
ma_ldr(payloadOf(src), dest);
}
void
MacroAssemblerARMCompat::unboxObject(const ValueOperand &src, Register dest)
{
ma_mov(src.payloadReg(), dest);
}
void
MacroAssemblerARMCompat::unboxObject(const Address &src, Register dest)
{
ma_ldr(payloadOf(src), dest);
}
void
MacroAssemblerARMCompat::unboxValue(const ValueOperand &src, AnyRegister dest)
{

View File

@ -746,6 +746,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testNull(Condition cond, const ValueOperand &value);
Condition testUndefined(Condition cond, const ValueOperand &value);
Condition testString(Condition cond, const ValueOperand &value);
Condition testSymbol(Condition cond, const ValueOperand &value);
Condition testObject(Condition cond, const ValueOperand &value);
Condition testNumber(Condition cond, const ValueOperand &value);
Condition testMagic(Condition cond, const ValueOperand &value);
@ -758,6 +759,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testNull(Condition cond, Register tag);
Condition testUndefined(Condition cond, Register tag);
Condition testString(Condition cond, Register tag);
Condition testSymbol(Condition cond, Register tag);
Condition testObject(Condition cond, Register tag);
Condition testDouble(Condition cond, Register tag);
Condition testNumber(Condition cond, Register tag);
@ -772,6 +774,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testNull(Condition cond, const Address &address);
Condition testUndefined(Condition cond, const Address &address);
Condition testString(Condition cond, const Address &address);
Condition testSymbol(Condition cond, const Address &address);
Condition testObject(Condition cond, const Address &address);
Condition testNumber(Condition cond, const Address &address);
@ -779,6 +782,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testNull(Condition cond, const BaseIndex &src);
Condition testBoolean(Condition cond, const BaseIndex &src);
Condition testString(Condition cond, const BaseIndex &src);
Condition testSymbol(Condition cond, const BaseIndex &src);
Condition testInt32(Condition cond, const BaseIndex &src);
Condition testObject(Condition cond, const BaseIndex &src);
Condition testDouble(Condition cond, const BaseIndex &src);
@ -801,16 +805,20 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Label *label);
// unboxing code
void unboxInt32(const ValueOperand &operand, Register dest);
void unboxInt32(const Address &src, Register dest);
void unboxBoolean(const ValueOperand &operand, Register dest);
void unboxBoolean(const Address &src, Register dest);
void unboxDouble(const ValueOperand &operand, FloatRegister dest);
void unboxNonDouble(const ValueOperand &operand, Register dest);
void unboxNonDouble(const Address &src, Register dest);
void unboxInt32(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxInt32(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxDouble(const ValueOperand &src, FloatRegister dest);
void unboxDouble(const Address &src, FloatRegister dest);
void unboxString(const ValueOperand &operand, Register dest);
void unboxString(const Address &src, Register dest);
void unboxObject(const ValueOperand &src, Register dest);
void unboxObject(const Address &src, Register dest);
void unboxValue(const ValueOperand &src, AnyRegister dest);
void unboxPrivate(const ValueOperand &src, Register dest);
@ -936,6 +944,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
ma_b(label, c);
}
template<typename T>
void branchTestSymbol(Condition cond, const T & t, Label *label) {
Condition c = testSymbol(cond, t);
ma_b(label, c);
}
template<typename T>
void branchTestUndefined(Condition cond, const T & t, Label *label) {
Condition c = testUndefined(cond, t);
ma_b(label, c);

View File

@ -2320,6 +2320,27 @@ MacroAssemblerMIPSCompat::branchTestString(Condition cond, const BaseIndex &src,
ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_STRING), label, cond);
}
void
MacroAssemblerMIPSCompat::branchTestSymbol(Condition cond, const ValueOperand &value, Label *label)
{
branchTestSymbol(cond, value.typeReg(), label);
}
void
MacroAssemblerMIPSCompat::branchTestSymbol(Condition cond, const Register &tag, Label *label)
{
MOZ_ASSERT(cond == Equal || cond == NotEqual);
ma_b(tag, ImmTag(JSVAL_TAG_SYMBOL), label, cond);
}
void
MacroAssemblerMIPSCompat::branchTestSymbol(Condition cond, const BaseIndex &src, Label *label)
{
MOZ_ASSERT(cond == Equal || cond == NotEqual);
extractTag(src, SecondScratchReg);
ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_SYMBOL), label, cond);
}
void
MacroAssemblerMIPSCompat::branchTestUndefined(Condition cond, const ValueOperand &value,
Label *label)

View File

@ -691,6 +691,10 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
void branchTestString(Condition cond, Register tag, Label *label);
void branchTestString(Condition cond, const BaseIndex &src, Label *label);
void branchTestSymbol(Condition cond, const ValueOperand &value, Label *label);
void branchTestSymbol(Condition cond, const Register &tag, Label *label);
void branchTestSymbol(Condition cond, const BaseIndex &src, Label *label);
void branchTestUndefined(Condition cond, const ValueOperand &value, Label *label);
void branchTestUndefined(Condition cond, Register tag, Label *label);
void branchTestUndefined(Condition cond, const BaseIndex &src, Label *label);

View File

@ -177,6 +177,7 @@ CodeGeneratorShared::encodeAllocation(LSnapshot *snapshot, MDefinition *mir,
break;
case MIRType_Int32:
case MIRType_String:
case MIRType_Symbol:
case MIRType_Object:
case MIRType_Boolean:
case MIRType_Double:

View File

@ -9,6 +9,8 @@
#include "jit/LIR.h"
#include "jit/MIR.h"
#include "vm/Symbol.h"
using namespace js;
using namespace jit;
@ -23,6 +25,8 @@ LIRGeneratorShared::visitConstant(MConstant *ins)
return define(new(alloc()) LInteger(v.toInt32()), ins);
case MIRType_String:
return define(new(alloc()) LPointer(v.toString()), ins);
case MIRType_Symbol:
return define(new(alloc()) LPointer(v.toSymbol()), ins);
case MIRType_Object:
return define(new(alloc()) LPointer(&v.toObject()), ins);
default:

View File

@ -106,6 +106,9 @@ CodeGeneratorX64::visitUnbox(LUnbox *unbox)
case MIRType_String:
cond = masm.testString(Assembler::NotEqual, value);
break;
case MIRType_Symbol:
cond = masm.testSymbol(Assembler::NotEqual, value);
break;
default:
MOZ_ASSUME_UNREACHABLE("Given MIRType cannot be unboxed.");
}
@ -126,6 +129,9 @@ CodeGeneratorX64::visitUnbox(LUnbox *unbox)
case MIRType_String:
masm.unboxString(value, ToRegister(result));
break;
case MIRType_Symbol:
masm.unboxSymbol(value, ToRegister(result));
break;
default:
MOZ_ASSUME_UNREACHABLE("Given MIRType cannot be unboxed.");
}

View File

@ -281,6 +281,11 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
cmpl(tag, ImmTag(JSVAL_TAG_STRING));
return cond;
}
Condition testSymbol(Condition cond, Register tag) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpl(tag, ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Condition testObject(Condition cond, Register tag) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
@ -344,6 +349,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
splitTag(src, ScratchReg);
return testString(cond, ScratchReg);
}
Condition testSymbol(Condition cond, const ValueOperand &src) {
splitTag(src, ScratchReg);
return testSymbol(cond, ScratchReg);
}
Condition testObject(Condition cond, const ValueOperand &src) {
splitTag(src, ScratchReg);
return testObject(cond, ScratchReg);
@ -386,6 +395,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
splitTag(src, ScratchReg);
return testString(cond, ScratchReg);
}
Condition testSymbol(Condition cond, const Address &src) {
splitTag(src, ScratchReg);
return testSymbol(cond, ScratchReg);
}
Condition testObject(Condition cond, const Address &src) {
splitTag(src, ScratchReg);
return testObject(cond, ScratchReg);
@ -420,6 +433,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
splitTag(src, ScratchReg);
return testString(cond, ScratchReg);
}
Condition testSymbol(Condition cond, const BaseIndex &src) {
splitTag(src, ScratchReg);
return testSymbol(cond, ScratchReg);
}
Condition testInt32(Condition cond, const BaseIndex &src) {
splitTag(src, ScratchReg);
return testInt32(cond, ScratchReg);
@ -839,6 +856,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
cond = testString(cond, tag);
j(cond, label);
}
void branchTestSymbol(Condition cond, Register tag, Label *label) {
cond = testSymbol(cond, tag);
j(cond, label);
}
void branchTestObject(Condition cond, Register tag, Label *label) {
cond = testObject(cond, tag);
j(cond, label);
@ -915,6 +936,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
cond = testString(cond, src);
j(cond, label);
}
void branchTestSymbol(Condition cond, const ValueOperand &src, Label *label) {
cond = testSymbol(cond, src);
j(cond, label);
}
void branchTestObject(Condition cond, const ValueOperand &src, Label *label) {
cond = testObject(cond, src);
j(cond, label);
@ -950,6 +975,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
cond = testString(cond, address);
j(cond, label);
}
void branchTestSymbol(Condition cond, const BaseIndex &address, Label *label) {
cond = testSymbol(cond, address);
j(cond, label);
}
void branchTestObject(Condition cond, const BaseIndex &address, Label *label) {
cond = testObject(cond, address);
j(cond, label);
@ -1094,6 +1123,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
void unboxString(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const Operand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Operand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Operand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address &src, Register dest) { unboxNonDouble(Operand(src), dest); }

View File

@ -290,6 +290,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
cmpl(tag, ImmTag(JSVAL_TAG_STRING));
return cond;
}
Condition testSymbol(Condition cond, Register tag) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpl(tag, ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Condition testObject(Condition cond, Register tag) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
@ -382,6 +387,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
Condition testString(Condition cond, const ValueOperand &value) {
return testString(cond, value.typeReg());
}
Condition testSymbol(Condition cond, const ValueOperand &value) {
return testSymbol(cond, value.typeReg());
}
Condition testObject(Condition cond, const ValueOperand &value) {
return testObject(cond, value.typeReg());
}
@ -422,6 +430,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
cmpl(tagOf(address), ImmTag(JSVAL_TAG_STRING));
return cond;
}
Condition testSymbol(Condition cond, const BaseIndex &address) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpl(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Condition testInt32(Condition cond, const BaseIndex &address) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpl(tagOf(address), ImmTag(JSVAL_TAG_INT32));
@ -751,6 +764,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
j(cond, label);
}
template <typename T>
void branchTestSymbol(Condition cond, const T &t, Label *label) {
cond = testSymbol(cond, t);
j(cond, label);
}
template <typename T>
void branchTestObject(Condition cond, const T &t, Label *label) {
cond = testObject(cond, t);
j(cond, label);
@ -793,28 +811,27 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
movl(src, dest.payloadReg());
movl(ImmType(type), dest.typeReg());
}
void unboxInt32(const ValueOperand &src, Register dest) {
movl(src.payloadReg(), dest);
}
void unboxInt32(const Address &src, Register dest) {
movl(payloadOf(src), dest);
}
void unboxDouble(const Address &src, FloatRegister dest) {
loadDouble(Operand(src), dest);
}
void unboxBoolean(const ValueOperand &src, Register dest) {
movl(src.payloadReg(), dest);
}
void unboxBoolean(const Address &src, Register dest) {
movl(payloadOf(src), dest);
}
void unboxObject(const ValueOperand &src, Register dest) {
void unboxNonDouble(const ValueOperand &src, Register dest) {
if (src.payloadReg() != dest)
movl(src.payloadReg(), dest);
}
void unboxObject(const Address &src, Register dest) {
void unboxNonDouble(const Address &src, Register dest) {
movl(payloadOf(src), dest);
}
void unboxInt32(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxInt32(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand &src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address &src, Register dest) { unboxNonDouble(src, dest); }
void unboxDouble(const Address &src, FloatRegister dest) {
loadDouble(Operand(src), dest);
}
void unboxDouble(const ValueOperand &src, FloatRegister dest) {
JS_ASSERT(dest != ScratchFloatReg);
if (Assembler::HasSSE41()) {
@ -842,12 +859,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
unpcklps(ScratchFloatReg, dest);
}
}
void unboxString(const ValueOperand &src, Register dest) {
movl(src.payloadReg(), dest);
}
void unboxString(const Address &src, Register dest) {
movl(payloadOf(src), dest);
}
void unboxValue(const ValueOperand &src, AnyRegister dest) {
if (dest.isFloat()) {
Label notInt32, end;

View File

@ -297,6 +297,7 @@ class Type
static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); }
static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
static inline Type SymbolType() { return Type(JSVAL_TYPE_SYMBOL); }
static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); }
static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }

View File

@ -339,6 +339,12 @@ class GlobalObject : public JSObject
return &global->getPrototype(JSProto_String).toObject();
}
static JSObject *getOrCreateSymbolPrototype(JSContext *cx, Handle<GlobalObject*> global) {
if (!ensureConstructor(cx, global, JSProto_Symbol))
return nullptr;
return &global->getPrototype(JSProto_Symbol).toObject();
}
static JSObject *getOrCreateRegExpPrototype(JSContext *cx, Handle<GlobalObject*> global) {
if (!ensureConstructor(cx, global, JSProto_RegExp))
return nullptr;