--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java 2016-11-25 16:10:51.000000000 +0100 +++ new/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java 2016-11-25 16:10:51.000000000 +0100 @@ -822,13 +822,12 @@ private static void concatToList(final ArrayList list, final Object obj) { final boolean isScriptArray = isArray(obj); final boolean isScriptObject = isScriptArray || obj instanceof ScriptObject; - if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) { + if (isScriptArray || obj instanceof Iterable || obj instanceof JSObject || (obj != null && obj.getClass().isArray())) { final Iterator iter = arrayLikeIterator(obj, true); if (iter.hasNext()) { for (int i = 0; iter.hasNext(); ++i) { final Object value = iter.next(); - final boolean lacksIndex = obj != null && !((ScriptObject)obj).has(i); - if (value == ScriptRuntime.UNDEFINED && isScriptObject && lacksIndex) { + if (value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) { // TODO: eventually rewrite arrayLikeIterator to use a three-state enum for handling // UNDEFINED instead of an "includeUndefined" boolean with states SKIP, INCLUDE, // RETURN_EMPTY. Until then, this is how we'll make sure that empty elements don't make it @@ -1828,15 +1827,14 @@ } final Object arg = args[2]; - //args[2] continuousarray or non arraydata, let past non array datas + // The generic version uses its own logic and ArrayLikeIterator to decide if an object should + // be iterated over or added as single element. To avoid duplication of code and err on the safe side + // we only use the specialized version if arg is either a continuous array or a JS primitive. if (arg instanceof NativeArray) { - final ContinuousArrayData argData = getContinuousArrayData(arg); - if (argData == null) { - return false; - } + return (getContinuousArrayData(arg) != null); } - return true; + return JSType.isPrimitive(arg); } } --- /dev/null 2016-11-25 16:10:52.000000000 +0100 +++ new/test/script/basic/JDK-8161579.js 2016-11-25 16:10:52.000000000 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, 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-8161579: Array-like AbstractJSObject-based instance not treated as array by native array functions + * + * @test + * @run + */ + + +var AbstractJSObject = Java.type("jdk.nashorn.api.scripting.AbstractJSObject"); +var JavaStringArray = Java.type("java.lang.String[]"); +var JavaArrayList = Java.type("java.util.ArrayList"); + +var arrayLikeJSObject = new AbstractJSObject() { + hasMember: function(name) { return name == "length"; }, + getMember: function(name) { return name == "length" ? 3 : null; }, + hasSlot: function(slot) { return slot >= 0 && slot <= 2; }, + getSlot: function(slot) { return "abc"[slot]; }, + isArray: function() { return true; } +} + +var javaStringArray = new JavaStringArray(3); +javaStringArray[0] = "x"; +javaStringArray[1] = "y"; +javaStringArray[2] = "z"; + +var javaArrayList = new JavaArrayList(); +javaArrayList.add("i"); +javaArrayList.add("j"); +javaArrayList.add("k"); + +Assert.assertEquals([1, 2, 3].concat(arrayLikeJSObject).join(), "1,2,3,a,b,c"); +Assert.assertEquals([1, 2, 3].concat(javaStringArray).join(), "1,2,3,x,y,z"); +Assert.assertEquals([1, 2, 3].concat(javaArrayList).join(), "1,2,3,i,j,k"); +Assert.assertEquals([1, 2, 3].concat("foo").join(), "1,2,3,foo"); +Assert.assertEquals([1, 2, 3].concat(4).join(), "1,2,3,4"); +Assert.assertEquals([1, 2, 3].concat(false).join(), "1,2,3,false"); +