8020354: Object literal property initialization is not done in source order
Reviewed-by: sundar, jlaskey
--- 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