From c8de7063866a6bbf0bc9faa13c5f24004c1edf0c Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Fri, 19 Apr 2013 21:13:53 -0400 Subject: [PATCH] Bug 861596 - Add optimized ArgumentsObject stubs to Ion ICs. r=h4writer --- js/src/ion/IonCaches.cpp | 265 +++++++++++++++++++++++--- js/src/ion/IonCaches.h | 12 ++ js/src/ion/IonMacroAssembler.h | 25 +++ js/src/ion/arm/MacroAssembler-arm.cpp | 100 ++++++++-- js/src/ion/arm/MacroAssembler-arm.h | 12 +- js/src/ion/x64/MacroAssembler-x64.h | 46 ++++- js/src/ion/x86/MacroAssembler-x86.h | 60 +++++- 7 files changed, 459 insertions(+), 61 deletions(-) diff --git a/js/src/ion/IonCaches.cpp b/js/src/ion/IonCaches.cpp index de522f126de..79944390c23 100644 --- a/js/src/ion/IonCaches.cpp +++ b/js/src/ion/IonCaches.cpp @@ -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()); diff --git a/js/src/ion/IonCaches.h b/js/src/ion/IonCaches.h index 19920883537..3f7a2884417 100644 --- a/js/src/ion/IonCaches.h +++ b/js/src/ion/IonCaches.h @@ -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, diff --git a/js/src/ion/IonMacroAssembler.h b/js/src/ion/IonMacroAssembler.h index 6f0a583cf79..5c6c74ad128 100644 --- a/js/src/ion/IonMacroAssembler.h +++ b/js/src/ion/IonMacroAssembler.h @@ -166,6 +166,31 @@ class MacroAssembler : public MacroAssemblerSpecific branchPtr(cond, Address(obj, JSObject::offsetOfShape()), shape, label); } + template + 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 + 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. diff --git a/js/src/ion/arm/MacroAssembler-arm.cpp b/js/src/ion/arm/MacroAssembler-arm.cpp index 0076f8d2705..38e35506380 100644 --- a/js/src/ion/arm/MacroAssembler-arm.cpp +++ b/js/src/ion/arm/MacroAssembler-arm.cpp @@ -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) diff --git a/js/src/ion/arm/MacroAssembler-arm.h b/js/src/ion/arm/MacroAssembler-arm.h index 2f8551df591..1b8d4bb8882 100644 --- a/js/src/ion/arm/MacroAssembler-arm.h +++ b/js/src/ion/arm/MacroAssembler-arm.h @@ -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 void branchTestGCThing(Condition cond, const T &t, Label *label) { Condition c = testGCThing(cond, t); diff --git a/js/src/ion/x64/MacroAssembler-x64.h b/js/src/ion/x64/MacroAssembler-x64.h index e6d49ad41e8..dd6cc2b9310 100644 --- a/js/src/ion/x64/MacroAssembler-x64.h +++ b/js/src/ion/x64/MacroAssembler-x64.h @@ -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)); diff --git a/js/src/ion/x86/MacroAssembler-x86.h b/js/src/ion/x86/MacroAssembler-x86.h index 1268c5c009e..42fb5961044 100644 --- a/js/src/ion/x86/MacroAssembler-x86.h +++ b/js/src/ion/x86/MacroAssembler-x86.h @@ -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)