Bug 1169745 - Support JSOP_SUPERBASE in Baseline draft
authorTed Campbell <tcampbell@mozilla.com>
Fri, 02 Jun 2017 16:12:48 -0400
changeset 588498 a6c0424eb2a284f253a3a75d0cb46a463243e526
parent 585921 cce4d83d2b99ffedbd67a2f40ce26e53e9ae27ab
child 631593 bf4bffaf0dee8d3e6fd44af109c846d39f530aa4
push id62060
push userbmo:tcampbell@mozilla.com
push dateFri, 02 Jun 2017 22:10:55 +0000
bugs1169745
milestone55.0a1
Bug 1169745 - Support JSOP_SUPERBASE in Baseline MozReview-Commit-ID: QA2j2Wsrs8
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jsfun.h
--- 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];
 };