author | Hannes Verschore <hv1989@gmail.com> |
Wed, 20 Apr 2016 06:40:16 -0400 | |
changeset 294023 | be2f6cb7251c22cec13209cc2314789e7ae0d0ea |
parent 294022 | 37d592080a032a01c2110b0c6d9ba489aded0891 |
child 294024 | 7c1f8d3d4f69add3995d27d4c70c92d286aa54b9 |
push id | 75399 |
push user | hv1989@gmail.com |
push date | Wed, 20 Apr 2016 10:40:55 +0000 |
treeherder | mozilla-inbound@7c1f8d3d4f69 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | efaust |
bugs | 1241088 |
milestone | 48.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/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -1897,17 +1897,17 @@ BaselineCompiler::emit_JSOP_NEWARRAY() // Pass length in R0. masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg()); ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array); if (!group) return false; - ICNewArray_Fallback::Compiler stubCompiler(cx, group); + ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::Baseline); if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false; frame.push(R0); return true; } bool @@ -1967,17 +1967,17 @@ BaselineCompiler::emit_JSOP_INITELEM_ARR return true; } bool BaselineCompiler::emit_JSOP_NEWOBJECT() { frame.syncStack(0); - ICNewObject_Fallback::Compiler stubCompiler(cx); + ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline); if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false; frame.push(R0); return true; } bool @@ -1989,23 +1989,23 @@ BaselineCompiler::emit_JSOP_NEWINIT() if (key == JSProto_Array) { // Pass length in R0. masm.move32(Imm32(0), R0.scratchReg()); ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array); if (!group) return false; - ICNewArray_Fallback::Compiler stubCompiler(cx, group); + ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::Baseline); if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false; } else { MOZ_ASSERT(key == JSProto_Object); - ICNewObject_Fallback::Compiler stubCompiler(cx); + ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline); if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false; } frame.push(R0); return true; }
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3,16 +3,17 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "jit/CodeGenerator.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/Casting.h" #include "mozilla/DebugOnly.h" #include "mozilla/EnumeratedArray.h" #include "mozilla/EnumeratedRange.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/ScopeExit.h" #include "mozilla/SizePrintfMacros.h" #include "jslibmath.h" @@ -49,16 +50,17 @@ #include "jit/MacroAssembler-inl.h" #include "jit/shared/CodeGenerator-shared-inl.h" #include "jit/shared/Lowering-shared-inl.h" #include "vm/Interpreter-inl.h" using namespace js; using namespace js::jit; +using mozilla::AssertedCast; using mozilla::DebugOnly; using mozilla::FloatingPoint; using mozilla::Maybe; using mozilla::NegativeInfinity; using mozilla::PositiveInfinity; using JS::GenericNaN; namespace js { @@ -2372,16 +2374,51 @@ CodeGenerator::visitUnarySharedStub(LUna case JSOP_LENGTH: emitSharedStub(ICStub::Kind::GetProp_Fallback, lir); break; default: MOZ_CRASH("Unsupported jsop in shared stubs."); } } +void +CodeGenerator::visitNullarySharedStub(LNullarySharedStub* lir) +{ + jsbytecode* pc = lir->mir()->resumePoint()->pc(); + JSOp jsop = JSOp(*pc); + switch (jsop) { + case JSOP_NEWARRAY: { + uint32_t length = GET_UINT32(pc); + MOZ_ASSERT(length <= INT32_MAX, + "the bytecode emitter must fail to compile code that would " + "produce JSOP_NEWARRAY with a length exceeding int32_t range"); + + // Pass length in R0. + masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg()); + emitSharedStub(ICStub::Kind::NewArray_Fallback, lir); + break; + } + case JSOP_NEWOBJECT: + emitSharedStub(ICStub::Kind::NewObject_Fallback, lir); + break; + case JSOP_NEWINIT: { + JSProtoKey key = JSProtoKey(GET_UINT8(pc)); + if (key == JSProto_Array) { + masm.move32(Imm32(0), R0.scratchReg()); + emitSharedStub(ICStub::Kind::NewArray_Fallback, lir); + } else { + emitSharedStub(ICStub::Kind::NewObject_Fallback, lir); + } + break; + } + default: + MOZ_CRASH("Unsupported jsop in shared stubs."); + } +} + typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject); static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda); void CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton* lir) { pushArg(ToRegister(lir->scopeChain())); pushArg(ImmGCPtr(lir->mir()->info().fun)); @@ -5141,17 +5178,17 @@ CodeGenerator::visitNewArray(LNewArray* { Register objReg = ToRegister(lir->output()); Register tempReg = ToRegister(lir->temp()); JSObject* templateObject = lir->mir()->templateObject(); DebugOnly<uint32_t> length = lir->mir()->length(); MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT); - if (lir->mir()->shouldUseVM()) { + if (!templateObject) { visitNewArrayCallVM(lir); return; } OutOfLineNewArray* ool = new(alloc()) OutOfLineNewArray(lir); addOutOfLineCode(ool, lir->mir()); masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), @@ -5398,17 +5435,17 @@ ShouldInitFixedSlots(LInstruction* lir, void CodeGenerator::visitNewObject(LNewObject* lir) { Register objReg = ToRegister(lir->output()); Register tempReg = ToRegister(lir->temp()); JSObject* templateObject = lir->mir()->templateObject(); - if (lir->mir()->shouldUseVM()) { + if (!templateObject) { visitNewObjectVMCall(lir); return; } OutOfLineNewObject* ool = new(alloc()) OutOfLineNewObject(lir); addOutOfLineCode(ool, lir->mir()); bool initContents = ShouldInitFixedSlots(lir, templateObject); @@ -8864,16 +8901,32 @@ CodeGenerator::linkSharedStubs(JSContext stub = stubCompiler.getStub(&stubSpace_); break; } case ICStub::Kind::GetProp_Fallback: { ICGetProp_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonMonkey); stub = stubCompiler.getStub(&stubSpace_); break; } + case ICStub::Kind::NewArray_Fallback: { + JSScript* script = sharedStubs_[i].entry.script(); + jsbytecode* pc = sharedStubs_[i].entry.pc(script); + ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array); + if (!group) + return false; + + ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::IonMonkey); + stub = stubCompiler.getStub(&stubSpace_); + break; + } + case ICStub::Kind::NewObject_Fallback: { + ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonMonkey); + stub = stubCompiler.getStub(&stubSpace_); + break; + } default: MOZ_CRASH("Unsupported shared stub."); } if (!stub) return false; sharedStubs_[i].entry.setFirstStub(stub);
--- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -121,16 +121,17 @@ class CodeGenerator : public CodeGenerat void visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* lir); void visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool); void visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* lir); void visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool); void visitStringReplace(LStringReplace* lir); void emitSharedStub(ICStub::Kind kind, LInstruction* lir); void visitBinarySharedStub(LBinarySharedStub* lir); void visitUnarySharedStub(LUnarySharedStub* lir); + void visitNullarySharedStub(LNullarySharedStub* lir); void visitLambda(LLambda* lir); void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool); void visitLambdaArrow(LLambdaArrow* lir); void visitLambdaForSingleton(LLambdaForSingleton* lir); void visitPointer(LPointer* lir); void visitKeepAliveObject(LKeepAliveObject* lir); void visitSlots(LSlots* lir); void visitLoadSlotT(LLoadSlotT* lir);
--- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -7185,42 +7185,128 @@ IonBuilder::compareTrySharedStub(bool* e current->add(unbox); current->push(unbox); *emitted = true; return true; } bool -IonBuilder::jsop_newarray(uint32_t length) -{ - JSObject* templateObject = inspector->getTemplateObject(pc); - gc::InitialHeap heap; - MConstant* templateConst; - - if (templateObject) { - heap = templateObject->group()->initialHeap(constraints()); - templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); - } else { - heap = gc::DefaultHeap; - templateConst = MConstant::New(alloc(), NullValue()); - } +IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, uint32_t length) +{ + MOZ_ASSERT(*emitted == false); + + if (!templateObject) + return true; + + if (templateObject->is<UnboxedArrayObject>()) { + MOZ_ASSERT(templateObject->as<UnboxedArrayObject>().capacity() >= length); + if (!templateObject->as<UnboxedArrayObject>().hasInlineElements()) + return true; + } + + MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT); + + size_t arraySlots = + gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER; + + if (length > arraySlots) + return true; + + // Emit fastpath. + + gc::InitialHeap heap = templateObject->group()->initialHeap(constraints()); + MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); current->add(templateConst); MNewArray* ins = MNewArray::New(alloc(), constraints(), length, templateConst, heap, pc); current->add(ins); current->push(ins); + *emitted = true; + return true; +} + +bool +IonBuilder::newArrayTrySharedStub(bool* emitted) +{ + MOZ_ASSERT(*emitted == false); + + // Try to emit a shared stub cache. + + if (JitOptions.disableSharedStubs) + return true; + + if (*pc != JSOP_NEWINIT && *pc != JSOP_NEWARRAY) + return true; + + MInstruction* stub = MNullarySharedStub::New(alloc()); + current->add(stub); + current->push(stub); + + if (!resumeAfter(stub)) + return false; + + *emitted = true; + return true; +} + +bool +IonBuilder::newArrayTryVM(bool* emitted, uint32_t length) +{ + MOZ_ASSERT(*emitted == false); + + // Emit a VM call. + + gc::InitialHeap heap = gc::DefaultHeap; + MConstant* templateConst = MConstant::New(alloc(), NullValue()); + current->add(templateConst); + + MNewArray* ins = MNewArray::New(alloc(), constraints(), length, templateConst, heap, pc); + current->add(ins); + current->push(ins); + + *emitted = true; + return true; +} + +bool +IonBuilder::jsop_newarray(uint32_t length) +{ + JSObject* templateObject = inspector->getTemplateObject(pc); + if (!jsop_newarray(templateObject, length)) + return false; + + // Improve resulting typeset. ObjectGroup* templateGroup = inspector->getTemplateObjectGroup(pc); if (templateGroup) { TemporaryTypeSet* types = MakeSingletonTypeSet(constraints(), templateGroup); - ins->setResultTypeSet(types); - } - - return true; + current->peek(-1)->setResultTypeSet(types); + } + + return true; +} + +bool +IonBuilder::jsop_newarray(JSObject* templateObject, uint32_t length) +{ + bool emitted = false; + + if (!forceInlineCaches()) { + if (!newArrayTryTemplateObject(&emitted, templateObject, length) || emitted) + return emitted; + } + + if (!newArrayTrySharedStub(&emitted) || emitted) + return emitted; + + if (!newArrayTryVM(&emitted, length) || emitted) + return emitted; + + MOZ_CRASH("newarray should have been emited"); } bool IonBuilder::jsop_newarray_copyonwrite() { ArrayObject* templateObject = ObjectGroup::getCopyOnWriteObject(script(), pc); // The baseline compiler should have ensured the template object has a type @@ -7236,38 +7322,108 @@ IonBuilder::jsop_newarray_copyonwrite() current->add(ins); current->push(ins); return true; } bool -IonBuilder::jsop_newobject() -{ - JSObject* templateObject = inspector->getTemplateObject(pc); - gc::InitialHeap heap; - MConstant* templateConst; - - if (templateObject) { - heap = templateObject->group()->initialHeap(constraints()); - templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); - } else { - heap = gc::DefaultHeap; - templateConst = MConstant::New(alloc(), NullValue()); - } - +IonBuilder::newObjectTryTemplateObject(bool* emitted, JSObject* templateObject) +{ + MOZ_ASSERT(*emitted == false); + + if (!templateObject) + return true; + + if (templateObject->is<PlainObject>() && templateObject->as<PlainObject>().hasDynamicSlots()) + return true; + + // Emit fastpath. + + MNewObject::Mode mode; + if (JSOp(*pc) == JSOP_NEWOBJECT || JSOp(*pc) == JSOP_NEWINIT) + mode = MNewObject::ObjectLiteral; + else + mode = MNewObject::ObjectCreate; + + gc::InitialHeap heap = templateObject->group()->initialHeap(constraints()); + MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); current->add(templateConst); - MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, heap, - MNewObject::ObjectLiteral); - + + MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, heap, mode); current->add(ins); current->push(ins); - return resumeAfter(ins); + if (!resumeAfter(ins)) + return false; + + *emitted = true; + return true; +} + +bool +IonBuilder::newObjectTrySharedStub(bool* emitted) +{ + MOZ_ASSERT(*emitted == false); + + // Try to emit a shared stub cache. + + if (JitOptions.disableSharedStubs) + return true; + + MInstruction* stub = MNullarySharedStub::New(alloc()); + current->add(stub); + current->push(stub); + + if (!resumeAfter(stub)) + return false; + + *emitted = true; + return true; +} + +bool +IonBuilder::newObjectTryVM(bool* emitted) +{ + // Emit a VM call. + + gc::InitialHeap heap = gc::DefaultHeap; + MConstant* templateConst = MConstant::New(alloc(), NullValue()); + current->add(templateConst); + + MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, heap, + MNewObject::ObjectLiteral); + current->add(ins); + current->push(ins); + + if (!resumeAfter(ins)) + return false; + + *emitted = true; + return true; +} + +bool +IonBuilder::jsop_newobject() +{ + bool emitted = false; + + if (!forceInlineCaches()) { + JSObject* templateObject = inspector->getTemplateObject(pc); + if (!newObjectTryTemplateObject(&emitted, templateObject) || emitted) + return emitted; + } + if (!newObjectTrySharedStub(&emitted) || emitted) + return emitted; + + if (!newObjectTryVM(&emitted) || emitted) + return emitted; + + MOZ_CRASH("newobject should have been emited"); } bool IonBuilder::jsop_initelem() { MDefinition* value = current->pop(); MDefinition* id = current->pop(); MDefinition* obj = current->peek(-1); @@ -7349,17 +7505,20 @@ IonBuilder::initializeArrayElement(MDefi if (!resumeAfter(increment)) return false; } } else { if (NeedsPostBarrier(value)) current->add(MPostWriteBarrier::New(alloc(), obj, value)); - if (obj->toNewArray()->convertDoubleElements()) { + if ((obj->isNewArray() && obj->toNewArray()->convertDoubleElements()) || + (obj->isNullarySharedStub() && + obj->resultTypeSet()->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles)) + { MInstruction* valueDouble = MToDouble::New(alloc(), value); current->add(valueDouble); value = valueDouble; } // Store the value. MStoreElement* store = MStoreElement::New(alloc(), elements, id, value, /* needsHoleCheck = */ false); @@ -7395,24 +7554,29 @@ bool IonBuilder::jsop_initprop(PropertyName* name) { bool useSlowPath = false; MDefinition* value = current->peek(-1); MDefinition* obj = current->peek(-2); if (obj->isLambda()) { useSlowPath = true; - } else if (JSObject* templateObject = obj->toNewObject()->templateObject()) { - if (templateObject->is<PlainObject>()) { - if (!templateObject->as<PlainObject>().containsPure(name)) - useSlowPath = true; + } else if (obj->isNewObject()) { + if (JSObject* templateObject = obj->toNewObject()->templateObject()) { + if (templateObject->is<PlainObject>()) { + if (!templateObject->as<PlainObject>().containsPure(name)) + useSlowPath = true; + } else { + MOZ_ASSERT(templateObject->as<UnboxedPlainObject>().layout().lookup(name)); + } } else { - MOZ_ASSERT(templateObject->as<UnboxedPlainObject>().layout().lookup(name)); + useSlowPath = true; } } else { + MOZ_ASSERT(obj->isNullarySharedStub()); useSlowPath = true; } if (useSlowPath) { current->pop(); MInitProp* init = MInitProp::New(alloc(), obj, name, value); current->add(init); return resumeAfter(init); @@ -10496,30 +10660,26 @@ IonBuilder::jsop_rest() return true; } // We know the exact number of arguments the callee pushed. unsigned numActuals = inlineCallInfo_->argc(); unsigned numFormals = info().nargs() - 1; unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0; - MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); - current->add(templateConst); - - MNewArray* array = MNewArray::New(alloc(), constraints(), numRest, templateConst, - templateObject->group()->initialHeap(constraints()), pc); - current->add(array); + if (!jsop_newarray(numRest)) + return false; if (numRest == 0) { // No more updating to do. (Note that in this one case the length from // the template object is already correct.) - current->push(array); - return true; - } - + return true; + } + + MDefinition *array = current->peek(-1); MElements* elements = MElements::New(alloc(), array); current->add(elements); // Unroll the argument copy loop. We don't need to do any bounds or hole // checking here. MConstant* index = nullptr; for (unsigned i = numFormals; i < numActuals; i++) { index = MConstant::New(alloc(), Int32Value(i - numFormals)); @@ -10540,17 +10700,16 @@ IonBuilder::jsop_rest() MSetArrayLength* length = MSetArrayLength::New(alloc(), elements, index); current->add(length); // Update the initialized length for all the (necessarily non-hole) // elements added. MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, index); current->add(initLength); - current->push(array); return true; } bool IonBuilder::jsop_checkobjcoercible() { MDefinition* toCheck = current->peek(-1);
--- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -508,16 +508,26 @@ class IonBuilder // jsop_compare helpers. bool compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); + // jsop_newarray helpers. + bool newArrayTrySharedStub(bool* emitted); + bool newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, uint32_t length); + bool newArrayTryVM(bool* emitted, uint32_t length); + + // jsop_newobject helpers. + bool newObjectTrySharedStub(bool* emitted); + bool newObjectTryTemplateObject(bool* emitted, JSObject* templateObject); + bool newObjectTryVM(bool* emitted); + // jsop_in helpers. bool inTryDense(bool* emitted, MDefinition* obj, MDefinition* id); bool inTryFold(bool* emitted, MDefinition* obj, MDefinition* id); // binary data lookup helpers. TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj); TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types); bool typedObjectHasField(MDefinition* typedObj, @@ -718,16 +728,17 @@ class IonBuilder bool jsop_runonce(); bool jsop_rest(); bool jsop_not(); bool jsop_getprop(PropertyName* name); bool jsop_setprop(PropertyName* name); bool jsop_delprop(PropertyName* name); bool jsop_delelem(); bool jsop_newarray(uint32_t length); + bool jsop_newarray(JSObject* templateObject, uint32_t length); bool jsop_newarray_copyonwrite(); bool jsop_newobject(); bool jsop_initelem(); bool jsop_initelem_array(); bool jsop_initelem_getter_setter(); bool jsop_mutateproto(); bool jsop_initprop(PropertyName* name); bool jsop_initprop_getter_setter(PropertyName* name);
--- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2357,16 +2357,27 @@ LIRGenerator::visitUnarySharedStub(MUnar MOZ_ASSERT(ins->type() == MIRType_Value); LUnarySharedStub* lir = new(alloc()) LUnarySharedStub(useBoxFixedAtStart(input, R0)); defineSharedStubReturn(lir, ins); assignSafepoint(lir, ins); } void +LIRGenerator::visitNullarySharedStub(MNullarySharedStub* ins) +{ + MOZ_ASSERT(ins->type() == MIRType_Value); + + LNullarySharedStub* lir = new(alloc()) LNullarySharedStub(); + + defineSharedStubReturn(lir, ins); + assignSafepoint(lir, ins); +} + +void LIRGenerator::visitLambda(MLambda* ins) { if (ins->info().singletonType || ins->info().useSingletonForClone) { // If the function has a singleton type, this instruction will only be // executed once so we don't bother inlining it. // // If UseSingletonForClone is true, we will assign a singleton type to // the clone and we have to clone the script, we can't do that inline.
--- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -166,16 +166,17 @@ class LIRGenerator : public LIRGenerator void visitRegExpMatcher(MRegExpMatcher* ins); void visitRegExpSearcher(MRegExpSearcher* ins); void visitRegExpTester(MRegExpTester* ins); void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins); void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins); void visitStringReplace(MStringReplace* ins); void visitBinarySharedStub(MBinarySharedStub* ins); void visitUnarySharedStub(MUnarySharedStub* ins); + void visitNullarySharedStub(MNullarySharedStub* ins); void visitLambda(MLambda* ins); void visitLambdaArrow(MLambdaArrow* ins); void visitKeepAliveObject(MKeepAliveObject* ins); void visitSlots(MSlots* ins); void visitElements(MElements* ins); void visitConstantElements(MConstantElements* ins); void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins); void visitMaybeToDoubleElement(MMaybeToDoubleElement* ins);
--- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -496,33 +496,29 @@ IonBuilder::inlineArray(CallInfo& callIn // Don't inline large allocations. if (initLength > ArrayObject::EagerAllocationMaxLength) return InliningStatus_NotInlined; } callInfo.setImplicitlyUsedUnchecked(); - MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); - current->add(templateConst); - - MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst, - templateObject->group()->initialHeap(constraints()), pc); - current->add(ins); - current->push(ins); - + if (!jsop_newarray(templateObject, initLength)) + return InliningStatus_Error; + + MDefinition* array = current->peek(-1); if (callInfo.argc() >= 2) { JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject); for (uint32_t i = 0; i < initLength; i++) { MDefinition* value = callInfo.getArg(i); - if (!initializeArrayElement(ins, i, value, unboxedType, /* addResumePoint = */ false)) + if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false)) return InliningStatus_Error; } - MInstruction* setLength = setInitializedLength(ins, unboxedType, initLength); + MInstruction* setLength = setInitializedLength(array, unboxedType, initLength); if (!resumeAfter(setLength)) return InliningStatus_Error; } return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -2062,26 +2058,21 @@ IonBuilder::inlineObjectCreate(CallInfo& MOZ_ASSERT(types->getKnownMIRType() == MIRType_Object); } else { if (arg->type() != MIRType_Null) return InliningStatus_NotInlined; } callInfo.setImplicitlyUsedUnchecked(); - MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); - current->add(templateConst); - MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, - templateObject->group()->initialHeap(constraints()), - MNewObject::ObjectCreate); - current->add(ins); - current->push(ins); - if (!resumeAfter(ins)) + bool emitted = false; + if (!newObjectTryTemplateObject(&emitted, templateObject)) return InliningStatus_Error; + MOZ_ASSERT(emitted); return InliningStatus_Inlined; } IonBuilder::InliningStatus IonBuilder::inlineDefineDataProperty(CallInfo& callInfo) { MOZ_ASSERT(!callInfo.constructing());
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -4315,24 +4315,16 @@ MBeta::printOpcode(GenericPrinter& out) { MDefinition::printOpcode(out); out.printf(" "); comparison_->dump(out); } bool -MNewObject::shouldUseVM() const -{ - if (JSObject* obj = templateObject()) - return obj->is<PlainObject>() && obj->as<PlainObject>().hasDynamicSlots(); - return true; -} - -bool MCreateThisWithTemplate::canRecoverOnBailout() const { MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>()); MOZ_ASSERT_IF(templateObject()->is<PlainObject>(), !templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite()); return true; } @@ -4551,35 +4543,16 @@ MNewArray::MNewArray(CompilerConstraintL setResultTypeSet(types); if (types->convertDoubleElements(constraints) == TemporaryTypeSet::AlwaysConvertToDoubles) convertDoubleElements_ = true; } } } bool -MNewArray::shouldUseVM() const -{ - if (!templateObject()) - return true; - - if (templateObject()->is<UnboxedArrayObject>()) { - MOZ_ASSERT(templateObject()->as<UnboxedArrayObject>().capacity() >= length()); - return !templateObject()->as<UnboxedArrayObject>().hasInlineElements(); - } - - MOZ_ASSERT(length() <= NativeObject::MAX_DENSE_ELEMENTS_COUNT); - - size_t arraySlots = - gc::GetGCKindSlots(templateObject()->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER; - - return length() > arraySlots; -} - -bool MLoadFixedSlot::mightAlias(const MDefinition* store) const { if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot()) return false; return true; } bool
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3086,20 +3086,16 @@ class MNewArray jsbytecode* pc() const { return pc_; } bool convertDoubleElements() const { return convertDoubleElements_; } - // Returns true if the code generator should call through to the - // VM rather than the fast path. - bool shouldUseVM() const; - // NewArray is marked as non-effectful because all our allocations are // either lazy when we are using "new Array(length)" or bounded by the // script or the stack size when we are using "new Array(...)" or "[...]" // notations. So we might have to allocate the array twice if we bail // during the computation of the first element of the square braket // notation. virtual AliasSet getAliasSet() const override { return AliasSet::None(); @@ -3208,17 +3204,17 @@ class MNewObject Mode mode_; MNewObject(CompilerConstraintList* constraints, MConstant* templateConst, gc::InitialHeap initialHeap, Mode mode) : MUnaryInstruction(templateConst), initialHeap_(initialHeap), mode_(mode) { - MOZ_ASSERT_IF(mode != ObjectLiteral, !shouldUseVM()); + MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject()); setResultType(MIRType_Object); if (JSObject* obj = templateObject()) setResultTypeSet(MakeSingletonTypeSet(constraints, obj)); // The constant is kept separated in a MConstant, this way we can safely // mark it during GC if we recover the object allocation. Otherwise, by // making it emittedAtUses, we do not produce register allocations for @@ -3233,20 +3229,16 @@ class MNewObject static MNewObject* New(TempAllocator& alloc, CompilerConstraintList* constraints, MConstant* templateConst, gc::InitialHeap initialHeap, Mode mode) { return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode); } - // Returns true if the code generator should call through to the - // VM rather than the fast path. - bool shouldUseVM() const; - Mode mode() const { return mode_; } JSObject* templateObject() const { return getOperand(0)->toConstant()->toObjectOrNull(); } @@ -7606,16 +7598,34 @@ class MUnarySharedStub INSTRUCTION_HEADER(UnarySharedStub) static MUnarySharedStub* New(TempAllocator& alloc, MDefinition* input) { return new(alloc) MUnarySharedStub(input); } }; +class MNullarySharedStub + : public MNullaryInstruction +{ + explicit MNullarySharedStub() + : MNullaryInstruction() + { + setResultType(MIRType_Value); + } + + public: + INSTRUCTION_HEADER(NullarySharedStub) + + static MNullarySharedStub* New(TempAllocator& alloc) + { + return new(alloc) MNullarySharedStub(); + } +}; + // Check the current frame for over-recursion past the global stack limit. class MCheckOverRecursed : public MNullaryInstruction { public: INSTRUCTION_HEADER(CheckOverRecursed) static MCheckOverRecursed* New(TempAllocator& alloc) {
--- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -47,16 +47,17 @@ namespace jit { _(Beta) \ _(OsrValue) \ _(OsrScopeChain) \ _(OsrReturnValue) \ _(OsrArgumentsObject) \ _(ReturnFromCtor) \ _(BinarySharedStub) \ _(UnarySharedStub) \ + _(NullarySharedStub) \ _(CheckOverRecursed) \ _(DefVar) \ _(DefLexical) \ _(DefFun) \ _(CreateThis) \ _(CreateThisWithProto) \ _(CreateThisWithTemplate) \ _(CreateArgumentsObject) \
--- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -4513,55 +4513,55 @@ ICUpdatedStub::addUpdateStubForValue(JSC return true; } // // NewArray_Fallback // static bool -DoNewArray(JSContext* cx, BaselineFrame* frame, ICNewArray_Fallback* stub, uint32_t length, +DoNewArray(JSContext* cx, void* payload, ICNewArray_Fallback* stub, uint32_t length, MutableHandleValue res) { + SharedStubInfo info(cx, payload, stub->icEntry()); + FallbackICSpew(cx, stub, "NewArray"); RootedObject obj(cx); if (stub->templateObject()) { RootedObject templateObject(cx, stub->templateObject()); obj = NewArrayOperationWithTemplate(cx, templateObject); if (!obj) return false; } else { - RootedScript script(cx, frame->script()); - jsbytecode* pc = stub->icEntry()->pc(script); + HandleScript script = info.script(); + jsbytecode* pc = info.pc(); obj = NewArrayOperation(cx, script, pc, length); if (!obj) return false; if (obj && !obj->isSingleton() && !obj->group()->maybePreliminaryObjects()) { JSObject* templateObject = NewArrayOperation(cx, script, pc, length, TenuredObject); if (!templateObject) return false; stub->setTemplateObject(templateObject); } } res.setObject(*obj); return true; } -typedef bool(*DoNewArrayFn)(JSContext*, BaselineFrame*, ICNewArray_Fallback*, uint32_t, +typedef bool(*DoNewArrayFn)(JSContext*, void*, ICNewArray_Fallback*, uint32_t, MutableHandleValue); static const VMFunction DoNewArrayInfo = FunctionInfo<DoNewArrayFn>(DoNewArray, TailCall); bool ICNewArray_Fallback::Compiler::generateStubCode(MacroAssembler& masm) { - MOZ_ASSERT(engine_ == Engine::Baseline); - EmitRestoreTailCallReg(masm); masm.push(R0.scratchReg()); // length masm.push(ICStubReg); // stub. pushStubPayload(masm, R0.scratchReg()); return tailCallVM(DoNewArrayInfo, masm); } @@ -4597,38 +4597,41 @@ GenerateNewObjectWithTemplateCode(JSCont EmitStubGuardFailure(masm); Linker linker(masm); AutoFlushICache afc("GenerateNewObjectWithTemplateCode"); return linker.newCode<CanGC>(cx, BASELINE_CODE); } static bool -DoNewObject(JSContext* cx, BaselineFrame* frame, ICNewObject_Fallback* stub, MutableHandleValue res) +DoNewObject(JSContext* cx, void* payload, ICNewObject_Fallback* stub, MutableHandleValue res) { + SharedStubInfo info(cx, payload, stub->icEntry()); + FallbackICSpew(cx, stub, "NewObject"); RootedObject obj(cx); RootedObject templateObject(cx, stub->templateObject()); if (templateObject) { MOZ_ASSERT(!templateObject->group()->maybePreliminaryObjects()); obj = NewObjectOperationWithTemplate(cx, templateObject); } else { - RootedScript script(cx, frame->script()); - jsbytecode* pc = stub->icEntry()->pc(script); + HandleScript script = info.script(); + jsbytecode* pc = info.pc(); obj = NewObjectOperation(cx, script, pc); if (obj && !obj->isSingleton() && !obj->group()->maybePreliminaryObjects()) { JSObject* templateObject = NewObjectOperation(cx, script, pc, TenuredObject); if (!templateObject) return false; - if (templateObject->is<UnboxedPlainObject>() || - !templateObject->as<PlainObject>().hasDynamicSlots()) + if (!stub->invalid() && + (templateObject->is<UnboxedPlainObject>() || + !templateObject->as<PlainObject>().hasDynamicSlots())) { JitCode* code = GenerateNewObjectWithTemplateCode(cx, templateObject); if (!code) return false; ICStubSpace* space = ICStubCompiler::StubSpaceForKind(ICStub::NewObject_WithTemplate, script, ICStubCompiler::Engine::Baseline); @@ -4645,24 +4648,22 @@ DoNewObject(JSContext* cx, BaselineFrame if (!obj) return false; res.setObject(*obj); return true; } -typedef bool(*DoNewObjectFn)(JSContext*, BaselineFrame*, ICNewObject_Fallback*, MutableHandleValue); +typedef bool(*DoNewObjectFn)(JSContext*, void*, ICNewObject_Fallback*, MutableHandleValue); static const VMFunction DoNewObjectInfo = FunctionInfo<DoNewObjectFn>(DoNewObject, TailCall); bool ICNewObject_Fallback::Compiler::generateStubCode(MacroAssembler& masm) { - MOZ_ASSERT(engine_ == Engine::Baseline); - EmitRestoreTailCallReg(masm); masm.push(ICStubReg); // stub. pushStubPayload(masm, R0.scratchReg()); return tailCallVM(DoNewObjectInfo, masm); }
--- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -3233,16 +3233,17 @@ class ICGetProp_ArgumentsCallee : public ICStub* getStub(ICStubSpace* space) { return newStub<ICGetProp_ArgumentsCallee>(space, getStubCode(), firstMonitorStub_); } }; }; // JSOP_NEWARRAY +// JSOP_NEWINIT class ICNewArray_Fallback : public ICFallbackStub { friend class ICStubSpace; HeapPtrObject templateObject_; // The group used for objects created here is always available, even if the @@ -3255,18 +3256,18 @@ class ICNewArray_Fallback : public ICFal {} public: class Compiler : public ICStubCompiler { RootedObjectGroup templateGroup; bool generateStubCode(MacroAssembler& masm); public: - Compiler(JSContext* cx, ObjectGroup* templateGroup) - : ICStubCompiler(cx, ICStub::NewArray_Fallback, Engine::Baseline), + Compiler(JSContext* cx, ObjectGroup* templateGroup, Engine engine) + : ICStubCompiler(cx, ICStub::NewArray_Fallback, engine), templateGroup(cx, templateGroup) {} ICStub* getStub(ICStubSpace* space) { return newStub<ICNewArray_Fallback>(space, getStubCode(), templateGroup); } }; @@ -3301,18 +3302,18 @@ class ICNewObject_Fallback : public ICFa : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(nullptr) {} public: class Compiler : public ICStubCompiler { bool generateStubCode(MacroAssembler& masm); public: - explicit Compiler(JSContext* cx) - : ICStubCompiler(cx, ICStub::NewObject_Fallback, Engine::Baseline) + explicit Compiler(JSContext* cx, Engine engine) + : ICStubCompiler(cx, ICStub::NewObject_Fallback, engine) {} ICStub* getStub(ICStubSpace* space) { return newStub<ICNewObject_Fallback>(space, getStubCode()); } }; HeapPtrObject& templateObject() {
--- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -886,17 +886,17 @@ class LNewArray : public LInstructionHel public: LIR_HEADER(NewArray) explicit LNewArray(const LDefinition& temp) { setTemp(0, temp); } const char* extraName() const { - return mir()->shouldUseVM() ? "VMCall" : nullptr; + return mir()->templateObject() ? "VMCall" : nullptr; } const LDefinition* temp() { return getTemp(0); } MNewArray* mir() const { return mir_->toNewArray(); @@ -948,17 +948,17 @@ class LNewObject : public LInstructionHe public: LIR_HEADER(NewObject) explicit LNewObject(const LDefinition& temp) { setTemp(0, temp); } const char* extraName() const { - return mir()->shouldUseVM() ? "VMCall" : nullptr; + return mir()->templateObject() ? "VMCall" : nullptr; } const LDefinition* temp() { return getTemp(0); } MNewObject* mir() const { return mir_->toNewObject(); @@ -4508,16 +4508,26 @@ class LUnarySharedStub : public LCallIns const MUnarySharedStub* mir() const { return mir_->toUnarySharedStub(); } static const size_t Input = 0; }; +class LNullarySharedStub : public LCallInstructionHelper<BOX_PIECES, 0, 0> +{ + public: + LIR_HEADER(NullarySharedStub) + + const MNullarySharedStub* mir() const { + return mir_->toNullarySharedStub(); + } +}; + class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0> { public: LIR_HEADER(LambdaForSingleton) explicit LLambdaForSingleton(const LAllocation& scopeChain) { setOperand(0, scopeChain);
--- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -210,16 +210,17 @@ _(RegExpSearcher) \ _(RegExpTester) \ _(RegExpPrototypeOptimizable) \ _(RegExpInstanceOptimizable) \ _(StringReplace) \ _(Substr) \ _(BinarySharedStub) \ _(UnarySharedStub) \ + _(NullarySharedStub) \ _(Lambda) \ _(LambdaArrow) \ _(LambdaForSingleton) \ _(KeepAliveObject) \ _(Slots) \ _(Elements) \ _(ConvertElementsToDoubles) \ _(MaybeToDoubleElement) \
--- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -191,17 +191,17 @@ LIRGeneratorShared::defineInt64(LInstruc add(lir); } void LIRGeneratorShared::defineSharedStubReturn(LInstruction* lir, MDefinition* mir) { lir->setMir(mir); - MOZ_ASSERT(lir->isBinarySharedStub() || lir->isUnarySharedStub()); + MOZ_ASSERT(lir->isBinarySharedStub() || lir->isUnarySharedStub() || lir->isNullarySharedStub()); MOZ_ASSERT(mir->type() == MIRType_Value); uint32_t vreg = getVirtualRegister(); #if defined(JS_NUNBOX32) lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, LGeneralReg(JSReturnReg_Type))); lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD,