Bug 1273858 - Ion-compile JSOP_PUSHLEXICALENV/JSOP_POPLEXICALENV
MozReview-Commit-ID: CqD2GUGoNyY
--- a/js/src/jit/BytecodeAnalysis.cpp
+++ b/js/src/jit/BytecodeAnalysis.cpp
@@ -163,16 +163,18 @@ BytecodeAnalysis::init(TempAllocator& al
case JSOP_STRICTSETNAME:
case JSOP_DELNAME:
case JSOP_GETALIASEDVAR:
case JSOP_SETALIASEDVAR:
case JSOP_LAMBDA:
case JSOP_LAMBDA_ARROW:
case JSOP_DEFFUN:
case JSOP_DEFVAR:
+ case JSOP_PUSHLEXICALENV:
+ case JSOP_POPLEXICALENV:
usesEnvironmentChain_ = true;
break;
case JSOP_GETGNAME:
case JSOP_SETGNAME:
case JSOP_STRICTSETGNAME:
if (script_->hasNonSyntacticScope())
usesEnvironmentChain_ = true;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3430,16 +3430,32 @@ CodeGenerator::visitMaybeCopyElementsFor
void
CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment* lir)
{
Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
masm.loadPtr(environment, ToRegister(lir->output()));
}
+typedef LexicalEnvironmentObject* (*NewLexicalEnvironmentObjectFn)(JSContext*,
+ Handle<LexicalScope*>,
+ HandleObject, gc::InitialHeap);
+static const VMFunction NewLexicalEnvironmentObjectInfo =
+ FunctionInfo<NewLexicalEnvironmentObjectFn>(LexicalEnvironmentObject::create,
+ "LexicalEnvironmentObject::create");
+
+void
+CodeGenerator::visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir)
+{
+ pushArg(Imm32(gc::DefaultHeap));
+ pushArg(ToRegister(lir->enclosing()));
+ pushArg(ImmGCPtr(lir->mir()->scope()));
+ callVM(NewLexicalEnvironmentObjectInfo, lir);
+}
+
void
CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity* guard)
{
Register input = ToRegister(guard->input());
Register expected = ToRegister(guard->expected());
Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -282,16 +282,17 @@ class CodeGenerator final : public CodeG
void emitConcat(LInstruction* lir, Register lhs, Register rhs, Register output);
void visitConcat(LConcat* lir);
void visitCharCodeAt(LCharCodeAt* lir);
void visitFromCharCode(LFromCharCode* lir);
void visitFromCodePoint(LFromCodePoint* lir);
void visitSinCos(LSinCos *lir);
void visitStringSplit(LStringSplit* lir);
void visitFunctionEnvironment(LFunctionEnvironment* lir);
+ void visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir);
void visitCallGetProperty(LCallGetProperty* lir);
void visitCallGetElement(LCallGetElement* lir);
void visitCallSetElement(LCallSetElement* lir);
void visitCallInitElementArray(LCallInitElementArray* lir);
void visitThrow(LThrow* lir);
void visitTypeOfV(LTypeOfV* lir);
void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
void visitToAsync(LToAsync* lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2196,16 +2196,23 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_lambda(info().getFunction(pc));
case JSOP_LAMBDA_ARROW:
return jsop_lambda_arrow(info().getFunction(pc));
case JSOP_SETFUNNAME:
return jsop_setfunname(GET_UINT8(pc));
+ case JSOP_PUSHLEXICALENV:
+ return jsop_pushlexicalenv(GET_UINT32_INDEX(pc));
+
+ case JSOP_POPLEXICALENV:
+ current->setEnvironmentChain(walkEnvironmentChain(1));
+ return Ok();
+
case JSOP_ITER:
return jsop_iter(GET_INT8(pc));
case JSOP_MOREITER:
return jsop_itermore();
case JSOP_ISNOITER:
return jsop_isnoiter();
@@ -2259,20 +2266,18 @@ IonBuilder::inspectOpcode(JSOp op)
return Ok();
}
case JSOP_IS_CONSTRUCTING:
pushConstant(MagicValue(JS_IS_CONSTRUCTING));
return Ok();
#ifdef DEBUG
- case JSOP_PUSHLEXICALENV:
case JSOP_FRESHENLEXICALENV:
case JSOP_RECREATELEXICALENV:
- case JSOP_POPLEXICALENV:
// These opcodes are currently unhandled by Ion, but in principle
// there's no reason they couldn't be. Whenever this happens, OSR
// will have to consider that JSOP_{FRESHEN,RECREATE}LEXICALENV
// mutates the env chain -- right now MBasicBlock::environmentChain()
// caches the env chain. JSOP_{FRESHEN,RECREATE}LEXICALENV must
// update that stale value.
#endif
default:
@@ -11833,16 +11838,31 @@ IonBuilder::jsop_setfunname(uint8_t pref
current->add(ins);
current->push(fun);
return resumeAfter(ins);
}
AbortReasonOr<Ok>
+IonBuilder::jsop_pushlexicalenv(uint32_t index)
+{
+ MOZ_ASSERT(analysis().usesEnvironmentChain());
+
+ LexicalScope* scope = &script()->getScope(index)->as<LexicalScope>();
+ MNewLexicalEnvironmentObject* ins =
+ MNewLexicalEnvironmentObject::New(alloc(), current->environmentChain(), scope);
+
+ current->add(ins);
+ current->setEnvironmentChain(ins);
+
+ return resumeAfter(ins);
+}
+
+AbortReasonOr<Ok>
IonBuilder::jsop_setarg(uint32_t arg)
{
// To handle this case, we should spill the arguments to the space where
// actual arguments are stored. The tricky part is that if we add a MIR
// to wrap the spilling action, we don't want the spilling to be
// captured by the GETARG and by the resume point, only by
// MGetFrameArgument.
MOZ_ASSERT(analysis_.hasSetArg());
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -556,16 +556,17 @@ class IonBuilder
AbortReasonOr<Ok> jsop_mutateproto();
AbortReasonOr<Ok> jsop_initprop(PropertyName* name);
AbortReasonOr<Ok> jsop_initprop_getter_setter(PropertyName* name);
AbortReasonOr<Ok> jsop_regexp(RegExpObject* reobj);
AbortReasonOr<Ok> jsop_object(JSObject* obj);
AbortReasonOr<Ok> jsop_lambda(JSFunction* fun);
AbortReasonOr<Ok> jsop_lambda_arrow(JSFunction* fun);
AbortReasonOr<Ok> jsop_setfunname(uint8_t prefixKind);
+ AbortReasonOr<Ok> jsop_pushlexicalenv(uint32_t index);
AbortReasonOr<Ok> jsop_functionthis();
AbortReasonOr<Ok> jsop_globalthis();
AbortReasonOr<Ok> jsop_typeof();
AbortReasonOr<Ok> jsop_toasync();
AbortReasonOr<Ok> jsop_toid();
AbortReasonOr<Ok> jsop_iter(uint8_t flags);
AbortReasonOr<Ok> jsop_itermore();
AbortReasonOr<Ok> jsop_isnoiter();
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2476,16 +2476,29 @@ LIRGenerator::visitSetFunName(MSetFunNam
LSetFunName* lir = new(alloc()) LSetFunName(useRegisterAtStart(ins->fun()),
useBoxAtStart(ins->name()));
add(lir, ins);
assignSafepoint(lir, ins);
}
void
+LIRGenerator::visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* ins)
+{
+ MDefinition* enclosing = ins->enclosing();
+ MOZ_ASSERT(enclosing->type() == MIRType::Object);
+
+ LNewLexicalEnvironmentObject* lir =
+ new(alloc()) LNewLexicalEnvironmentObject(useRegisterAtStart(enclosing));
+
+ defineReturn(lir, ins);
+ assignSafepoint(lir, ins);
+}
+
+void
LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins)
{
MDefinition* obj = ins->object();
MOZ_ASSERT(obj->type() == MIRType::Object);
add(new(alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
}
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -181,16 +181,17 @@ class LIRGenerator : public LIRGenerator
void visitGetFirstDollarIndex(MGetFirstDollarIndex* 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 visitSetFunName(MSetFunName* ins);
+ void visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* 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);
void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins);
void visitLoadSlot(MLoadSlot* ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -11479,16 +11479,46 @@ class MFunctionEnvironment
MDefinition* foldsTo(TempAllocator& alloc) override;
// A function's environment is fixed.
AliasSet getAliasSet() const override {
return AliasSet::None();
}
};
+// Allocate a new LexicalEnvironmentObject.
+class MNewLexicalEnvironmentObject
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ CompilerGCPointer<LexicalScope*> scope_;
+
+ MNewLexicalEnvironmentObject(MDefinition* enclosing, LexicalScope* scope)
+ : MUnaryInstruction(enclosing),
+ scope_(scope)
+ {
+ setResultType(MIRType::Object);
+ }
+
+ public:
+ INSTRUCTION_HEADER(NewLexicalEnvironmentObject)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, enclosing))
+
+ LexicalScope* scope() const {
+ return scope_;
+ }
+ bool possiblyCalls() const override {
+ return true;
+ }
+ bool appendRoots(MRootList& roots) const override {
+ return roots.append(scope_);
+ }
+};
+
// Store to vp[slot] (slots that are not inline in an object).
class MStoreSlot
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
{
uint32_t slot_;
MIRType slotType_;
bool needsBarrier_;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -167,16 +167,17 @@ namespace jit {
_(Elements) \
_(ConstantElements) \
_(ConvertElementsToDoubles) \
_(MaybeToDoubleElement) \
_(MaybeCopyElementsForWrite) \
_(LoadSlot) \
_(StoreSlot) \
_(FunctionEnvironment) \
+ _(NewLexicalEnvironmentObject) \
_(FilterTypeSet) \
_(TypeBarrier) \
_(MonitorTypes) \
_(PostWriteBarrier) \
_(PostWriteElementBarrier) \
_(GetPropertyCache) \
_(GetPropertyPolymorphic) \
_(SetPropertyPolymorphic) \
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -273,16 +273,17 @@ struct VMFunction
template <class> struct TypeToDataType { /* Unexpected return type for a VMFunction. */ };
template <> struct TypeToDataType<bool> { static const DataType result = Type_Bool; };
template <> struct TypeToDataType<JSObject*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<NativeObject*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<PlainObject*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<InlineTypedObject*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<NamedLambdaObject*> { static const DataType result = Type_Object; };
+template <> struct TypeToDataType<LexicalEnvironmentObject*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<ArrayObject*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<TypedArrayObject*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<JSString*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<JSFlatString*> { static const DataType result = Type_Object; };
template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<HandleString> { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<HandlePropertyName> { static const DataType result = Type_Handle; };
template <> struct TypeToDataType<HandleFunction> { static const DataType result = Type_Handle; };
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7038,16 +7038,34 @@ class LFunctionEnvironment : public LIns
explicit LFunctionEnvironment(const LAllocation& function) {
setOperand(0, function);
}
const LAllocation* function() {
return getOperand(0);
}
};
+// Allocate a new LexicalEnvironmentObject.
+class LNewLexicalEnvironmentObject : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NewLexicalEnvironmentObject)
+
+ explicit LNewLexicalEnvironmentObject(const LAllocation& enclosing) {
+ setOperand(0, enclosing);
+ }
+ const LAllocation* enclosing() {
+ return getOperand(0);
+ }
+
+ MNewLexicalEnvironmentObject* mir() const {
+ return mir_->toNewLexicalEnvironmentObject();
+ }
+};
+
class LCallGetProperty : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
{
public:
LIR_HEADER(CallGetProperty)
static const size_t Value = 0;
explicit LCallGetProperty(const LBoxAllocation& val) {
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -314,16 +314,17 @@
_(ClampDToUint8) \
_(ClampVToUint8) \
_(LoadFixedSlotV) \
_(LoadFixedSlotT) \
_(LoadFixedSlotAndUnbox) \
_(StoreFixedSlotV) \
_(StoreFixedSlotT) \
_(FunctionEnvironment) \
+ _(NewLexicalEnvironmentObject) \
_(GetPropertyCacheV) \
_(GetPropertyCacheT) \
_(GetPropertyPolymorphicV) \
_(GetPropertyPolymorphicT) \
_(BindNameCache) \
_(CallBindVar) \
_(CallGetProperty) \
_(GetNameCache) \
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -884,18 +884,18 @@ LexicalEnvironmentObject::createTemplate
if (enclosing)
env->initEnclosingEnvironment(enclosing);
return env;
}
/* static */ LexicalEnvironmentObject*
-LexicalEnvironmentObject::createTemplateObject(JSContext* cx, Handle<LexicalScope*> scope,
- HandleObject enclosing, gc::InitialHeap heap)
+LexicalEnvironmentObject::create(JSContext* cx, Handle<LexicalScope*> scope,
+ HandleObject enclosing, gc::InitialHeap heap)
{
assertSameCompartment(cx, enclosing);
MOZ_ASSERT(scope->hasEnvironment());
RootedShape shape(cx, scope->environmentShape());
LexicalEnvironmentObject* env = createTemplateObject(cx, shape, enclosing, heap);
if (!env)
return nullptr;
@@ -910,17 +910,17 @@ LexicalEnvironmentObject::createTemplate
return env;
}
/* static */ LexicalEnvironmentObject*
LexicalEnvironmentObject::create(JSContext* cx, Handle<LexicalScope*> scope,
AbstractFramePtr frame)
{
RootedObject enclosing(cx, frame.environmentChain());
- return createTemplateObject(cx, scope, enclosing, gc::DefaultHeap);
+ return create(cx, scope, enclosing, gc::DefaultHeap);
}
/* static */ LexicalEnvironmentObject*
LexicalEnvironmentObject::createGlobal(JSContext* cx, Handle<GlobalObject*> global)
{
MOZ_ASSERT(global);
RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
@@ -992,18 +992,17 @@ LexicalEnvironmentObject::createHollowFo
return env;
}
/* static */ LexicalEnvironmentObject*
LexicalEnvironmentObject::clone(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
{
Rooted<LexicalScope*> scope(cx, &env->scope());
RootedObject enclosing(cx, &env->enclosingEnvironment());
- Rooted<LexicalEnvironmentObject*> copy(cx, createTemplateObject(cx, scope, enclosing,
- gc::TenuredHeap));
+ Rooted<LexicalEnvironmentObject*> copy(cx, create(cx, scope, enclosing, gc::TenuredHeap));
if (!copy)
return nullptr;
// We can't assert that the clone has the same shape, because it could
// have been reshaped by PurgeEnvironmentChain.
MOZ_ASSERT(env->slotSpan() == copy->slotSpan());
for (uint32_t i = JSSLOT_FREE(&class_); i < copy->slotSpan(); i++)
copy->setSlot(i, env->getSlot(i));
@@ -1011,17 +1010,17 @@ LexicalEnvironmentObject::clone(JSContex
return copy;
}
/* static */ LexicalEnvironmentObject*
LexicalEnvironmentObject::recreate(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
{
Rooted<LexicalScope*> scope(cx, &env->scope());
RootedObject enclosing(cx, &env->enclosingEnvironment());
- return createTemplateObject(cx, scope, enclosing, gc::TenuredHeap);
+ return create(cx, scope, enclosing, gc::TenuredHeap);
}
bool
LexicalEnvironmentObject::isExtensible() const
{
return nonProxyIsExtensible();
}
@@ -1066,18 +1065,17 @@ NamedLambdaObject::create(JSContext* cx,
#ifdef DEBUG
// There should be exactly one binding in the named lambda scope.
BindingIter bi(scope);
bi++;
MOZ_ASSERT(bi.done());
#endif
LexicalEnvironmentObject* obj =
- LexicalEnvironmentObject::createTemplateObject(cx, scope.as<LexicalScope>(),
- enclosing, heap);
+ LexicalEnvironmentObject::create(cx, scope.as<LexicalScope>(), enclosing, heap);
if (!obj)
return nullptr;
obj->initFixedSlot(lambdaSlot(), ObjectValue(*func));
return static_cast<NamedLambdaObject*>(obj);
}
/* static */ NamedLambdaObject*
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -472,21 +472,18 @@ class LexicalEnvironmentObject : public
void initScope(LexicalScope* scope) {
MOZ_ASSERT(!isGlobal());
MOZ_ASSERT(isSyntactic());
initScopeUnchecked(scope);
}
public:
- static LexicalEnvironmentObject* createTemplateObject(JSContext* cx,
- Handle<LexicalScope*> scope,
- HandleObject enclosing,
- gc::InitialHeap heap);
-
+ static LexicalEnvironmentObject* create(JSContext* cx, Handle<LexicalScope*> scope,
+ HandleObject enclosing, gc::InitialHeap heap);
static LexicalEnvironmentObject* create(JSContext* cx, Handle<LexicalScope*> scope,
AbstractFramePtr frame);
static LexicalEnvironmentObject* createGlobal(JSContext* cx, Handle<GlobalObject*> global);
static LexicalEnvironmentObject* createNonSyntactic(JSContext* cx, HandleObject enclosing);
static LexicalEnvironmentObject* createHollowForDebug(JSContext* cx,
Handle<LexicalScope*> scope);
// Create a new LexicalEnvironmentObject with the same enclosing env and