Bug 1273858 - Ion-compile JSOP_FRESHENLEXICALENV/JSOP_RECREATELEXICALENV
MozReview-Commit-ID: DHFceqW3YlD
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3446,16 +3446,29 @@ void
CodeGenerator::visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir)
{
pushArg(Imm32(gc::DefaultHeap));
pushArg(ToRegister(lir->enclosing()));
pushArg(ImmGCPtr(lir->mir()->scope()));
callVM(NewLexicalEnvironmentObjectInfo, lir);
}
+typedef JSObject* (*CopyLexicalEnvironmentObjectFn)(JSContext*, HandleObject, bool);
+static const VMFunction CopyLexicalEnvironmentObjectInfo =
+ FunctionInfo<CopyLexicalEnvironmentObjectFn>(js::jit::CopyLexicalEnvironmentObject,
+ "js::jit::CopyLexicalEnvironmentObject");
+
+void
+CodeGenerator::visitCopyLexicalEnvironmentObject(LCopyLexicalEnvironmentObject* lir)
+{
+ pushArg(Imm32(lir->mir()->copySlots()));
+ pushArg(ToRegister(lir->env()));
+ callVM(CopyLexicalEnvironmentObjectInfo, 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
@@ -283,16 +283,17 @@ class CodeGenerator final : public CodeG
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 visitCopyLexicalEnvironmentObject(LCopyLexicalEnvironmentObject* 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
@@ -2203,16 +2203,22 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_PUSHLEXICALENV:
return jsop_pushlexicalenv(GET_UINT32_INDEX(pc));
case JSOP_POPLEXICALENV:
current->setEnvironmentChain(walkEnvironmentChain(1));
return Ok();
+ case JSOP_FRESHENLEXICALENV:
+ return jsop_copylexicalenv(true);
+
+ case JSOP_RECREATELEXICALENV:
+ return jsop_copylexicalenv(false);
+
case JSOP_ITER:
return jsop_iter(GET_INT8(pc));
case JSOP_MOREITER:
return jsop_itermore();
case JSOP_ISNOITER:
return jsop_isnoiter();
@@ -2265,26 +2271,16 @@ IonBuilder::inspectOpcode(JSOp op)
#endif
return Ok();
}
case JSOP_IS_CONSTRUCTING:
pushConstant(MagicValue(JS_IS_CONSTRUCTING));
return Ok();
-#ifdef DEBUG
- case JSOP_FRESHENLEXICALENV:
- case JSOP_RECREATELEXICALENV:
- // 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:
break;
}
// Track a simpler message, since the actionable abort message is a
// static string, and the internal opcode name isn't an actionable
// thing anyways.
trackActionableAbort("Unsupported bytecode");
@@ -11853,16 +11849,30 @@ IonBuilder::jsop_pushlexicalenv(uint32_t
current->add(ins);
current->setEnvironmentChain(ins);
return resumeAfter(ins);
}
AbortReasonOr<Ok>
+IonBuilder::jsop_copylexicalenv(bool copySlots)
+{
+ MOZ_ASSERT(analysis().usesEnvironmentChain());
+
+ MCopyLexicalEnvironmentObject* ins =
+ MCopyLexicalEnvironmentObject::New(alloc(), current->environmentChain(), copySlots);
+
+ 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
@@ -557,16 +557,17 @@ class IonBuilder
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_copylexicalenv(bool copySlots);
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
@@ -2489,16 +2489,29 @@ LIRGenerator::visitNewLexicalEnvironment
LNewLexicalEnvironmentObject* lir =
new(alloc()) LNewLexicalEnvironmentObject(useRegisterAtStart(enclosing));
defineReturn(lir, ins);
assignSafepoint(lir, ins);
}
void
+LIRGenerator::visitCopyLexicalEnvironmentObject(MCopyLexicalEnvironmentObject* ins)
+{
+ MDefinition* env = ins->env();
+ MOZ_ASSERT(env->type() == MIRType::Object);
+
+ LCopyLexicalEnvironmentObject* lir =
+ new(alloc()) LCopyLexicalEnvironmentObject(useRegisterAtStart(env));
+
+ 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
@@ -182,16 +182,17 @@ class LIRGenerator : public LIRGenerator
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 visitCopyLexicalEnvironmentObject(MCopyLexicalEnvironmentObject* 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
@@ -11509,16 +11509,43 @@ class MNewLexicalEnvironmentObject
bool possiblyCalls() const override {
return true;
}
bool appendRoots(MRootList& roots) const override {
return roots.append(scope_);
}
};
+// Allocate a new LexicalEnvironmentObject from existing one
+class MCopyLexicalEnvironmentObject
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ bool copySlots_;
+
+ MCopyLexicalEnvironmentObject(MDefinition* env, bool copySlots)
+ : MUnaryInstruction(env),
+ copySlots_(copySlots)
+ {
+ setResultType(MIRType::Object);
+ }
+
+ public:
+ INSTRUCTION_HEADER(CopyLexicalEnvironmentObject)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, env))
+
+ bool copySlots() const {
+ return copySlots_;
+ }
+ bool possiblyCalls() const override {
+ return true;
+ }
+};
+
// 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
@@ -168,16 +168,17 @@ namespace jit {
_(ConstantElements) \
_(ConvertElementsToDoubles) \
_(MaybeToDoubleElement) \
_(MaybeCopyElementsForWrite) \
_(LoadSlot) \
_(StoreSlot) \
_(FunctionEnvironment) \
_(NewLexicalEnvironmentObject) \
+ _(CopyLexicalEnvironmentObject) \
_(FilterTypeSet) \
_(TypeBarrier) \
_(MonitorTypes) \
_(PostWriteBarrier) \
_(PostWriteElementBarrier) \
_(GetPropertyCache) \
_(GetPropertyPolymorphic) \
_(SetPropertyPolymorphic) \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -920,16 +920,27 @@ NewArgumentsObject(JSContext* cx, Baseli
ArgumentsObject* obj = ArgumentsObject::createExpected(cx, frame);
if (!obj)
return false;
res.setObject(*obj);
return true;
}
JSObject*
+CopyLexicalEnvironmentObject(JSContext* cx, HandleObject env, bool copySlots)
+{
+ Handle<LexicalEnvironmentObject*> lexicalEnv = env.as<LexicalEnvironmentObject>();
+
+ if (copySlots)
+ return LexicalEnvironmentObject::clone(cx, lexicalEnv);
+
+ return LexicalEnvironmentObject::recreate(cx, lexicalEnv);
+}
+
+JSObject*
InitRestParameter(JSContext* cx, uint32_t length, Value* rest, HandleObject templateObj,
HandleObject objRes)
{
if (objRes) {
Rooted<ArrayObject*> arrRes(cx, &objRes->as<ArrayObject>());
MOZ_ASSERT(!arrRes->getDenseInitializedLength());
MOZ_ASSERT(arrRes->group() == templateObj->group());
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -709,16 +709,18 @@ GlobalNameConflictsCheckFromIon(JSContex
MOZ_MUST_USE bool
CheckGlobalOrEvalDeclarationConflicts(JSContext* cx, BaselineFrame* frame);
MOZ_MUST_USE bool
InitFunctionEnvironmentObjects(JSContext* cx, BaselineFrame* frame);
MOZ_MUST_USE bool
NewArgumentsObject(JSContext* cx, BaselineFrame* frame, MutableHandleValue res);
+JSObject* CopyLexicalEnvironmentObject(JSContext* cx, HandleObject env, bool copySlots);
+
JSObject* InitRestParameter(JSContext* cx, uint32_t length, Value* rest, HandleObject templateObj,
HandleObject res);
MOZ_MUST_USE bool
HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr, bool* mustReturn);
MOZ_MUST_USE bool
OnDebuggerStatement(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn);
MOZ_MUST_USE bool
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7056,16 +7056,34 @@ class LNewLexicalEnvironmentObject : pub
return getOperand(0);
}
MNewLexicalEnvironmentObject* mir() const {
return mir_->toNewLexicalEnvironmentObject();
}
};
+// Copy a LexicalEnvironmentObject.
+class LCopyLexicalEnvironmentObject : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(CopyLexicalEnvironmentObject)
+
+ explicit LCopyLexicalEnvironmentObject(const LAllocation& env) {
+ setOperand(0, env);
+ }
+ const LAllocation* env() {
+ return getOperand(0);
+ }
+
+ MCopyLexicalEnvironmentObject* mir() const {
+ return mir_->toCopyLexicalEnvironmentObject();
+ }
+};
+
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
@@ -315,16 +315,17 @@
_(ClampVToUint8) \
_(LoadFixedSlotV) \
_(LoadFixedSlotT) \
_(LoadFixedSlotAndUnbox) \
_(StoreFixedSlotV) \
_(StoreFixedSlotT) \
_(FunctionEnvironment) \
_(NewLexicalEnvironmentObject) \
+ _(CopyLexicalEnvironmentObject) \
_(GetPropertyCacheV) \
_(GetPropertyCacheT) \
_(GetPropertyPolymorphicV) \
_(GetPropertyPolymorphicT) \
_(BindNameCache) \
_(CallBindVar) \
_(CallGetProperty) \
_(GetNameCache) \