author | Jan de Mooij <jdemooij@mozilla.com> |
Tue, 10 Sep 2013 16:17:06 +0200 | |
changeset 146413 | 8c452ca6d4165f69c4dc0901fc6bf9753e58afb2 |
parent 146412 | 61824642543ad2d21365f8a8e368686f452f9f69 |
child 146414 | e112a8245e294e13071e95d8fd06e29620f49c52 |
push id | 25260 |
push user | ryanvm@gmail.com |
push date | Wed, 11 Sep 2013 00:29:30 +0000 |
treeherder | mozilla-central@f73bed2856a8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bhackett |
bugs | 914132 |
milestone | 26.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
|
js/src/jit/CodeGenerator.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/IonBuilder.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/MIR.cpp | file | annotate | diff | comparison | revisions | |
js/src/jit/MIR.h | file | annotate | diff | comparison | revisions | |
js/src/jsinfer.cpp | file | annotate | diff | comparison | revisions | |
js/src/jsinfer.h | file | annotate | diff | comparison | revisions |
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -6428,28 +6428,38 @@ class OutOfLineTypeOfV : public OutOfLin bool CodeGenerator::visitTypeOfV(LTypeOfV *lir) { const ValueOperand value = ToValue(lir, LTypeOfV::Input); Register output = ToRegister(lir->output()); Register tag = masm.splitTagForTest(value); - OutOfLineTypeOfV *ool = new OutOfLineTypeOfV(lir); - if (!addOutOfLineCode(ool)) - return false; - JSRuntime *rt = GetIonContext()->runtime; - - // Jump to the OOL path if the value is an object. Objects are complicated - // since they may have a typeof hook. - masm.branchTestObject(Assembler::Equal, tag, ool->entry()); - Label done; + OutOfLineTypeOfV *ool = NULL; + if (lir->mir()->inputMaybeCallableOrEmulatesUndefined()) { + // The input may be a callable object (result is "function") or may + // emulate undefined (result is "undefined"). Use an OOL path. + ool = new OutOfLineTypeOfV(lir); + if (!addOutOfLineCode(ool)) + return false; + + masm.branchTestObject(Assembler::Equal, tag, ool->entry()); + } else { + // Input is not callable and does not emulate undefined, so if + // it's an object the result is always "object". + Label notObject; + masm.branchTestObject(Assembler::NotEqual, tag, ¬Object); + masm.movePtr(ImmGCPtr(rt->atomState.object), output); + masm.jump(&done); + masm.bind(¬Object); + } + Label notNumber; masm.branchTestNumber(Assembler::NotEqual, tag, ¬Number); masm.movePtr(ImmGCPtr(rt->atomState.number), output); masm.jump(&done); masm.bind(¬Number); Label notUndefined; masm.branchTestUndefined(Assembler::NotEqual, tag, ¬Undefined); @@ -6467,17 +6477,18 @@ CodeGenerator::visitTypeOfV(LTypeOfV *li masm.branchTestBoolean(Assembler::NotEqual, tag, ¬Boolean); masm.movePtr(ImmGCPtr(rt->atomState.boolean), output); masm.jump(&done); masm.bind(¬Boolean); masm.movePtr(ImmGCPtr(rt->atomState.string), output); masm.bind(&done); - masm.bind(ool->rejoin()); + if (ool) + masm.bind(ool->rejoin()); return true; } bool CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool) { LTypeOfV *ins = ool->ins();
--- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -8929,16 +8929,18 @@ IonBuilder::jsop_this() } bool IonBuilder::jsop_typeof() { MDefinition *input = current->pop(); MTypeOf *ins = MTypeOf::New(input, input->type()); + ins->infer(cx); + current->add(ins); current->push(ins); return true; } bool IonBuilder::jsop_toid()
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -210,16 +210,29 @@ MaybeEmulatesUndefined(JSContext *cx, MD if (!types) return true; if (!types->maybeObject()) return false; return types->hasObjectFlags(cx, types::OBJECT_FLAG_EMULATES_UNDEFINED); } +static bool +MaybeCallable(JSContext *cx, MDefinition *op) +{ + if (!op->mightBeType(MIRType_Object)) + return false; + + types::StackTypeSet *types = op->resultTypeSet(); + if (!types) + return true; + + return types->maybeCallable(); +} + void MTest::infer(JSContext *cx) { JS_ASSERT(operandMightEmulateUndefined()); if (!MaybeEmulatesUndefined(cx, getOperand(0))) markOperandCantEmulateUndefined(); } @@ -1878,16 +1891,25 @@ MTypeOf::foldsTo(bool useValueNumbers) default: return this; } JSRuntime *rt = GetIonContext()->runtime; return MConstant::New(StringValue(TypeName(type, rt))); } +void +MTypeOf::infer(JSContext *cx) +{ + JS_ASSERT(inputMaybeCallableOrEmulatesUndefined()); + + if (!MaybeEmulatesUndefined(cx, input()) && !MaybeCallable(cx, input())) + markInputNotCallableOrEmulatesUndefined(); +} + MBitAnd * MBitAnd::New(MDefinition *left, MDefinition *right) { return new MBitAnd(left, right); } MBitAnd * MBitAnd::NewAsmJS(MDefinition *left, MDefinition *right)
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -2890,19 +2890,21 @@ class MBitNot void computeRange(); }; class MTypeOf : public MUnaryInstruction, public BoxInputsPolicy { MIRType inputType_; + bool inputMaybeCallableOrEmulatesUndefined_; MTypeOf(MDefinition *def, MIRType inputType) - : MUnaryInstruction(def), inputType_(inputType) + : MUnaryInstruction(def), inputType_(inputType), + inputMaybeCallableOrEmulatesUndefined_(true) { setResultType(MIRType_String); setMovable(); } public: INSTRUCTION_HEADER(TypeOf) @@ -2911,17 +2913,26 @@ class MTypeOf } TypePolicy *typePolicy() { return this; } MIRType inputType() const { return inputType_; } + MDefinition *foldsTo(bool useValueNumbers); + void infer(JSContext *cx); + + bool inputMaybeCallableOrEmulatesUndefined() const { + return inputMaybeCallableOrEmulatesUndefined_; + } + void markInputNotCallableOrEmulatesUndefined() { + inputMaybeCallableOrEmulatesUndefined_ = false; + } AliasSet getAliasSet() const { return AliasSet::None(); } }; class MToId : public MBinaryInstruction,
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1101,16 +1101,42 @@ StackTypeSet::isDOMClass() if (!(clasp->flags & JSCLASS_IS_DOMJSCLASS)) return false; } return true; } +bool +StackTypeSet::maybeCallable() +{ + if (!maybeObject()) + return false; + + if (unknownObject()) + return true; + + unsigned count = getObjectCount(); + for (unsigned i = 0; i < count; i++) { + Class *clasp; + if (JSObject *object = getSingleObject(i)) + clasp = object->getClass(); + else if (TypeObject *object = getTypeObject(i)) + clasp = object->clasp; + else + continue; + + if (clasp->isCallable()) + return true; + } + + return false; +} + JSObject * StackTypeSet::getCommonPrototype() { if (unknownObject()) return NULL; JSObject *proto = NULL; unsigned count = getObjectCount();
--- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -620,16 +620,19 @@ class StackTypeSet : public TypeSet JSObject *getCommonPrototype(); /* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */ int getTypedArrayType(); /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */ bool isDOMClass(); + /* Whether clasp->isCallable() is true for one or more objects in this set. */ + bool maybeCallable(); + /* Get the single value which can appear in this type set, otherwise NULL. */ JSObject *getSingleton(); /* Whether any objects in the type set needs a barrier on id. */ bool propertyNeedsBarrier(JSContext *cx, jsid id); /* * Whether this set contains all types in other, except (possibly) the