8062030: Nashorn bug retrieving array property after key string concatenation

Reviewed-by: sundar, lagergren, attila
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
index d2f23e8..0624b73 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
@@ -40,6 +40,7 @@
 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.JSType;
 
 /**
@@ -170,12 +171,12 @@
             if (index > -1) {
                 return JSOBJECT_GETSLOT.invokeExact(jsobj, index);
             }
-        } else if (key instanceof String) {
-            final String name = (String)key;
+        } else if (key instanceof String || key instanceof ConsString) {
+            final String name = key.toString();
             if (name.indexOf('(') != -1) {
-                return fallback.invokeExact(jsobj, key);
+                return fallback.invokeExact(jsobj, (Object) name);
             }
-            return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key);
+            return JSOBJECT_GETMEMBER.invokeExact(jsobj, name);
         }
         return null;
     }
@@ -186,8 +187,8 @@
             JSOBJECT_SETSLOT.invokeExact(jsobj, (int)key, value);
         } else if (key instanceof Number) {
             JSOBJECT_SETSLOT.invokeExact(jsobj, getIndex((Number)key), value);
-        } else if (key instanceof String) {
-            JSOBJECT_SETMEMBER.invokeExact(jsobj, (String)key, value);
+        } else if (key instanceof String || key instanceof ConsString) {
+            JSOBJECT_SETMEMBER.invokeExact(jsobj, key.toString(), value);
         }
     }
 
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index aaf5a2c..48772ae 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -42,6 +42,7 @@
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.JSType;
 
 /**
@@ -185,11 +186,11 @@
             if (index > -1) {
                 return ((JSObject)jsobj).getSlot(index);
             }
-        } else if (key instanceof String) {
-            final String name = (String)key;
+        } else if (key instanceof String || key instanceof ConsString) {
+            final String name = key.toString();
             // get with method name and signature. delegate it to beans linker!
             if (name.indexOf('(') != -1) {
-                return fallback.invokeExact(jsobj, key);
+                return fallback.invokeExact(jsobj, (Object) name);
             }
             return ((JSObject)jsobj).getMember(name);
         }
@@ -202,8 +203,8 @@
             ((JSObject)jsobj).setSlot((Integer)key, value);
         } else if (key instanceof Number) {
             ((JSObject)jsobj).setSlot(getIndex((Number)key), value);
-        } else if (key instanceof String) {
-            ((JSObject)jsobj).setMember((String)key, value);
+        } else if (key instanceof String || key instanceof ConsString) {
+            ((JSObject)jsobj).setMember(key.toString(), value);
         }
     }
 
diff --git a/nashorn/test/script/basic/JDK-8055762.js b/nashorn/test/script/basic/JDK-8055762.js
index e772a57..a0aac52 100644
--- a/nashorn/test/script/basic/JDK-8055762.js
+++ b/nashorn/test/script/basic/JDK-8055762.js
@@ -74,9 +74,12 @@
         }
     };
 
+    var a = "a";
     print(obj["foo"]);
+    print(obj[a + "bc"]);
     print(obj[2]);
     obj.bar = 23;
+    obj[a + "bc"] = 23;
     obj[3] = 23;
     obj.func("hello");
 }
diff --git a/nashorn/test/script/basic/JDK-8055762.js.EXPECTED b/nashorn/test/script/basic/JDK-8055762.js.EXPECTED
index 51a0201..1cba646 100644
--- a/nashorn/test/script/basic/JDK-8055762.js.EXPECTED
+++ b/nashorn/test/script/basic/JDK-8055762.js.EXPECTED
@@ -1,5 +1,7 @@
 FOO
+ABC
 0
 bar set to 23
+abc set to 23
 [3] set to 23
 func called with hello
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java
index b277bde..d6b9dcd 100644
--- a/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java
@@ -109,6 +109,35 @@
         }
     }
 
+    // @bug 8062030: Nashorn bug retrieving array property after key string concatenation
+    @Test
+    // ConsString attribute access on a JSObject
+    public void consStringTest() {
+        final ScriptEngineManager m = new ScriptEngineManager();
+        final ScriptEngine e = m.getEngineByName("nashorn");
+        try {
+            final MapWrapperObject obj = new MapWrapperObject();
+            e.put("obj", obj);
+            e.put("f", "f");
+            e.eval("obj[f + 'oo'] = 'bar';");
+
+            assertEquals(obj.getMap().get("foo"), "bar");
+            assertEquals(e.eval("obj[f + 'oo']"), "bar");
+            assertEquals(e.eval("obj['foo']"), "bar");
+            assertEquals(e.eval("f + 'oo' in obj"), Boolean.TRUE);
+            assertEquals(e.eval("'foo' in obj"), Boolean.TRUE);
+            e.eval("delete obj[f + 'oo']");
+            assertFalse(obj.getMap().containsKey("foo"));
+            assertEquals(e.eval("obj[f + 'oo']"), null);
+            assertEquals(e.eval("obj['foo']"), null);
+            assertEquals(e.eval("f + 'oo' in obj"), Boolean.FALSE);
+            assertEquals(e.eval("'foo' in obj"), Boolean.FALSE);
+        } catch (final Exception exp) {
+            exp.printStackTrace();
+            fail(exp.getMessage());
+        }
+    }
+
     public static class BufferObject extends AbstractJSObject {
         private final IntBuffer buf;