Bug 1322314 - Part 2: Disallow emitting ParseNode twice (backout 908dce87d771). r=shu
authorTooru Fujisawa <arai_a@mac.com>
Thu, 15 Dec 2016 16:54:45 +0900
changeset 370957 06f2e1a6a1a29e58b211e94b93e813c39b7d150e
parent 370956 4681df10417515f060f2b48eeeddf96c16828dcf
child 370958 61c633e7330a39e481907b2fb6288a674e837a71
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1322314
milestone53.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
Bug 1322314 - Part 2: Disallow emitting ParseNode twice (backout 908dce87d771). r=shu
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ParseNode.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6953,24 +6953,23 @@ BytecodeEmitter::emitComprehensionFor(Pa
 
 MOZ_NEVER_INLINE bool
 BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
 {
     FunctionBox* funbox = pn->pn_funbox;
     RootedFunction fun(cx, funbox->function());
     RootedAtom name(cx, fun->explicitName());
     MOZ_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript());
-    MOZ_ASSERT_IF(pn->isOp(JSOP_FUNWITHPROTO), needsProto);
 
     /*
      * Set the |wasEmitted| flag in the funbox once the function has been
      * emitted. Function definitions that need hoisting to the top of the
      * function will be seen by emitFunction in two places.
      */
-    if (funbox->wasEmitted && pn->functionIsHoisted()) {
+    if (funbox->wasEmitted) {
         // Annex B block-scoped functions are hoisted like any other
         // block-scoped function to the top of their scope. When their
         // definitions are seen for the second time, we need to emit the
         // assignment that assigns the function to the outer 'var' binding.
         if (funbox->isAnnexB) {
             auto emitRhs = [&name](BytecodeEmitter* bce, const NameLocation&, bool) {
                 // The RHS is the value of the lexically bound name in the
                 // innermost scope.
@@ -7089,17 +7088,17 @@ BytecodeEmitter::emitFunction(ParseNode*
                     return false;
             } else {
                 if (!emit1(JSOP_NULL))
                     return false;
             }
         }
 
         if (needsProto) {
-            MOZ_ASSERT(pn->getOp() == JSOP_FUNWITHPROTO || pn->getOp() == JSOP_LAMBDA);
+            MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA);
             pn->setOp(JSOP_FUNWITHPROTO);
         }
 
         if (pn->getOp() == JSOP_DEFFUN) {
             if (!emitIndex32(JSOP_LAMBDA, index))
                 return false;
             return emit1(JSOP_DEFFUN);
         }
@@ -10025,45 +10024,30 @@ void
 CGConstList::finish(ConstArray* array)
 {
     MOZ_ASSERT(length() == array->length);
 
     for (unsigned i = 0; i < length(); i++)
         array->vector[i] = list[i];
 }
 
-bool
-CGObjectList::isAdded(ObjectBox* objbox)
-{
-    // An objbox added to CGObjectList as non-first element has non-null
-    // emitLink member.  The first element has null emitLink.
-    // Check for firstbox to cover the first element.
-    return objbox->emitLink || objbox == firstbox;
-}
-
 /*
  * Find the index of the given object for code generator.
  *
  * Since the emitter refers to each parsed object only once, for the index we
  * use the number of already indexed objects. We also add the object to a list
  * to convert the list to a fixed-size array when we complete code generation,
  * see js::CGObjectList::finish below.
  */
 unsigned
 CGObjectList::add(ObjectBox* objbox)
 {
-    if (isAdded(objbox))
-        return indexOf(objbox->object);
-
+    MOZ_ASSERT(!objbox->emitLink);
     objbox->emitLink = lastbox;
     lastbox = objbox;
-
-    // See the comment in CGObjectList::isAdded.
-    if (!firstbox)
-        firstbox = objbox;
     return length++;
 }
 
 unsigned
 CGObjectList::indexOf(JSObject* obj)
 {
     MOZ_ASSERT(length > 0);
     unsigned index = length - 1;
@@ -10080,22 +10064,17 @@ CGObjectList::finish(ObjectArray* array)
 
     js::GCPtrObject* cursor = array->vector + array->length;
     ObjectBox* objbox = lastbox;
     do {
         --cursor;
         MOZ_ASSERT(!*cursor);
         MOZ_ASSERT(objbox->object->isTenured());
         *cursor = objbox->object;
-
-        ObjectBox* tmp = objbox->emitLink;
-        // Clear emitLink for CGObjectList::isAdded.
-        objbox->emitLink = nullptr;
-        objbox = tmp;
-    } while (objbox != nullptr);
+    } while ((objbox = objbox->emitLink) != nullptr);
     MOZ_ASSERT(cursor == array->vector);
 }
 
 ObjectBox*
 CGObjectList::find(uint32_t index)
 {
     MOZ_ASSERT(index < length);
     ObjectBox* box = lastbox;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -38,22 +38,20 @@ class CGConstList {
         return list.append(v);
     }
     size_t length() const { return list.length(); }
     void finish(ConstArray* array);
 };
 
 struct CGObjectList {
     uint32_t            length;     /* number of emitted so far objects */
-    ObjectBox*          firstbox;  /* first emitted object */
     ObjectBox*          lastbox;   /* last emitted object */
 
-    CGObjectList() : length(0), firstbox(nullptr), lastbox(nullptr) {}
+    CGObjectList() : length(0), lastbox(nullptr) {}
 
-    bool isAdded(ObjectBox* objbox);
     unsigned add(ObjectBox* objbox);
     unsigned indexOf(JSObject* obj);
     void finish(ObjectArray* array);
     ObjectBox* find(uint32_t index);
 };
 
 struct MOZ_STACK_CLASS CGScopeList {
     Rooted<GCVector<Scope*>> vector;
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -644,24 +644,22 @@ class ParseNode
                                            1. array initialiser has holes
                                            2. array initializer has spread node */
 #define PNX_NONCONST    0x04            /* initialiser has non-constants */
 
     bool functionIsHoisted() const {
         MOZ_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION);
         MOZ_ASSERT(isOp(JSOP_LAMBDA) ||        // lambda, genexpr
                    isOp(JSOP_LAMBDA_ARROW) ||  // arrow function
-                   isOp(JSOP_FUNWITHPROTO) ||  // already emitted lambda with needsProto
                    isOp(JSOP_DEFFUN) ||        // non-body-level function statement
                    isOp(JSOP_NOP) ||           // body-level function stmt in global code
                    isOp(JSOP_GETLOCAL) ||      // body-level function stmt in function code
                    isOp(JSOP_GETARG) ||        // body-level function redeclaring formal
                    isOp(JSOP_INITLEXICAL));    // block-level function stmt
-        return !isOp(JSOP_LAMBDA) && !isOp(JSOP_LAMBDA_ARROW) &&
-               !isOp(JSOP_FUNWITHPROTO) && !isOp(JSOP_DEFFUN);
+        return !isOp(JSOP_LAMBDA) && !isOp(JSOP_LAMBDA_ARROW) && !isOp(JSOP_DEFFUN);
     }
 
     /*
      * True if this statement node could be a member of a Directive Prologue: an
      * expression statement consisting of a single string literal.
      *
      * This considers only the node and its children, not its context. After
      * parsing, check the node's pn_prologue flag to see if it is indeed part of