mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 861596 - Add optimized ArgumentsObject stubs to Ion ICs. r=h4writer
This commit is contained in:
parent
043d238980
commit
bd36917c01
@ -398,8 +398,14 @@ IonCache::linkAndAttachStub(JSContext *cx, MacroAssembler &masm, StubAttacher &a
|
||||
|
||||
attachStub(masm, attacher, code);
|
||||
|
||||
IonSpew(IonSpew_InlineCaches, "Generated %s %s stub at %p",
|
||||
attachKind, CacheName(kind()), code->raw());
|
||||
if (pc) {
|
||||
IonSpew(IonSpew_InlineCaches, "Cache %p(%s:%d/%d) generated %s %s stub at %p",
|
||||
this, script->filename(), script->lineno, pc - script->code,
|
||||
attachKind, CacheName(kind()), code->raw());
|
||||
} else {
|
||||
IonSpew(IonSpew_InlineCaches, "Cache %p generated %s %s stub at %p",
|
||||
this, attachKind, CacheName(kind()), code->raw());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -543,6 +549,39 @@ IsCacheableNoProperty(JSObject *obj, JSObject *holder, RawShape shape, jsbytecod
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsOptimizableArgumentsObjectForLength(JSObject *obj)
|
||||
{
|
||||
if (!obj->isArguments())
|
||||
return false;
|
||||
|
||||
if (obj->asArguments().hasOverriddenLength())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsOptimizableArgumentsObjectForGetElem(JSObject *obj, Value idval)
|
||||
{
|
||||
if (!IsOptimizableArgumentsObjectForLength(obj))
|
||||
return false;
|
||||
|
||||
ArgumentsObject &argsObj = obj->asArguments();
|
||||
|
||||
if (argsObj.isAnyElementDeleted())
|
||||
return false;
|
||||
|
||||
if (!idval.isInt32())
|
||||
return false;
|
||||
|
||||
int32_t idint = idval.toInt32();
|
||||
if (idint < 0 || idint >= argsObj.initialLength())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, RawShape shape)
|
||||
{
|
||||
@ -1076,6 +1115,61 @@ GetPropertyIC::attachTypedArrayLength(JSContext *cx, IonScript *ion, JSObject *o
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "typed array length");
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropertyIC::attachArgumentsLength(JSContext *cx, IonScript *ion, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
JS_ASSERT(!idempotent());
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
Register tmpReg;
|
||||
if (output().hasValue()) {
|
||||
tmpReg = output().valueReg().scratchReg();
|
||||
} else {
|
||||
JS_ASSERT(output().type() == MIRType_Int32);
|
||||
tmpReg = output().typedReg().gpr();
|
||||
}
|
||||
JS_ASSERT(object() != tmpReg);
|
||||
|
||||
Class *clasp = obj->isStrictArguments() ? &StrictArgumentsObjectClass
|
||||
: &NormalArgumentsObjectClass;
|
||||
|
||||
Label fail;
|
||||
Label pass;
|
||||
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, clasp, &failures);
|
||||
|
||||
// Get initial ArgsObj length value, test if length has been overridden.
|
||||
masm.unboxInt32(Address(object(), ArgumentsObject::getInitialLengthSlotOffset()), tmpReg);
|
||||
masm.branchTest32(Assembler::NonZero, tmpReg, Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT),
|
||||
&failures);
|
||||
|
||||
masm.rshiftPtr(Imm32(ArgumentsObject::PACKED_BITS_COUNT), tmpReg);
|
||||
|
||||
// If output is Int32, result is already in right place, otherwise box it into output.
|
||||
if (output().hasValue())
|
||||
masm.tagValue(JSVAL_TYPE_INT32, tmpReg, output().valueReg());
|
||||
|
||||
// Success.
|
||||
attacher.jumpRejoin(masm);
|
||||
|
||||
// Failure.
|
||||
masm.bind(&failures);
|
||||
attacher.jumpNextStub(masm);
|
||||
|
||||
if (obj->isStrictArguments()) {
|
||||
JS_ASSERT(!hasStrictArgumentsLengthStub_);
|
||||
hasStrictArgumentsLengthStub_ = true;
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (strict)");
|
||||
}
|
||||
|
||||
JS_ASSERT(!hasNormalArgumentsLengthStub_);
|
||||
hasNormalArgumentsLengthStub_ = true;
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (normal)");
|
||||
}
|
||||
|
||||
static bool
|
||||
IsIdempotentAndMaybeHasHooks(IonCache &cache, JSObject *obj)
|
||||
{
|
||||
@ -1146,6 +1240,7 @@ TryAttachNativeGetPropStub(JSContext *cx, IonScript *ion,
|
||||
void *returnAddr, bool *isCacheable)
|
||||
{
|
||||
JS_ASSERT(!*isCacheable);
|
||||
JS_ASSERT(cache.canAttachStub());
|
||||
|
||||
RootedObject checkObj(cx, obj);
|
||||
if (IsCacheableListBase(obj)) {
|
||||
@ -1186,10 +1281,6 @@ TryAttachNativeGetPropStub(JSContext *cx, IonScript *ion,
|
||||
|
||||
*isCacheable = true;
|
||||
|
||||
// Falback to the interpreter function.
|
||||
if (!cache.canAttachStub())
|
||||
return true;
|
||||
|
||||
if (readSlot)
|
||||
return cache.attachReadSlot(cx, ion, obj, holder, shape);
|
||||
else if (obj->isArray() && !cache.hasArrayLengthStub() && cx->names().length == name)
|
||||
@ -1221,25 +1312,35 @@ GetPropertyIC::update(JSContext *cx, size_t cacheIndex,
|
||||
// limit. Once we can make calls from within generated stubs, a new call
|
||||
// stub will be generated instead and the previous stubs unlinked.
|
||||
bool isCacheable = false;
|
||||
if (!TryAttachNativeGetPropStub(cx, ion, cache, obj, name,
|
||||
safepointIndex, returnAddr,
|
||||
&isCacheable))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isCacheable && cache.canAttachStub() &&
|
||||
!cache.idempotent() && cx->names().length == name)
|
||||
{
|
||||
if (cache.output().type() != MIRType_Value && cache.output().type() != MIRType_Int32) {
|
||||
// The next execution should cause an invalidation because the type
|
||||
// does not fit.
|
||||
isCacheable = false;
|
||||
} else if (obj->isTypedArray() && !cache.hasTypedArrayLengthStub()) {
|
||||
if (cache.canAttachStub()) {
|
||||
if (name == cx->names().length &&
|
||||
IsOptimizableArgumentsObjectForLength(obj) &&
|
||||
(cache.output().type() == MIRType_Value || cache.output().type() == MIRType_Int32) &&
|
||||
!cache.hasArgumentsLengthStub(obj->isStrictArguments()))
|
||||
{
|
||||
isCacheable = true;
|
||||
if (!cache.attachTypedArrayLength(cx, ion, obj))
|
||||
if (!cache.attachArgumentsLength(cx, ion, obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isCacheable && !TryAttachNativeGetPropStub(cx, ion, cache, obj, name,
|
||||
safepointIndex, returnAddr,
|
||||
&isCacheable))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isCacheable && !cache.idempotent() && cx->names().length == name) {
|
||||
if (cache.output().type() != MIRType_Value && cache.output().type() != MIRType_Int32) {
|
||||
// The next execution should cause an invalidation because the type
|
||||
// does not fit.
|
||||
isCacheable = false;
|
||||
} else if (obj->isTypedArray() && !cache.hasTypedArrayLengthStub()) {
|
||||
isCacheable = true;
|
||||
if (!cache.attachTypedArrayLength(cx, ion, obj))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.idempotent() && !isCacheable) {
|
||||
@ -2115,6 +2216,114 @@ GetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, JSObject *o
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "typed array");
|
||||
}
|
||||
|
||||
bool
|
||||
GetElementIC::attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
Register tmpReg = output().scratchReg().gpr();
|
||||
JS_ASSERT(tmpReg != InvalidReg);
|
||||
|
||||
Class *clasp = obj->isStrictArguments() ? &StrictArgumentsObjectClass
|
||||
: &NormalArgumentsObjectClass;
|
||||
|
||||
Label fail;
|
||||
Label pass;
|
||||
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, clasp, &failures);
|
||||
|
||||
// Get initial ArgsObj length value, test if length has been overridden.
|
||||
masm.unboxInt32(Address(object(), ArgumentsObject::getInitialLengthSlotOffset()), tmpReg);
|
||||
masm.branchTest32(Assembler::NonZero, tmpReg, Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT),
|
||||
&failures);
|
||||
|
||||
// Decide to what type index the stub should be optimized
|
||||
Register indexReg;
|
||||
JS_ASSERT(!index().constant());
|
||||
|
||||
// Check index against length.
|
||||
Label failureRestoreIndex;
|
||||
if (index().reg().hasValue()) {
|
||||
ValueOperand val = index().reg().valueReg();
|
||||
masm.branchTestInt32(Assembler::NotEqual, val, &failures);
|
||||
indexReg = val.scratchReg();
|
||||
|
||||
masm.unboxInt32(val, indexReg);
|
||||
masm.branch32(Assembler::AboveOrEqual, indexReg, tmpReg, &failureRestoreIndex);
|
||||
} else {
|
||||
JS_ASSERT(index().reg().type() == MIRType_Int32);
|
||||
indexReg = index().reg().typedReg().gpr();
|
||||
masm.branch32(Assembler::AboveOrEqual, indexReg, tmpReg, &failures);
|
||||
}
|
||||
// Save indexReg because it needs to be clobbered to check deleted bit.
|
||||
Label failurePopIndex;
|
||||
masm.push(indexReg);
|
||||
|
||||
// Check if property was deleted on arguments object.
|
||||
masm.loadPrivate(Address(object(), ArgumentsObject::getDataSlotOffset()), tmpReg);
|
||||
masm.loadPtr(Address(tmpReg, offsetof(ArgumentsData, deletedBits)), tmpReg);
|
||||
|
||||
// In tempReg, calculate index of word containing bit: (idx >> logBitsPerWord)
|
||||
masm.rshiftPtr(Imm32(JS_BITS_PER_WORD_LOG2), indexReg);
|
||||
masm.loadPtr(BaseIndex(tmpReg, indexReg, ScaleFromElemWidth(sizeof(size_t))), tmpReg);
|
||||
|
||||
// Don't bother testing specific bit, if any bit is set in the word, fail.
|
||||
masm.branchPtr(Assembler::NotEqual, tmpReg, ImmWord((size_t)0), &failurePopIndex);
|
||||
|
||||
// Get the address to load from into tmpReg
|
||||
masm.loadPrivate(Address(object(), ArgumentsObject::getDataSlotOffset()), tmpReg);
|
||||
masm.addPtr(Imm32(ArgumentsData::offsetOfArgs()), tmpReg);
|
||||
|
||||
// Restore original index register value, to use for indexing element.
|
||||
masm.pop(indexReg);
|
||||
BaseIndex elemIdx(tmpReg, indexReg, ScaleFromElemWidth(sizeof(Value)));
|
||||
|
||||
// Ensure result is not magic value, and type-check result.
|
||||
masm.branchTestMagic(Assembler::Equal, elemIdx, &failureRestoreIndex);
|
||||
|
||||
if (output().hasTyped()) {
|
||||
JS_ASSERT(!output().typedReg().isFloat());
|
||||
JS_ASSERT(index().reg().type() == MIRType_Boolean ||
|
||||
index().reg().type() == MIRType_Int32 ||
|
||||
index().reg().type() == MIRType_String ||
|
||||
index().reg().type() == MIRType_Object);
|
||||
masm.branchTestMIRType(Assembler::NotEqual, elemIdx, index().reg().type(),
|
||||
&failureRestoreIndex);
|
||||
}
|
||||
|
||||
masm.loadTypedOrValue(elemIdx, output());
|
||||
|
||||
// indexReg may need to be reconstructed if it was originally a value.
|
||||
if (index().reg().hasValue())
|
||||
masm.tagValue(JSVAL_TYPE_INT32, indexReg, index().reg().valueReg());
|
||||
|
||||
// Success.
|
||||
attacher.jumpRejoin(masm);
|
||||
|
||||
// Restore the object before continuing to the next stub.
|
||||
masm.bind(&failurePopIndex);
|
||||
masm.pop(indexReg);
|
||||
masm.bind(&failureRestoreIndex);
|
||||
if (index().reg().hasValue())
|
||||
masm.tagValue(JSVAL_TYPE_INT32, indexReg, index().reg().valueReg());
|
||||
masm.bind(&failures);
|
||||
attacher.jumpNextStub(masm);
|
||||
|
||||
|
||||
if (obj->isStrictArguments()) {
|
||||
JS_ASSERT(!hasStrictArgumentsStub_);
|
||||
hasStrictArgumentsStub_ = true;
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (strict)");
|
||||
}
|
||||
|
||||
JS_ASSERT(!hasNormalArgumentsStub_);
|
||||
hasNormalArgumentsStub_ = true;
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (normal)");
|
||||
}
|
||||
|
||||
bool
|
||||
GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
|
||||
HandleValue idval, MutableHandleValue res)
|
||||
@ -2143,7 +2352,17 @@ GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
|
||||
|
||||
bool attachedStub = false;
|
||||
if (cache.canAttachStub()) {
|
||||
if (obj->isNative() && cache.monitoredResult()) {
|
||||
if (IsOptimizableArgumentsObjectForGetElem(obj, idval) &&
|
||||
!cache.hasArgumentsStub(obj->isStrictArguments()) &&
|
||||
!cache.index().constant() &&
|
||||
(cache.index().reg().hasValue() ||
|
||||
cache.index().reg().type() == MIRType_Int32) &&
|
||||
(cache.output().hasValue() || !cache.output().typedReg().isFloat()))
|
||||
{
|
||||
if (!cache.attachArgumentsElement(cx, ion, obj))
|
||||
return false;
|
||||
attachedStub = true;
|
||||
} else if (obj->isNative() && cache.monitoredResult()) {
|
||||
uint32_t dummy;
|
||||
if (idval.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy)) {
|
||||
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
|
||||
|
@ -497,6 +497,8 @@ class GetPropertyIC : public RepatchIonCache
|
||||
bool allowGetters_ : 1;
|
||||
bool hasArrayLengthStub_ : 1;
|
||||
bool hasTypedArrayLengthStub_ : 1;
|
||||
bool hasStrictArgumentsLengthStub_ : 1;
|
||||
bool hasNormalArgumentsLengthStub_ : 1;
|
||||
|
||||
public:
|
||||
GetPropertyIC(RegisterSet liveRegs,
|
||||
@ -535,6 +537,9 @@ class GetPropertyIC : public RepatchIonCache
|
||||
bool hasTypedArrayLengthStub() const {
|
||||
return hasTypedArrayLengthStub_;
|
||||
}
|
||||
bool hasArgumentsLengthStub(bool strict) const {
|
||||
return strict ? hasStrictArgumentsLengthStub_ : hasNormalArgumentsLengthStub_;
|
||||
}
|
||||
|
||||
bool attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
||||
HandleShape shape);
|
||||
@ -543,6 +548,7 @@ class GetPropertyIC : public RepatchIonCache
|
||||
const SafepointIndex *safepointIndex, void *returnAddr);
|
||||
bool attachArrayLength(JSContext *cx, IonScript *ion, JSObject *obj);
|
||||
bool attachTypedArrayLength(JSContext *cx, IonScript *ion, JSObject *obj);
|
||||
bool attachArgumentsLength(JSContext *cx, IonScript *ion, JSObject *obj);
|
||||
|
||||
static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
|
||||
};
|
||||
@ -609,6 +615,8 @@ class GetElementIC : public RepatchIonCache
|
||||
|
||||
bool monitoredResult_ : 1;
|
||||
bool hasDenseStub_ : 1;
|
||||
bool hasStrictArgumentsStub_ : 1;
|
||||
bool hasNormalArgumentsStub_ : 1;
|
||||
|
||||
size_t failedUpdates_;
|
||||
|
||||
@ -645,6 +653,9 @@ class GetElementIC : public RepatchIonCache
|
||||
bool hasDenseStub() const {
|
||||
return hasDenseStub_;
|
||||
}
|
||||
bool hasArgumentsStub(bool strict) const {
|
||||
return strict ? hasStrictArgumentsStub_ : hasNormalArgumentsStub_;
|
||||
}
|
||||
void setHasDenseStub() {
|
||||
JS_ASSERT(!hasDenseStub());
|
||||
hasDenseStub_ = true;
|
||||
@ -653,6 +664,7 @@ class GetElementIC : public RepatchIonCache
|
||||
bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
|
||||
bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
|
||||
bool attachTypedArrayElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
|
||||
bool attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj);
|
||||
|
||||
static bool
|
||||
update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
|
||||
|
@ -166,6 +166,31 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
branchPtr(cond, Address(obj, JSObject::offsetOfShape()), shape, label);
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Condition testMIRType(Condition cond, const Value &val, MIRType type) {
|
||||
JS_ASSERT(type == MIRType_Null || type == MIRType_Undefined ||
|
||||
type == MIRType_Boolean || type == MIRType_Int32 ||
|
||||
type == MIRType_String || type == MIRType_Object ||
|
||||
type == MIRType_Double);
|
||||
switch (type) {
|
||||
case MIRType_Null: return testNull(cond, val);
|
||||
case MIRType_Undefined: return testUndefined(cond, val);
|
||||
case MIRType_Boolean: return testBoolean(cond, val);
|
||||
case MIRType_Int32: return testInt32(cond, val);
|
||||
case MIRType_String: return testString(cond, val);
|
||||
case MIRType_Object: return testObject(cond, val);
|
||||
case MIRType_Double: return testDouble(cond, val);
|
||||
default:
|
||||
JS_NOT_REACHED("Bad MIRType");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
void branchTestMIRType(Condition cond, const Value &val, MIRType type, Label *label) {
|
||||
cond = testMIRType(cond, val, type);
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
// Branches to |label| if |reg| is false. |reg| should be a C++ bool.
|
||||
void branchIfFalseBool(const Register ®, Label *label) {
|
||||
// Note that C++ bool is only 1 byte, so ignore the higher-order bits.
|
||||
|
@ -2299,15 +2299,6 @@ MacroAssemblerARMCompat::testGCThing(Assembler::Condition cond, const Address &a
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testGCThing(Assembler::Condition cond, const BaseIndex &address)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testMagic(Assembler::Condition cond, const Address &address)
|
||||
{
|
||||
@ -2317,15 +2308,6 @@ MacroAssemblerARMCompat::testMagic(Assembler::Condition cond, const Address &add
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testMagic(Assembler::Condition cond, const BaseIndex &address)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testInt32(Assembler::Condition cond, const Address &address)
|
||||
{
|
||||
@ -2360,6 +2342,88 @@ MacroAssemblerARMCompat::testNumber(Condition cond, const Register &tag)
|
||||
return cond == Equal ? BelowOrEqual : Above;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testUndefined(Condition cond, const BaseIndex &src)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testNull(Condition cond, const BaseIndex &src)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_NULL));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testBoolean(Condition cond, const BaseIndex &src)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testString(Condition cond, const BaseIndex &src)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_STRING));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testInt32(Condition cond, const BaseIndex &src)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_INT32));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testObject(Condition cond, const BaseIndex &src)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_OBJECT));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testDouble(Condition cond, const BaseIndex &src)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
Assembler::Condition actual = (cond == Equal) ? Below : AboveOrEqual;
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(value.typeReg(), ImmTag(JSVAL_TAG_CLEAR));
|
||||
return actual;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testMagic(Assembler::Condition cond, const BaseIndex &address)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
|
||||
Assembler::Condition
|
||||
MacroAssemblerARMCompat::testGCThing(Assembler::Condition cond, const BaseIndex &address)
|
||||
{
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::branchTestValue(Condition cond, const ValueOperand &value, const Value &v,
|
||||
Label *label)
|
||||
|
@ -640,12 +640,20 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
Condition testPrimitive(Condition cond, const Register &tag);
|
||||
|
||||
Condition testGCThing(Condition cond, const Address &address);
|
||||
Condition testGCThing(Condition cond, const BaseIndex &address);
|
||||
Condition testMagic(Condition cond, const Address &address);
|
||||
Condition testMagic(Condition cond, const BaseIndex &address);
|
||||
Condition testInt32(Condition cond, const Address &address);
|
||||
Condition testDouble(Condition cond, const Address &address);
|
||||
|
||||
Condition testUndefined(Condition cond, const BaseIndex &src);
|
||||
Condition testNull(Condition cond, const BaseIndex &src);
|
||||
Condition testBoolean(Condition cond, const BaseIndex &src);
|
||||
Condition testString(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);
|
||||
Condition testMagic(Condition cond, const BaseIndex &src);
|
||||
Condition testGCThing(Condition cond, const BaseIndex &src);
|
||||
|
||||
template <typename T>
|
||||
void branchTestGCThing(Condition cond, const T &t, Label *label) {
|
||||
Condition c = testGCThing(cond, t);
|
||||
|
@ -318,23 +318,53 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
splitTag(src, ScratchReg);
|
||||
return testGCThing(cond, ScratchReg);
|
||||
}
|
||||
Condition testGCThing(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testGCThing(cond, ScratchReg);
|
||||
}
|
||||
Condition testMagic(Condition cond, const Address &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testMagic(cond, ScratchReg);
|
||||
}
|
||||
Condition testMagic(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testMagic(cond, ScratchReg);
|
||||
}
|
||||
Condition testPrimitive(Condition cond, const ValueOperand &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testPrimitive(cond, ScratchReg);
|
||||
}
|
||||
|
||||
|
||||
Condition testUndefined(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testUndefined(cond, ScratchReg);
|
||||
}
|
||||
Condition testNull(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testNull(cond, ScratchReg);
|
||||
}
|
||||
Condition testBoolean(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testBoolean(cond, ScratchReg);
|
||||
}
|
||||
Condition testString(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testString(cond, ScratchReg);
|
||||
}
|
||||
Condition testInt32(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testInt32(cond, ScratchReg);
|
||||
}
|
||||
Condition testObject(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testObject(cond, ScratchReg);
|
||||
}
|
||||
Condition testDouble(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testDouble(cond, ScratchReg);
|
||||
}
|
||||
Condition testMagic(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testMagic(cond, ScratchReg);
|
||||
}
|
||||
Condition testGCThing(Condition cond, const BaseIndex &src) {
|
||||
splitTag(src, ScratchReg);
|
||||
return testGCThing(cond, ScratchReg);
|
||||
}
|
||||
|
||||
Condition isMagic(Condition cond, const ValueOperand &src, JSWhyMagic why) {
|
||||
uint64_t magic = MagicValue(why).asRawBits();
|
||||
cmpPtr(src.valueReg(), ImmWord(magic));
|
||||
|
@ -281,21 +281,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
Condition testGCThing(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
Condition testMagic(Condition cond, const Address &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testMagic(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testMagic(Condition cond, const Register &tag) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_MAGIC));
|
||||
@ -370,6 +360,56 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
return testPrimitive(cond, value.typeReg());
|
||||
}
|
||||
|
||||
|
||||
Condition testUndefined(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
return cond;
|
||||
}
|
||||
Condition testNull(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_NULL));
|
||||
return cond;
|
||||
}
|
||||
Condition testBoolean(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
return cond;
|
||||
}
|
||||
Condition testString(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_STRING));
|
||||
return cond;
|
||||
}
|
||||
Condition testInt32(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_INT32));
|
||||
return cond;
|
||||
}
|
||||
Condition testObject(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
|
||||
return cond;
|
||||
}
|
||||
Condition testDouble(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
Condition actual = (cond == Equal) ? Below : AboveOrEqual;
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
|
||||
return actual;
|
||||
}
|
||||
Condition testMagic(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testGCThing(Condition cond, const BaseIndex &address) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label);
|
||||
void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value,
|
||||
Label *label)
|
||||
|
Loading…
Reference in New Issue
Block a user