☠☠ backed out by fdf520ad7dbc ☠ ☠ | |
author | Tom Schuster <evilpies@gmail.com> |
Wed, 18 Jul 2012 01:22:15 +0200 | |
changeset 106557 | 183decadb9acf6825a364dc18685a8e9eb72831a |
parent 106556 | 8144319a6464e3c76b3ec5fca75a65f1a61e114d |
child 106558 | 8dd41661cf09782ae692e36dffc2a3f580e7e003 |
push id | 23447 |
push user | danderson@mozilla.com |
push date | Tue, 11 Sep 2012 17:34:27 +0000 |
treeherder | mozilla-central@fdfaef738a00 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 725966 |
milestone | 16.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -1655,17 +1655,17 @@ CodeGenerator::visitBinaryV(LBinaryV *li JS_NOT_REACHED("Unexpected binary op"); return false; } } bool CodeGenerator::visitCompareS(LCompareS *lir) { - JSOp op = lir->mir()->jsop(); + JSOp op = lir->jsop(); Register left = ToRegister(lir->left()); Register right = ToRegister(lir->right()); Register output = ToRegister(lir->output()); typedef bool (*pf)(JSContext *, HandleString, HandleString, JSBool *); static const VMFunction stringsEqualInfo = FunctionInfo<pf>(ion::StringsEqual<true>); static const VMFunction stringsNotEqualInfo = FunctionInfo<pf>(ion::StringsEqual<false>); @@ -1829,16 +1829,225 @@ CodeGenerator::visitIsNullOrUndefinedAnd cond = masm.testNull(cond, value); else cond = masm.testUndefined(cond, value); emitBranch(cond, lir->ifTrue(), lir->ifFalse()); return true; } +static JSType +StringToJSType(JSContext *cx, JSLinearString *str) +{ + JSRuntime *rt = cx->runtime; + + if (EqualStrings(str, rt->atomState.typeAtoms[JSTYPE_STRING])) + return JSTYPE_STRING; + if (EqualStrings(str, rt->atomState.typeAtoms[JSTYPE_NUMBER])) + return JSTYPE_NUMBER; + if (EqualStrings(str, rt->atomState.typeAtoms[JSTYPE_BOOLEAN])) + return JSTYPE_BOOLEAN; + if (EqualStrings(str, rt->atomState.typeAtoms[JSTYPE_VOID])) + return JSTYPE_VOID; + if (EqualStrings(str, rt->atomState.typeAtoms[JSTYPE_OBJECT])) + return JSTYPE_OBJECT; + if (EqualStrings(str, rt->atomState.typeAtoms[JSTYPE_FUNCTION])) + return JSTYPE_FUNCTION; + if (EqualStrings(str, rt->atomState.typeAtoms[JSTYPE_XML])) + return JSTYPE_XML; + return JSTYPE_LIMIT; +} + + +bool +CodeGenerator::visitTypeOfIs(LTypeOfIs *lir) +{ + JSOp op = lir->jsop(); + const ValueOperand value = ToValue(lir, LTypeOfIs::Value); + Register output = ToRegister(lir->output()); + + JSContext *cx = gen->cx; + JSLinearString *str = lir->value().toString()->ensureLinear(cx); + if (!str) + return false; + + JSType type = StringToJSType(cx, str); + + Assembler::Condition cond = JSOpToCondition(op); + if (type == JSTYPE_STRING) { + cond = masm.testString(cond, value); + emitSet(cond, output); + } else if (type == JSTYPE_NUMBER) { + cond = masm.testNumber(cond, value); + emitSet(cond, output); + } else if (type == JSTYPE_BOOLEAN) { + cond = masm.testBoolean(cond, value); + emitSet(cond, output); + } else if (type == JSTYPE_VOID) { + cond = masm.testUndefined(cond, value); + emitSet(cond, output); + } else if (type == JSTYPE_OBJECT) { + Register tag = masm.splitTagForTest(value); + + Label isObject, isntObject, done; + masm.branchTestNull(Assembler::Equal, tag, &isObject); + masm.branchTestObject(Assembler::NotEqual, tag, &isntObject); + + Register object = masm.extractObject(value, output); + masm.loadObjClass(object, output); + + // JSFunction is special, because there is no Call hook in Class for them. + masm.cmpPtr(output, ImmWord(&FunctionClass)); + masm.j(Assembler::Equal, &isntObject); + + // The typeof hook could tell us anything, eg. "xml". + masm.cmpPtr(Address(output, offsetof(Class, ops.typeOf)), ImmWord(reinterpret_cast<void *>(NULL))); + if (!bailoutIf(Assembler::NotEqual, lir->snapshot())) + return false; + + // Per ES5 everything which has no [[Call]] is an object. + masm.cmpPtr(Address(output, offsetof(Class, call)), ImmWord(reinterpret_cast<void *>(NULL))); + masm.j(Assembler::NotEqual, &isntObject); + + masm.bind(&isObject); + masm.move32(Imm32(op == JSOP_EQ || op == JSOP_STRICTEQ), output); + masm.jump(&done); + + masm.bind(&isntObject); + masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output); + masm.bind(&done); + } else if (type == JSTYPE_FUNCTION) { + Register tag = masm.splitTagForTest(value); + + Label isFunction, isntFunction, done; + masm.branchTestObject(Assembler::NotEqual, tag, &isntFunction); + + Register object = masm.extractObject(value, output); + masm.loadObjClass(object, output); + + masm.cmpPtr(output, ImmWord(&FunctionClass)); + masm.j(Assembler::Equal, &isFunction); + + masm.cmpPtr(Address(output, offsetof(Class, ops.typeOf)), ImmWord(reinterpret_cast<void *>(NULL))); + if (!bailoutIf(Assembler::NotEqual, lir->snapshot())) + return false; + + masm.cmpPtr(Address(output, offsetof(Class, call)), ImmWord(reinterpret_cast<void *>(NULL))); + masm.j(Assembler::Equal, &isntFunction); + + masm.bind(&isFunction); + masm.move32(Imm32(op == JSOP_EQ || op == JSOP_STRICTEQ), output); + masm.jump(&done); + + masm.bind(&isntFunction); + masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output); + masm.bind(&done); + } else if (type == JSTYPE_XML) { + // Don't even really bother. + cond = masm.testObject(Assembler::Equal, value); + if (!bailoutIf(cond, lir->snapshot())) + return false; + masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output); + } else { + JS_ASSERT(type == JSTYPE_LIMIT); + // This happens for code like |typeof x == 'banana'|, because this would never be + // equal to any type we can always return false. + masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output); + } + return true; +} + +bool +CodeGenerator::visitTypeOfIsAndBranch(LTypeOfIsAndBranch *lir) +{ + JSOp op = lir->jsop(); + const ValueOperand value = ToValue(lir, LTypeOfIsAndBranch::Value); + + JSContext *cx = gen->cx; + JSLinearString *str = lir->value().toString()->ensureLinear(cx); + if (!str) + return false; + + JSType type = StringToJSType(cx, str); + + MBasicBlock *ifTrue; + MBasicBlock *ifFalse; + + if (op == JSOP_EQ || op == JSOP_STRICTEQ) { + ifTrue = lir->ifTrue(); + ifFalse = lir->ifFalse(); + } else { + // Swap branches. + ifTrue = lir->ifFalse(); + ifFalse = lir->ifTrue(); + } + + if (type == JSTYPE_STRING) { + Assembler::Condition cond = masm.testString(Assembler::Equal, value); + emitBranch(cond, ifTrue, ifFalse); + } else if (type == JSTYPE_NUMBER) { + Assembler::Condition cond = masm.testNumber(Assembler::Equal, value); + emitBranch(cond, ifTrue, ifFalse); + } else if (type == JSTYPE_BOOLEAN) { + Assembler::Condition cond = masm.testBoolean(Assembler::Equal, value); + emitBranch(cond, ifTrue, ifFalse); + } else if (type == JSTYPE_VOID) { + Assembler::Condition cond = masm.testUndefined(Assembler::Equal, value); + emitBranch(cond, ifTrue, ifFalse); + } else if (type == JSTYPE_OBJECT) { + Register tag = masm.splitTagForTest(value); + Register temp = ToRegister(lir->temp()); + + masm.branchTestNull(Assembler::Equal, tag, ifTrue->lir()->label()); + masm.branchTestObject(Assembler::NotEqual, tag, ifFalse->lir()->label()); + + Register object = masm.extractObject(value, temp); + masm.loadObjClass(object, temp); + + masm.cmpPtr(temp, ImmWord(&FunctionClass)); + masm.j(Assembler::Equal, ifFalse->lir()->label()); + + masm.cmpPtr(Address(temp, offsetof(Class, ops.typeOf)), ImmWord(reinterpret_cast<void *>(NULL))); + if (!bailoutIf(Assembler::NotEqual, lir->snapshot())) + return false; + + masm.cmpPtr(Address(temp, offsetof(Class, call)), ImmWord(reinterpret_cast<void *>(NULL))); + emitBranch(Assembler::Equal, ifTrue, ifFalse); + } else if (type == JSTYPE_FUNCTION) { + Register tag = masm.splitTagForTest(value); + Register temp = ToRegister(lir->temp()); + + masm.branchTestObject(Assembler::NotEqual, tag, ifFalse->lir()->label()); + + Register object = masm.extractObject(value, temp); + masm.loadObjClass(object, temp); + + masm.cmpPtr(temp, ImmWord(&FunctionClass)); + masm.j(Assembler::Equal, ifTrue->lir()->label()); + + masm.cmpPtr(Address(temp, offsetof(Class, ops.typeOf)), ImmWord(reinterpret_cast<void *>(NULL))); + if (!bailoutIf(Assembler::NotEqual, lir->snapshot())) + return false; + + masm.cmpPtr(Address(temp, offsetof(Class, call)), ImmWord(reinterpret_cast<void *>(NULL))); + emitBranch(Assembler::NotEqual, ifTrue, ifFalse); + } else if (type == JSTYPE_XML) { + // Don't even really bother. + Assembler::Condition cond = masm.testObject(Assembler::Equal, value); + if (!bailoutIf(cond, lir->snapshot())) + return false; + masm.jump(ifFalse->lir()->label()); + } else { + JS_ASSERT(type == JSTYPE_LIMIT); + masm.jump(ifFalse->lir()->label()); + } + + return true; +} + bool CodeGenerator::visitConcat(LConcat *lir) { typedef JSString *(*pf)(JSContext *, HandleString, HandleString); static const VMFunction js_ConcatStringsInfo = FunctionInfo<pf>(js_ConcatStrings); pushArg(ToRegister(lir->rhs())); pushArg(ToRegister(lir->lhs()));
--- a/js/src/ion/CodeGenerator.h +++ b/js/src/ion/CodeGenerator.h @@ -142,16 +142,18 @@ class CodeGenerator : public CodeGenerat bool visitStoreFixedSlotT(LStoreFixedSlotT *ins); bool visitAbsI(LAbsI *lir); bool visitMathFunctionD(LMathFunctionD *ins); bool visitBinaryV(LBinaryV *lir); bool visitCompareS(LCompareS *lir); bool visitCompareV(LCompareV *lir); bool visitIsNullOrUndefined(LIsNullOrUndefined *lir); bool visitIsNullOrUndefinedAndBranch(LIsNullOrUndefinedAndBranch *lir); + bool visitTypeOfIs(LTypeOfIs *lir); + bool visitTypeOfIsAndBranch(LTypeOfIsAndBranch *lir); bool visitConcat(LConcat *lir); bool visitCharCodeAt(LCharCodeAt *lir); bool visitFromCharCode(LFromCharCode *lir); bool visitFunctionEnvironment(LFunctionEnvironment *lir); bool visitCallGetProperty(LCallGetProperty *lir); bool visitCallGetElement(LCallGetElement *lir); bool visitCallSetElement(LCallSetElement *lir); bool visitThrow(LThrow *lir);
--- a/js/src/ion/LIR-Common.h +++ b/js/src/ion/LIR-Common.h @@ -857,23 +857,30 @@ class LCompareD : public LInstructionHel } MCompare *mir() { return mir_->toCompare(); } }; class LCompareS : public LInstructionHelper<1, 2, 0> { + JSOp jsop_; + public: LIR_HEADER(CompareS); - LCompareS(const LAllocation &left, const LAllocation &right) { + LCompareS(JSOp jsop, const LAllocation &left, const LAllocation &right) + : jsop_(jsop) + { setOperand(0, left); setOperand(1, right); } + JSOp jsop() const{ + return jsop_; + } const LAllocation *left() { return getOperand(0); } const LAllocation *right() { return getOperand(1); } const LDefinition *output() { return getDef(0); @@ -1061,16 +1068,81 @@ class LIsNullOrUndefinedAndBranch : publ MBasicBlock *ifFalse() const { return ifFalse_; } MCompare *mir() { return mir_->toCompare(); } }; +class LTypeOfIs : public LInstructionHelper<1, BOX_PIECES, 0> +{ + JSOp op_; + const js::Value v_; + + public: + LIR_HEADER(TypeOfIs); + + LTypeOfIs(JSOp op, const js::Value &v) + : op_(op), v_(v) + { } + + static const size_t Value = 0; + + JSOp jsop() { + return op_; + } + js::Value value() { + return v_; + } + const LDefinition *output() { + return getDef(0); + } +}; + +class LTypeOfIsAndBranch : public LInstructionHelper<0, BOX_PIECES, 1> +{ + JSOp jsop_; + const js::Value v_; + MBasicBlock *ifTrue_; + MBasicBlock *ifFalse_; + + public: + LIR_HEADER(TypeOfIsAndBranch); + + LTypeOfIsAndBranch(JSOp jsop, const js::Value &v, const LDefinition &temp, + MBasicBlock *ifTrue, MBasicBlock *ifFalse) + : jsop_(jsop), + v_(v), + ifTrue_(ifTrue), + ifFalse_(ifFalse) + { + setTemp(0, temp); + } + + static const size_t Value = 0; + + JSOp jsop() const { + return jsop_; + } + js::Value value() { + return v_; + } + const LDefinition *temp() { + return getTemp(0); + } + MBasicBlock *ifTrue() const { + return ifTrue_; + } + MBasicBlock *ifFalse() const { + return ifFalse_; + } + +}; + // Not operation on an integer. class LNotI : public LInstructionHelper<1, 1, 0> { public: LIR_HEADER(NotI); LNotI(const LAllocation &input) { setOperand(0, input);
--- a/js/src/ion/LOpcodes.h +++ b/js/src/ion/LOpcodes.h @@ -87,16 +87,18 @@ _(CompareS) \ _(CompareV) \ _(CompareAndBranch) \ _(CompareDAndBranch) \ _(CompareB) \ _(CompareBAndBranch) \ _(IsNullOrUndefined) \ _(IsNullOrUndefinedAndBranch) \ + _(TypeOfIs) \ + _(TypeOfIsAndBranch) \ _(AbsI) \ _(AbsD) \ _(SqrtD) \ _(MathFunctionD) \ _(NotI) \ _(NotD) \ _(NotV) \ _(AddI) \
--- a/js/src/ion/Lowering.cpp +++ b/js/src/ion/Lowering.cpp @@ -339,16 +339,24 @@ ReorderComparison(JSOp op, MDefinition * if (lhs->isConstant()) { *rhsp = lhs; *lhsp = rhs; return js::analyze::ReverseCompareOp(op); } return op; } +inline bool +IsTypeOfCompare(MDefinition *left, MDefinition *right) +{ + if (!left->isTypeOf() || !right->isConstant()) + return false; + return right->toConstant()->value().isString(); +} + bool LIRGenerator::visitTest(MTest *test) { MDefinition *opd = test->getOperand(0); MBasicBlock *ifTrue = test->ifTrue(); MBasicBlock *ifFalse = test->ifFalse(); if (opd->type() == MIRType_Value) { @@ -396,16 +404,33 @@ LIRGenerator::visitTest(MTest *test) // first operand. if (IsNullOrUndefined(comp->specialization())) { LIsNullOrUndefinedAndBranch *lir = new LIsNullOrUndefinedAndBranch(ifTrue, ifFalse); if (!useBox(lir, LIsNullOrUndefinedAndBranch::Value, left)) return false; return add(lir, comp); } + + if (comp->specialization() == MIRType_String) { + // We can safely reorder, because operand order doesn't matter for LCompareS. + JSOp op = ReorderComparison(comp->jsop(), &left, &right); + if (IsTypeOfCompare(left, right)) { + MTypeOf *typeOf = left->toTypeOf(); + + LTypeOfIsAndBranch *lir = new LTypeOfIsAndBranch(op, right->toConstant()->value(), + temp(), ifTrue, ifFalse); + if (!useBox(lir, LTypeOfIsAndBranch::Value, typeOf->input())) + return false; + if (!assignSnapshot(lir)) + return false; + return add(lir, comp); + } + } + if (comp->specialization() == MIRType_Boolean) { JS_ASSERT(left->type() == MIRType_Value); JS_ASSERT(right->type() == MIRType_Boolean); LCompareBAndBranch *lir = new LCompareBAndBranch(useRegisterOrConstant(right), ifTrue, ifFalse); if (!useBox(lir, LCompareBAndBranch::Lhs, left)) return false; @@ -424,63 +449,53 @@ bool LIRGenerator::visitInlineFunctionGuard(MInlineFunctionGuard *ins) { LInlineFunctionGuard *lir = new LInlineFunctionGuard(useRegister(ins->input()), ins->function(), ins->functionBlock(), ins->fallbackBlock()); return add(lir); } -static inline bool -CanEmitCompareAtUses(MInstruction *ins) +inline bool +CanEmitInstructionAtUses(MInstruction *ins, MDefinition::Opcode op) { if (!ins->canEmitAtUses()) return false; - bool foundTest = false; + bool alreadyUsed = false; for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) { MNode *node = iter->node(); if (!node->isDefinition()) return false; - if (!node->toDefinition()->isTest()) + if (node->toDefinition()->op() != op) return false; - if (foundTest) + if (alreadyUsed) return false; - foundTest = true; + alreadyUsed = true; } return true; } bool LIRGenerator::visitCompare(MCompare *comp) { MDefinition *left = comp->lhs(); MDefinition *right = comp->rhs(); if (comp->specialization() != MIRType_None) { // Try to fold the comparison so that we don't have to handle all cases. bool result; if (comp->tryFold(&result)) return define(new LInteger(result), comp); - // Move below the emitAtUses call if we ever implement - // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't - // make sense and avoids confusion. - if (comp->specialization() == MIRType_String) { - LCompareS *lir = new LCompareS(useRegister(left), useRegister(right)); - if (!define(lir, comp)) - return false; - return assignSafepoint(lir, comp); - } - // Sniff out if the output of this compare is used only for a branching. // If it is, then we willl emit an LCompare*AndBranch instruction in place // of this compare and any test that uses this compare. Thus, we can // ignore this Compare. - if (CanEmitCompareAtUses(comp)) + if (CanEmitInstructionAtUses(comp, MDefinition::Op_Test)) return emitAtUses(comp); if (comp->specialization() == MIRType_Int32 || comp->specialization() == MIRType_Object) { JSOp op = ReorderComparison(comp->jsop(), &left, &right); LAllocation rhs = comp->specialization() == MIRType_Object ? useRegister(right) : useAnyOrConstant(right); return define(new LCompare(op, useRegister(left), rhs), comp); @@ -494,16 +509,36 @@ LIRGenerator::visitCompare(MCompare *com JS_ASSERT(right->type() == MIRType_Boolean); LCompareB *lir = new LCompareB(useRegisterOrConstant(right)); if (!useBox(lir, LCompareB::Lhs, left)) return false; return define(lir, comp); } + if (comp->specialization() == MIRType_String) { + JSOp op = ReorderComparison(comp->jsop(), &left, &right); + + if (IsTypeOfCompare(left, right)) { + MTypeOf *typeOf = left->toTypeOf(); + + LTypeOfIs *lir = new LTypeOfIs(op, right->toConstant()->value()); + if (!useBox(lir, LTypeOfIs::Value, typeOf->input())) + return false; + if (!assignSnapshot(lir)) + return false; + return define(lir, comp); + } + + LCompareS *lir = new LCompareS(op, useRegister(left), useRegister(right)); + if (!define(lir, comp)) + return false; + return assignSafepoint(lir, comp); + } + JS_ASSERT(IsNullOrUndefined(comp->specialization())); LIsNullOrUndefined *lir = new LIsNullOrUndefined(); if (!useBox(lir, LIsNullOrUndefined::Value, comp->getOperand(0))) return false; return define(lir, comp); } @@ -549,16 +584,19 @@ LIRGenerator::lowerBitOp(JSOp op, MInstr } bool LIRGenerator::visitTypeOf(MTypeOf *ins) { MDefinition *opd = ins->input(); JS_ASSERT(opd->type() == MIRType_Value); + if (CanEmitInstructionAtUses(ins, MDefinition::Op_Compare)) + return emitAtUses(ins); + LTypeOfV *lir = new LTypeOfV(); if (!useBox(lir, LTypeOfV::Input, opd)) return false; return define(lir, ins) && assignSafepoint(lir, ins); } bool LIRGenerator::visitToId(MToId *ins)
--- a/js/src/ion/arm/MacroAssembler-arm.cpp +++ b/js/src/ion/arm/MacroAssembler-arm.cpp @@ -1969,28 +1969,40 @@ MacroAssemblerARMCompat::testInt32(Assem Assembler::Condition MacroAssemblerARMCompat::testBoolean(Assembler::Condition cond, const ValueOperand &value) { JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); ma_cmp(value.typeReg(), ImmType(JSVAL_TYPE_BOOLEAN)); return cond; } + Assembler::Condition MacroAssemblerARMCompat::testDouble(Assembler::Condition cond, const ValueOperand &value) { JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); Assembler::Condition actual = (cond == Equal) ? Below : AboveOrEqual; ma_cmp(value.typeReg(), ImmTag(JSVAL_TAG_CLEAR)); return actual; } Assembler::Condition +MacroAssemblerARMCompat::testNumber(Assembler::Condition cond, const ValueOperand &value) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + Assembler::Condition actual = (cond == Equal) + ? BelowOrEqual + : Above; + ma_cmp(value.typeReg(), ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)); + return actual; +} + +Assembler::Condition MacroAssemblerARMCompat::testNull(Assembler::Condition cond, const ValueOperand &value) { JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); ma_cmp(value.typeReg(), ImmType(JSVAL_TYPE_NULL)); return cond; } Assembler::Condition
--- a/js/src/ion/arm/MacroAssembler-arm.h +++ b/js/src/ion/arm/MacroAssembler-arm.h @@ -526,16 +526,17 @@ class MacroAssemblerARMCompat : public M Register splitTagForTest(const ValueOperand &value) { return value.typeReg(); } // higher level tag testing code Condition testInt32(Condition cond, const ValueOperand &value); Condition testBoolean(Condition cond, const ValueOperand &value); Condition testDouble(Condition cond, const ValueOperand &value); + Condition testNumber(Condition cond, const ValueOperand &value); Condition testNull(Condition cond, const ValueOperand &value); Condition testUndefined(Condition cond, const ValueOperand &value); Condition testString(Condition cond, const ValueOperand &value); Condition testObject(Condition cond, const ValueOperand &value); Condition testMagic(Condition cond, const ValueOperand &value); Condition testPrimitive(Condition cond, const ValueOperand &value);
--- a/js/src/ion/x64/MacroAssembler-x64.h +++ b/js/src/ion/x64/MacroAssembler-x64.h @@ -271,16 +271,20 @@ class MacroAssemblerX64 : public MacroAs Condition testBoolean(Condition cond, const ValueOperand &src) { splitTag(src, ScratchReg); return testBoolean(cond, ScratchReg); } Condition testDouble(Condition cond, const ValueOperand &src) { splitTag(src, ScratchReg); return testDouble(cond, ScratchReg); } + Condition testNumber(Condition cond, const ValueOperand &src) { + splitTag(src, ScratchReg); + return testNumber(cond, ScratchReg); + } Condition testNull(Condition cond, const ValueOperand &src) { splitTag(src, ScratchReg); return testNull(cond, ScratchReg); } Condition testString(Condition cond, const ValueOperand &src) { splitTag(src, ScratchReg); return testString(cond, ScratchReg); }
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/ion/typeof-is.js @@ -0,0 +1,346 @@ +function isObject(x) { + return "object" === typeof x; +} +function isObject2(x) { + if ("object" === typeof x) + return true; + return false; +} +function isBoolean(x) { + return "boolean" === typeof x; +} +function isBoolean2(x) { + if ("boolean" === typeof x) + return true; + return false; +} +function isFunction(x) { + return "function" === typeof x; +} +function isFunction2(x) { + if ("function" === typeof x) + return true; + return false; +} +function isNumber(x) { + return "number" === typeof x; +} +function isNumber2(x) { + if ("number" === typeof x) + return true; + return false; +} +function isString(x) { + return "string" === typeof x; +} +function isString2(x) { + if ("string" === typeof x) + return true; + return false; +} +function isUndefined(x) { + return "undefined" === typeof x; +} +function isUndefined2(x) { + if ("undefined" === typeof x) + return true; + return false; +} +function isBanana(x) { + return "Banana" === typeof x; +} +function isBanana2(x) { + if ("Banana" === typeof x) + return true; + return false; +} + +for (var i = 0; i < 100; i++) { + assertEq(isObject(null), true); + assertEq(isObject2(null), true); + assertEq(isBoolean(null), false); + assertEq(isBoolean2(null), false); + assertEq(isFunction(null), false); + assertEq(isFunction2(null), false); + assertEq(isNumber(null), false); + assertEq(isNumber2(null), false); + assertEq(isString(null), false); + assertEq(isString2(null), false); + assertEq(isUndefined(null), false); + assertEq(isUndefined2(null), false); + assertEq(isBanana(null), false); + assertEq(isBanana2(null), false); + + assertEq(isObject({}), true); + assertEq(isObject2({}), true); + assertEq(isBoolean({}), false); + assertEq(isBoolean2({}), false); + assertEq(isFunction({}), false); + assertEq(isFunction2({}), false); + assertEq(isNumber({}), false); + assertEq(isNumber2({}), false); + assertEq(isString({}), false); + assertEq(isString2({}), false); + assertEq(isUndefined({}), false); + assertEq(isUndefined2({}), false); + assertEq(isBanana({}), false); + assertEq(isBanana2({}), false); + + assertEq(isObject([]), true); + assertEq(isObject2([]), true); + assertEq(isBoolean([]), false); + assertEq(isBoolean2([]), false); + assertEq(isFunction([]), false); + assertEq(isFunction2([]), false); + assertEq(isNumber([]), false); + assertEq(isNumber2([]), false); + assertEq(isString([]), false); + assertEq(isString2([]), false); + assertEq(isUndefined([]), false); + assertEq(isUndefined2([]), false); + assertEq(isBanana([]), false); + assertEq(isBanana2([]), false); + + assertEq(isObject(new Date()), true); + assertEq(isObject2(new Date()), true); + assertEq(isBoolean(new Date()), false); + assertEq(isBoolean2(new Date()), false); + assertEq(isFunction(new Date()), false); + assertEq(isFunction2(new Date()), false); + assertEq(isNumber(new Date()), false); + assertEq(isNumber2(new Date()), false); + assertEq(isString(new Date()), false); + assertEq(isString2(new Date()), false); + assertEq(isUndefined(new Date()), false); + assertEq(isUndefined2(new Date()), false); + assertEq(isBanana(new Date()), false); + assertEq(isBanana2(new Date()), false); + + assertEq(isObject(new String()), true); + assertEq(isObject2(new String()), true); + assertEq(isBoolean(new String()), false); + assertEq(isBoolean2(new String()), false); + assertEq(isFunction(new String()), false); + assertEq(isFunction2(new String()), false); + assertEq(isNumber(new String()), false); + assertEq(isNumber2(new String()), false); + assertEq(isString(new String()), false); + assertEq(isString2(new String()), false); + assertEq(isUndefined(new String()), false); + assertEq(isUndefined2(new String()), false); + assertEq(isBanana(new String()), false); + assertEq(isBanana2(new String()), false); + + assertEq(isObject(new Boolean()), true); + assertEq(isObject2(new Boolean()), true); + assertEq(isBoolean(new Boolean()), false); + assertEq(isBoolean2(new Boolean()), false); + assertEq(isFunction(new Boolean()), false); + assertEq(isFunction2(new Boolean()), false); + assertEq(isNumber(new Boolean()), false); + assertEq(isNumber2(new Boolean()), false); + assertEq(isString(new Boolean()), false); + assertEq(isString2(new Boolean()), false); + assertEq(isUndefined(new Boolean()), false); + assertEq(isUndefined2(new Boolean()), false); + assertEq(isBanana(new Boolean()), false); + assertEq(isBanana2(new Boolean()), false); + + assertEq(isObject(Proxy.create({})), true); + assertEq(isObject2(Proxy.create({})), true); + assertEq(isBoolean(Proxy.create({})), false); + assertEq(isBoolean2(Proxy.create({})), false); + assertEq(isFunction(Proxy.create({})), false); + assertEq(isFunction2(Proxy.create({})), false); + assertEq(isNumber(Proxy.create({})), false); + assertEq(isNumber2(Proxy.create({})), false); + assertEq(isString(Proxy.create({})), false); + assertEq(isString2(Proxy.create({})), false); + assertEq(isUndefined(Proxy.create({})), false); + assertEq(isUndefined2(Proxy.create({})), false); + assertEq(isBanana(Proxy.create({})), false); + assertEq(isBanana2(Proxy.create({})), false); + + assertEq(isObject(true), false); + assertEq(isObject2(true), false); + assertEq(isBoolean(true), true); + assertEq(isBoolean2(true), true); + assertEq(isFunction(true), false); + assertEq(isFunction2(true), false); + assertEq(isNumber(true), false); + assertEq(isNumber2(true), false); + assertEq(isString(true), false); + assertEq(isString2(true), false); + assertEq(isUndefined(true), false); + assertEq(isUndefined2(true), false); + assertEq(isBanana(true), false); + assertEq(isBanana2(true), false); + + assertEq(isObject(false), false); + assertEq(isObject2(false), false); + assertEq(isBoolean(false), true); + assertEq(isBoolean2(false), true); + assertEq(isFunction(false), false); + assertEq(isFunction2(false), false); + assertEq(isNumber(false), false); + assertEq(isNumber2(false), false); + assertEq(isString(false), false); + assertEq(isString2(false), false); + assertEq(isUndefined(false), false); + assertEq(isUndefined2(false), false); + assertEq(isBanana(false), false); + assertEq(isBanana2(false), false); + + + assertEq(isObject(Function.prototype), false); + assertEq(isObject2(Function.prototype), false); + assertEq(isBoolean(Function.prototype), false); + assertEq(isBoolean2(Function.prototype), false); + assertEq(isFunction(Function.prototype), true); + assertEq(isFunction2(Function.prototype), true); + assertEq(isNumber(Function.prototype), false); + assertEq(isNumber2(Function.prototype), false); + assertEq(isString(Function.prototype), false); + assertEq(isString2(Function.prototype), false); + assertEq(isUndefined(Function.prototype), false); + assertEq(isUndefined2(Function.prototype), false); + assertEq(isBanana(Function.prototype), false); + assertEq(isBanana2(Function.prototype), false); + + + assertEq(isObject(eval), false); + assertEq(isObject2(eval), false); + assertEq(isBoolean(eval), false); + assertEq(isBoolean2(eval), false); + assertEq(isFunction(eval), true); + assertEq(isFunction2(eval), true); + assertEq(isNumber(eval), false); + assertEq(isNumber2(eval), false); + assertEq(isString(eval), false); + assertEq(isString2(eval), false); + assertEq(isUndefined(eval), false); + assertEq(isUndefined2(eval), false); + assertEq(isBanana(eval), false); + assertEq(isBanana2(eval), false); + + + assertEq(isObject((function () {}).bind()), false); + assertEq(isObject2((function () {}).bind()), false); + assertEq(isBoolean((function () {}).bind()), false); + assertEq(isBoolean2((function () {}).bind()), false); + assertEq(isFunction((function () {}).bind()), true); + assertEq(isFunction2((function () {}).bind()), true); + assertEq(isNumber((function () {}).bind()), false); + assertEq(isNumber2((function () {}).bind()), false); + assertEq(isString((function () {}).bind()), false); + assertEq(isString2((function () {}).bind()), false); + assertEq(isUndefined((function () {}).bind()), false); + assertEq(isUndefined2((function () {}).bind()), false); + assertEq(isBanana((function () {}).bind()), false); + assertEq(isBanana2((function () {}).bind()), false); + + assertEq(isObject(eval), false); + assertEq(isObject2(eval), false); + assertEq(isBoolean(eval), false); + assertEq(isBoolean2(eval), false); + assertEq(isFunction(eval), true); + assertEq(isFunction2(eval), true); + assertEq(isNumber(eval), false); + assertEq(isNumber2(eval), false); + assertEq(isString(eval), false); + assertEq(isString2(eval), false); + assertEq(isUndefined(eval), false); + assertEq(isUndefined2(eval), false); + assertEq(isBanana(eval), false); + assertEq(isBanana2(eval), false); + + assertEq(isObject(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isObject2(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isBoolean(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isBoolean2(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isFunction(Proxy.createFunction({}, function () {}, function () {})), true); + assertEq(isFunction2(Proxy.createFunction({}, function () {}, function () {})), true); + assertEq(isNumber(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isNumber2(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isString(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isString2(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isUndefined(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isUndefined2(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isBanana(Proxy.createFunction({}, function () {}, function () {})), false); + assertEq(isBanana2(Proxy.createFunction({}, function () {}, function () {})), false); + + assertEq(isObject(1.5), false); + assertEq(isObject2(1.5), false); + assertEq(isBoolean(1.5), false); + assertEq(isBoolean2(1.5), false); + assertEq(isFunction(1.5), false); + assertEq(isFunction2(1.5), false); + assertEq(isNumber(1.5), true); + assertEq(isNumber2(1.5), true); + assertEq(isString(1.5), false); + assertEq(isString2(1.5), false); + assertEq(isUndefined(1.5), false); + assertEq(isUndefined2(1.5), false); + assertEq(isBanana(1.5), false); + assertEq(isBanana2(1.5), false); + + assertEq(isObject(30), false); + assertEq(isObject2(30), false); + assertEq(isBoolean(30), false); + assertEq(isBoolean2(30), false); + assertEq(isFunction(30), false); + assertEq(isFunction2(30), false); + assertEq(isNumber(30), true); + assertEq(isNumber2(30), true); + assertEq(isString(30), false); + assertEq(isString2(30), false); + assertEq(isUndefined(30), false); + assertEq(isUndefined2(30), false); + assertEq(isBanana(30), false); + assertEq(isBanana2(30), false); + + assertEq(isObject(NaN), false); + assertEq(isObject2(NaN), false); + assertEq(isBoolean(NaN), false); + assertEq(isBoolean2(NaN), false); + assertEq(isFunction(NaN), false); + assertEq(isFunction2(NaN), false); + assertEq(isNumber(NaN), true); + assertEq(isNumber2(NaN), true); + assertEq(isString(NaN), false); + assertEq(isString2(NaN), false); + assertEq(isUndefined(NaN), false); + assertEq(isUndefined2(NaN), false); + assertEq(isBanana(NaN), false); + assertEq(isBanana2(NaN), false); + + assertEq(isObject("test"), false); + assertEq(isObject2("test"), false); + assertEq(isBoolean("test"), false); + assertEq(isBoolean2("test"), false); + assertEq(isFunction("test"), false); + assertEq(isFunction2("test"), false); + assertEq(isNumber("test"), false); + assertEq(isNumber2("test"), false); + assertEq(isString("test"), true); + assertEq(isString2("test"), true); + assertEq(isUndefined("test"), false); + assertEq(isUndefined2("test"), false); + assertEq(isBanana("test"), false); + assertEq(isBanana2("test"), false); + + assertEq(isObject(undefined), false); + assertEq(isObject2(undefined), false); + assertEq(isBoolean(undefined), false); + assertEq(isBoolean2(undefined), false); + assertEq(isFunction(undefined), false); + assertEq(isFunction2(undefined), false); + assertEq(isNumber(undefined), false); + assertEq(isNumber2(undefined), false); + assertEq(isString(undefined), false); + assertEq(isString2(undefined), false); + assertEq(isUndefined(undefined), true); + assertEq(isUndefined2(undefined), true); + assertEq(isBanana(undefined), false); + assertEq(isBanana2(undefined), false); +}