Bug 1169745 - Support JSOP_SUPERBASE in Baseline
MozReview-Commit-ID: QA2j2Wsrs8
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -4139,16 +4139,92 @@ BaselineCompiler::emit_JSOP_CALLEE()
MOZ_ASSERT(function());
frame.syncStack(0);
masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), R0.scratchReg());
masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
frame.push(R0);
return true;
}
+void
+BaselineCompiler::getThisEnvironment(Register reg)
+{
+ // Directly load callee from frame if we are in a Method
+ if (function() && function()->isMethod()) {
+ masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), reg);
+ return;
+ }
+
+ // Locate environment chain
+ masm.loadPtr(frame.addressOfEnvironmentChain(), reg);
+
+ // Walk environment chain until first non-arrow CallObject
+ for (ScopeIter si(script->innermostScope(pc)); si; si++) {
+ if (si.hasSyntacticEnvironment() && si.scope()->is<FunctionScope>()) {
+ JSFunction* fn = si.scope()->as<FunctionScope>().canonicalFunction();
+
+ // Skip arrow function scopes
+ if (fn->isArrow())
+ continue;
+
+ Address next_addr(reg, EnvironmentObject::offsetOfEnclosingEnvironment());
+ masm.unboxObject(next_addr, reg);
+ }
+ }
+
+ // Load callee
+ masm.unboxObject(Address(reg, CallObject::offsetOfCallee()), reg);
+}
+
+typedef JSObject* (*HomeObjectSuperBaseFn)(JSContext*, HandleObject);
+static const VMFunction HomeObjectSuperBaseInfo =
+ FunctionInfo<HomeObjectSuperBaseFn>(HomeObjectSuperBase, "HomeObjectSuperBase");
+
+bool
+BaselineCompiler::emit_JSOP_SUPERBASE()
+{
+ frame.syncStack(0);
+
+ Register scratch = R0.scratchReg();
+ Register proto = R1.scratchReg();
+
+ // Lookup CallObject
+ getThisEnvironment(scratch);
+
+ // Load [[HomeObject]]
+ // NOTE: Should always be defined in contexts |super| is allowed.
+ Address homeobj_addr(scratch, FunctionExtended::offsetOfMethodHomeObjectSlot());
+#ifdef DEBUG
+ Label isObject;
+ masm.branchTestObject(Assembler::Equal, homeobj_addr, &isObject);
+ masm.assumeUnreachable("[[HomeObject]] must be Object");
+ masm.bind(&isObject);
+#endif
+ masm.unboxObject(homeobj_addr, scratch);
+
+ // Load prototype from [[HomeObject]]
+ masm.loadObjProto(scratch, proto);
+
+ Label hasProto;
+ masm.branchPtr(Assembler::Above, proto, ImmWord(1), &hasProto);
+
+ // Use VMCall for missing or lazy proto
+ prepareVMCall();
+ pushArg(scratch); // [[HomeObject]]
+ if (!callVM(HomeObjectSuperBaseInfo))
+ return false;
+ masm.movePtr(ReturnReg, proto);
+
+ // Box prototype and return
+ masm.bind(&hasProto);
+ masm.tagValue(JSVAL_TYPE_OBJECT, proto, R1);
+ frame.push(R1);
+ return true;
+}
+
typedef bool (*NewArgumentsObjectFn)(JSContext*, BaselineFrame*, MutableHandleValue);
static const VMFunction NewArgumentsObjectInfo =
FunctionInfo<NewArgumentsObjectFn>(jit::NewArgumentsObject, "NewArgumentsObject");
bool
BaselineCompiler::emit_JSOP_ARGUMENTS()
{
frame.syncStack(0);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -211,16 +211,17 @@ namespace jit {
_(JSOP_GENERATOR) \
_(JSOP_INITIALYIELD) \
_(JSOP_YIELD) \
_(JSOP_AWAIT) \
_(JSOP_DEBUGAFTERYIELD) \
_(JSOP_FINALYIELDRVAL) \
_(JSOP_RESUME) \
_(JSOP_CALLEE) \
+ _(JSOP_SUPERBASE) \
_(JSOP_GETRVAL) \
_(JSOP_SETRVAL) \
_(JSOP_RETRVAL) \
_(JSOP_RETURN) \
_(JSOP_FUNCTIONTHIS) \
_(JSOP_GLOBALTHIS) \
_(JSOP_CHECKISOBJ) \
_(JSOP_CHECKISCALLABLE) \
@@ -354,16 +355,18 @@ class BaselineCompiler : public Baseline
MOZ_MUST_USE bool addPCMappingEntry(bool addIndexEntry);
MOZ_MUST_USE bool addYieldAndAwaitOffset();
void getEnvironmentCoordinateObject(Register reg);
Address getEnvironmentCoordinateAddressFromObject(Register objReg, Register reg);
Address getEnvironmentCoordinateAddress(Register reg);
+
+ void getThisEnvironment(Register reg);
};
extern const VMFunction NewArrayCopyOnWriteInfo;
} // namespace jit
} // namespace js
#endif /* jit_BaselineCompiler_h */
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1799,11 +1799,28 @@ ConcatStringsPure(JSContext* cx, JSStrin
// nullptr and let caller do a bailout. Return true to indicate no exception
// thrown.
*res = ConcatStrings<NoGC>(cx, lhs, rhs);
MOZ_ASSERT(!cx->isExceptionPending());
return true;
}
+JSObject*
+HomeObjectSuperBase(JSContext* cx, HandleObject homeObj)
+{
+ RootedObject superBase(cx);
+
+ if (!GetPrototype(cx, homeObj, &superBase))
+ return nullptr;
+
+ if (!superBase) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
+ "null", "object");
+ return nullptr;
+ }
+
+ return superBase;
+}
+
} // namespace jit
} // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -869,12 +869,15 @@ bool
ObjectHasGetterSetter(JSContext* cx, JSObject* obj, Shape* propShape);
JSString*
TypeOfObject(JSObject* obj, JSRuntime* rt);
bool
ConcatStringsPure(JSContext* cx, JSString* lhs, JSString* rhs, JSString** res);
+JSObject*
+HomeObjectSuperBase(JSContext* cx, HandleObject homeObj);
+
} // namespace jit
} // namespace js
#endif /* jit_VMFunctions_h */
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -767,16 +767,19 @@ class FunctionExtended : public JSFuncti
static inline size_t offsetOfExtendedSlot(unsigned which) {
MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
return offsetof(FunctionExtended, extendedSlots) + which * sizeof(GCPtrValue);
}
static inline size_t offsetOfArrowNewTargetSlot() {
return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
}
+ static inline size_t offsetOfMethodHomeObjectSlot() {
+ return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT);
+ }
private:
friend class JSFunction;
/* Reserved slots available for storage by particular native functions. */
GCPtrValue extendedSlots[NUM_EXTENDED_SLOTS];
};