Bug 1552229 - Emit field keys in correct order. r=jorendorff
☠☠ backed out by b702646a08e3 ☠ ☠
authorAshley Hauck <khyperia@mozilla.com>
Mon, 20 May 2019 18:36:33 +0000
changeset 474577 a8f5dec91d72d4032ced008f847ead37f350193f
parent 474576 6004e7f60bb6ae49de462c658b137da437d216cd
child 474578 586ea3b717009c60d461b56fe874a86332523b25
push id36042
push userdvarga@mozilla.com
push dateTue, 21 May 2019 04:19:40 +0000
treeherdermozilla-central@ca560ff55451 [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);