Bug 1552229 - Emit field keys in correct order. r=jorendorff
authorAshley Hauck <khyperia@mozilla.com>
Tue, 21 May 2019 17:55:34 +0000
changeset 474824 9953e8853243fe62ad2d74d30df1231cf5c5898f
parent 474823 b0583bec17687ad56b05a4216f2ba6787e361306
child 474825 60bf0ae446ce30b797a928d8f7961aadb00662b4
push id86002
push userahauck@mozilla.com
push dateTue, 21 May 2019 17:57:21 +0000
treeherderautoland@9953e8853243 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1552229
milestone69.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 1552229 - Emit field keys in correct order. r=jorendorff Differential Revision: https://phabricator.services.mozilla.com/D31495
js/src/frontend/BytecodeEmitter.cpp
js/src/jit-test/tests/fields/bug1552229.js
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -7631,21 +7631,53 @@ bool BytecodeEmitter::emitConditionalExp
 
   return true;
 }
 
 bool BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe,
                                        PropListType type) {
   //                [stack] CTOR? OBJ
 
+  size_t curFieldKeyIndex = 0;
   for (ParseNode* propdef : obj->contents()) {
     if (propdef->is<ClassField>()) {
-      // Skip over class fields and emit them at the end.  This is needed
-      // because they're all emitted into a single array, which is then stored
-      // into a local variable.
+      MOZ_ASSERT(type == ClassBody);
+      // Only handle computing field keys here: the .initializers lambda array
+      // is created elsewhere.
+      ClassField* field = &propdef->as<ClassField>();
+      if (field->name().getKind() == ParseNodeKind::ComputedName) {
+        if (!emitGetName(cx->names().dotFieldKeys)) {
+          //        [stack] CTOR? OBJ ARRAY
+          return false;
+        }
+
+        ParseNode* nameExpr = field->name().as<UnaryNode>().kid();
+
+        if (!emitTree(nameExpr)) {
+          //        [stack] CTOR? OBJ ARRAY KEY
+          return false;
+        }
+
+        if (!emit1(JSOP_TOID)) {
+          //        [stack] CTOR? OBJ ARRAY KEY
+          return false;
+        }
+
+        if (!emitUint32Operand(JSOP_INITELEM_ARRAY, curFieldKeyIndex)) {
+          //        [stack] CTOR? OBJ ARRAY
+          return false;
+        }
+
+        if (!emit1(JSOP_POP)) {
+          //        [stack] CTOR? OBJ
+          return false;
+        }
+
+        curFieldKeyIndex++;
+      }
       continue;
     }
 
     if (propdef->is<LexicalScopeNode>()) {
       // Constructors are sometimes wrapped in LexicalScopeNodes. As we already
       // handled emitting the constructor, skip it.
       MOZ_ASSERT(propdef->as<LexicalScopeNode>().scopeBody()->isKind(
           ParseNodeKind::ClassMethod));
@@ -7938,17 +7970,18 @@ FieldInitializers BytecodeEmitter::setup
 //   }
 // ];
 // class C {
 //   constructor() {
 //     .initializers[0]();
 //   }
 // }
 //
-// BytecodeEmitter::emitCreateFieldKeys does `let .fieldKeys = [keyExpr, ...];`
+// BytecodeEmitter::emitCreateFieldKeys does `let .fieldKeys = [...];`
+// BytecodeEmitter::emitPropertyList fills in the elements of the array.
 // See GeneralParser::fieldInitializer for the `this[.fieldKeys[0]]` part.
 bool BytecodeEmitter::emitCreateFieldKeys(ListNode* obj) {
   size_t numFieldKeys = 0;
   for (ParseNode* propdef : obj->contents()) {
     if (propdef->is<ClassField>()) {
       ClassField* field = &propdef->as<ClassField>();
       if (field->name().getKind() == ParseNodeKind::ComputedName) {
         numFieldKeys++;
@@ -7966,44 +7999,16 @@ bool BytecodeEmitter::emitCreateFieldKey
     return false;
   }
 
   if (!emitUint32Operand(JSOP_NEWARRAY, numFieldKeys)) {
     //              [stack] ARRAY
     return false;
   }
 
-  size_t curFieldKeyIndex = 0;
-  for (ParseNode* propdef : obj->contents()) {
-    if (propdef->is<ClassField>()) {
-      ClassField* field = &propdef->as<ClassField>();
-      if (field->name().getKind() == ParseNodeKind::ComputedName) {
-        ParseNode* nameExpr = field->name().as<UnaryNode>().kid();
-
-        if (!emitTree(nameExpr)) {
-          //        [stack] ARRAY KEY
-          return false;
-        }
-
-        if (!emit1(JSOP_TOID)) {
-          //        [stack] ARRAY KEY
-          return false;
-        }
-
-        if (!emitUint32Operand(JSOP_INITELEM_ARRAY, curFieldKeyIndex)) {
-          //        [stack] ARRAY
-          return false;
-        }
-
-        curFieldKeyIndex++;
-      }
-    }
-  }
-  MOZ_ASSERT(curFieldKeyIndex == numFieldKeys);
-
   if (!noe.emitAssignment()) {
     //              [stack] ARRAY
     return false;
   }
 
   if (!emit1(JSOP_POP)) {
     //              [stack]
     return false;
@@ -8772,25 +8777,26 @@ bool BytecodeEmitter::emitClass(
     }
   } else {
     if (!ce.emitInitDefaultConstructor(Some(classNode->pn_pos.begin),
                                        Some(classNode->pn_pos.end))) {
       //            [stack] CTOR HOMEOBJ
       return false;
     }
   }
+
+  if (!emitCreateFieldKeys(classMembers)) {
+    return false;
+  }
+
   if (!emitPropertyList(classMembers, ce, ClassBody)) {
     //              [stack] CTOR HOMEOBJ
     return false;
   }
 
-  if (!emitCreateFieldKeys(classMembers)) {
-    return false;
-  }
-
   if (!ce.emitEnd(kind)) {
     //              [stack] # class declaration
     //              [stack]
     //              [stack] # class expression
     //              [stack] CTOR
     return false;
   }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/fields/bug1552229.js
@@ -0,0 +1,17 @@
+// |jit-test| --enable-experimental-fields
+
+let i = 0;
+function f(x) {
+    assertEq(++i, x);
+    return x;
+}
+class C{
+    [f(1)](){}
+    [f(2)] = "hi";
+    [f(3)](){}
+    [f(4)] = "hi";
+}
+new C();
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);