8020354: Object literal property initialization is not done in source order
authorhannesw
Mon, 15 Jul 2013 15:51:06 +0200
changeset 18877 6d75ba520886
parent 18876 ada98218aaae
child 18878 078eb52cf5bc
8020354: Object literal property initialization is not done in source order Reviewed-by: sundar, jlaskey
nashorn/src/jdk/nashorn/internal/parser/Parser.java
nashorn/test/script/basic/JDK-8020354.js
nashorn/test/script/basic/JDK-8020354.js.EXPECTED
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Mon Jul 15 12:33:48 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Mon Jul 15 15:51:06 2013 +0200
@@ -55,9 +55,9 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import jdk.nashorn.internal.codegen.CompilerConstants;
@@ -1946,14 +1946,14 @@
 
         // Object context.
         // Prepare to accumulate elements.
-        // final List<Node> elements = new ArrayList<>();
-        final Map<String, PropertyNode> map = new LinkedHashMap<>();
+        final List<PropertyNode> elements = new ArrayList<>();
+        final Map<String, Integer> map = new HashMap<>();
 
         // Create a block for the object literal.
-            boolean commaSeen = true;
+        boolean commaSeen = true;
 loop:
-            while (true) {
-                switch (type) {
+        while (true) {
+            switch (type) {
                 case RBRACE:
                     next();
                     break loop;
@@ -1975,14 +1975,16 @@
                     // Get and add the next property.
                     final PropertyNode property = propertyAssignment();
                     final String key = property.getKeyName();
-                    final PropertyNode existingProperty = map.get(key);
-
-                    if (existingProperty == null) {
-                        map.put(key, property);
-                       // elements.add(property);
+                    final Integer existing = map.get(key);
+
+                    if (existing == null) {
+                        map.put(key, elements.size());
+                        elements.add(property);
                         break;
                     }
 
+                    final PropertyNode existingProperty = elements.get(existing);
+
                     // ECMA section 11.1.5 Object Initialiser
                     // point # 4 on property assignment production
                     final Expression   value  = property.getValue();
@@ -1993,12 +1995,9 @@
                     final FunctionNode prevGetter = existingProperty.getGetter();
                     final FunctionNode prevSetter = existingProperty.getSetter();
 
-                    boolean redefinitionOk = true;
                     // ECMA 11.1.5 strict mode restrictions
-                    if (isStrictMode) {
-                        if (value != null && prevValue != null) {
-                            redefinitionOk = false;
-                        }
+                    if (isStrictMode && value != null && prevValue != null) {
+                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
                     }
 
                     final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
@@ -2006,49 +2005,33 @@
 
                     // data property redefined as accessor property
                     if (prevValue != null && isAccessor) {
-                        redefinitionOk = false;
+                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
                     }
 
                     // accessor property redefined as data
                     if (isPrevAccessor && value != null) {
-                        redefinitionOk = false;
+                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
                     }
 
                     if (isAccessor && isPrevAccessor) {
                         if (getter != null && prevGetter != null ||
-                            setter != null && prevSetter != null) {
-                            redefinitionOk = false;
+                                setter != null && prevSetter != null) {
+                            throw error(AbstractParser.message("property.redefinition", key), property.getToken());
                         }
                     }
 
-                    if (!redefinitionOk) {
-                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
-                    }
-
-                    PropertyNode newProperty = existingProperty;
                     if (value != null) {
-                        if (prevValue == null) {
-                            map.put(key, newProperty = newProperty.setValue(value));
-                        } else {
-                            final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
-                            map.put(key, newProperty = newProperty.setValue(new BinaryNode(propertyToken, prevValue, value)));
-                        }
-
-                        map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
-                    }
-
-                    if (getter != null) {
-                        map.put(key, newProperty = newProperty.setGetter(getter));
-                    }
-
-                    if (setter != null) {
-                        map.put(key, newProperty = newProperty.setSetter(setter));
+                        elements.add(property);
+                    } else if (getter != null) {
+                        elements.set(existing, existingProperty.setGetter(getter));
+                    } else if (setter != null) {
+                        elements.set(existing, existingProperty.setSetter(setter));
                     }
                     break;
             }
         }
 
-        return new ObjectNode(objectToken, finish, new ArrayList<>(map.values()));
+        return new ObjectNode(objectToken, finish, elements);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8020354.js	Mon Jul 15 15:51:06 2013 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8020354: Object literal property initialization is not done in source order
+ *
+ * @test
+ * @run
+ */
+
+
+var obj = ({a: print(1), b: print(2), a: print(3)});
+
+var obj = ({
+    a: print(1),
+    get x() { print("getting x"); return "x" },
+    set x(v) { print("setting x"); },
+    b: print(2),
+    a: print(3)
+});
+
+print(obj.x);
+obj.x = 4;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8020354.js.EXPECTED	Mon Jul 15 15:51:06 2013 +0200
@@ -0,0 +1,9 @@
+1
+2
+3
+1
+2
+3
+getting x
+x
+setting x