Tue, 03 Jun 2014 17:04:23 +0530
8044520: Nashorn cannot execute node.js's express module
Reviewed-by: hannesw, lagergren
1.1 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Tue Jun 03 13:57:52 2014 +0530 1.2 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Tue Jun 03 17:04:23 2014 +0530 1.3 @@ -496,7 +496,7 @@ 1.4 public void setProto(final Object proto) { 1.5 inGlobal(new Callable<Void>() { 1.6 @Override public Void call() { 1.7 - sobj.setProtoCheck(unwrap(proto, global)); 1.8 + sobj.setPrototypeOf(unwrap(proto, global)); 1.9 return null; 1.10 } 1.11 });
2.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Jun 03 13:57:52 2014 +0530 2.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Jun 03 17:04:23 2014 +0530 2.3 @@ -1500,7 +1500,9 @@ 2.4 method.dup(); 2.5 if (protoNode != null) { 2.6 load(protoNode); 2.7 - method.invoke(ScriptObject.SET_PROTO_CHECK); 2.8 + // take care of { __proto__: 34 } or some such! 2.9 + method.convert(Type.OBJECT); 2.10 + method.invoke(ScriptObject.SET_PROTO_FROM_LITERAL); 2.11 } else { 2.12 globalObjectPrototype(); 2.13 method.invoke(ScriptObject.SET_PROTO);
3.1 --- a/src/jdk/nashorn/internal/objects/Global.java Tue Jun 03 13:57:52 2014 +0530 3.2 +++ b/src/jdk/nashorn/internal/objects/Global.java Tue Jun 03 17:04:23 2014 +0530 3.3 @@ -1908,8 +1908,8 @@ 3.4 3.5 // ES6 draft compliant __proto__ property of Object.prototype 3.6 // accessors on Object.prototype for "__proto__" 3.7 - final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", ScriptObject.GETPROTO); 3.8 - final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", ScriptObject.SETPROTOCHECK); 3.9 + final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", NativeObject.GET__PROTO__); 3.10 + final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", NativeObject.SET__PROTO__); 3.11 ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); 3.12 3.13
4.1 --- a/src/jdk/nashorn/internal/objects/NativeObject.java Tue Jun 03 13:57:52 2014 +0530 4.2 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Tue Jun 03 17:04:23 2014 +0530 4.3 @@ -25,6 +25,7 @@ 4.4 4.5 package jdk.nashorn.internal.objects; 4.6 4.7 +import static jdk.nashorn.internal.lookup.Lookup.MH; 4.8 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 4.9 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 4.10 4.11 @@ -74,6 +75,9 @@ 4.12 */ 4.13 @ScriptClass("Object") 4.14 public final class NativeObject { 4.15 + public static final MethodHandle GET__PROTO__ = findOwnMH("get__proto__", ScriptObject.class, Object.class); 4.16 + public static final MethodHandle SET__PROTO__ = findOwnMH("set__proto__", Object.class, Object.class, Object.class); 4.17 + 4.18 private static final Object TO_STRING = new Object(); 4.19 4.20 private static InvokeByName getTO_STRING() { 4.21 @@ -86,6 +90,35 @@ 4.22 }); 4.23 } 4.24 4.25 + @SuppressWarnings("unused") 4.26 + private static ScriptObject get__proto__(final Object self) { 4.27 + // See ES6 draft spec: B.2.2.1.1 get Object.prototype.__proto__ 4.28 + // Step 1 Let O be the result of calling ToObject passing the this. 4.29 + final Object obj = Global.toObject(self); 4.30 + Global.checkObject(obj); 4.31 + final ScriptObject sobj = (ScriptObject)obj; 4.32 + return sobj.getProto(); 4.33 + } 4.34 + 4.35 + @SuppressWarnings("unused") 4.36 + private static Object set__proto__(final Object self, final Object proto) { 4.37 + // See ES6 draft spec: B.2.2.1.2 set Object.prototype.__proto__ 4.38 + // Step 1 4.39 + Global.checkObjectCoercible(self); 4.40 + // Step 4 4.41 + if (! (self instanceof ScriptObject)) { 4.42 + return UNDEFINED; 4.43 + } 4.44 + 4.45 + final ScriptObject sobj = (ScriptObject)self; 4.46 + // __proto__ assignment ignores non-nulls and non-objects 4.47 + // step 3: If Type(proto) is neither Object nor Null, then return undefined. 4.48 + if (proto == null || proto instanceof ScriptObject) { 4.49 + sobj.setPrototypeOf(proto); 4.50 + } 4.51 + return UNDEFINED; 4.52 + } 4.53 + 4.54 private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class); 4.55 private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class); 4.56 4.57 @@ -160,7 +193,7 @@ 4.58 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 4.59 public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) { 4.60 if (obj instanceof ScriptObject) { 4.61 - ((ScriptObject)obj).setProtoCheck(proto); 4.62 + ((ScriptObject)obj).setPrototypeOf(proto); 4.63 return obj; 4.64 } else if (obj instanceof ScriptObjectMirror) { 4.65 ((ScriptObjectMirror)obj).setProto(proto); 4.66 @@ -777,4 +810,8 @@ 4.67 return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation, 4.68 methodType), false, source); 4.69 } 4.70 + 4.71 + private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 4.72 + return MH.findStatic(MethodHandles.lookup(), NativeObject.class, name, MH.type(rtype, types)); 4.73 + } 4.74 }
5.1 --- a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java Tue Jun 03 13:57:52 2014 +0530 5.2 +++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java Tue Jun 03 17:04:23 2014 +0530 5.3 @@ -459,5 +459,4 @@ 5.4 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 5.5 return MH.findStatic(MethodHandles.lookup(), GlobalFunctions.class, name, MH.type(rtype, types)); 5.6 } 5.7 - 5.8 }
6.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Jun 03 13:57:52 2014 +0530 6.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Jun 03 17:04:23 2014 +0530 6.3 @@ -132,8 +132,6 @@ 6.4 6.5 /** Method handle to retrive prototype of this object */ 6.6 public static final MethodHandle GETPROTO = findOwnMH("getProto", ScriptObject.class); 6.7 - /** Method handle to set prototype of this object */ 6.8 - public static final MethodHandle SETPROTOCHECK = findOwnMH("setProtoCheck", void.class, Object.class); 6.9 static final MethodHandle MEGAMORPHIC_GET = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class, boolean.class); 6.10 static final MethodHandle GLOBALFILTER = findOwnMH("globalFilter", Object.class, Object.class); 6.11 6.12 @@ -160,7 +158,7 @@ 6.13 public static final Call SET_PROTO = virtualCallNoLookup(ScriptObject.class, "setInitialProto", void.class, ScriptObject.class); 6.14 6.15 /** Method handle for setting the proto of a ScriptObject after checking argument */ 6.16 - public static final Call SET_PROTO_CHECK = virtualCallNoLookup(ScriptObject.class, "setProtoCheck", void.class, Object.class); 6.17 + public static final Call SET_PROTO_FROM_LITERAL = virtualCallNoLookup(ScriptObject.class, "setProtoFromLiteral", void.class, Object.class); 6.18 6.19 /** Method handle for setting the user accessors of a ScriptObject */ 6.20 public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); 6.21 @@ -1127,14 +1125,21 @@ 6.22 6.23 /** 6.24 * Set the __proto__ of an object with checks. 6.25 + * This is the built-in operation [[SetPrototypeOf]] 6.26 + * See ES6 draft spec: 9.1.2 [[SetPrototypeOf]] (V) 6.27 + * 6.28 * @param newProto Prototype to set. 6.29 */ 6.30 - public final void setProtoCheck(final Object newProto) { 6.31 - if (!isExtensible()) { 6.32 - throw typeError("__proto__.set.non.extensible", ScriptRuntime.safeToString(this)); 6.33 - } 6.34 - 6.35 + public final void setPrototypeOf(final Object newProto) { 6.36 if (newProto == null || newProto instanceof ScriptObject) { 6.37 + if (!isExtensible()) { 6.38 + // okay to set same proto again - even if non-extensible 6.39 + if (newProto == getProto()) { 6.40 + return; 6.41 + } 6.42 + throw typeError("__proto__.set.non.extensible", ScriptRuntime.safeToString(this)); 6.43 + } 6.44 + 6.45 // check for circularity 6.46 ScriptObject p = (ScriptObject)newProto; 6.47 while (p != null) { 6.48 @@ -1145,14 +1150,27 @@ 6.49 } 6.50 setProto((ScriptObject)newProto); 6.51 } else { 6.52 - final Global global = Context.getGlobal(); 6.53 - final Object newProtoObject = JSType.toScriptObject(global, newProto); 6.54 - 6.55 - if (newProtoObject instanceof ScriptObject) { 6.56 - setProto((ScriptObject)newProtoObject); 6.57 - } else { 6.58 - throw typeError(global, "cant.set.proto.to.non.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(newProto)); 6.59 - } 6.60 + throw typeError("cant.set.proto.to.non.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(newProto)); 6.61 + } 6.62 + } 6.63 + 6.64 + /** 6.65 + * Set the __proto__ of an object from an object literal. 6.66 + * See ES6 draft spec: B.3.1 __proto__ Property Names in 6.67 + * Object Initializers. Step 6 handling of "__proto__". 6.68 + * 6.69 + * @param newProto Prototype to set. 6.70 + */ 6.71 + public final void setProtoFromLiteral(final Object newProto) { 6.72 + if (newProto == null || newProto instanceof ScriptObject) { 6.73 + setPrototypeOf(newProto); 6.74 + } else { 6.75 + // Some non-object, non-null. Then, we need to set 6.76 + // Object.prototype as the new __proto__ 6.77 + // 6.78 + // var obj = { __proto__ : 34 }; 6.79 + // print(obj.__proto__ === Object.prototype); // => true 6.80 + setPrototypeOf(Global.objectPrototype()); 6.81 } 6.82 } 6.83
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/script/basic/JDK-8044520.js Tue Jun 03 17:04:23 2014 +0530 7.3 @@ -0,0 +1,145 @@ 7.4 +/* 7.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/** 7.28 + * JDK-8044520: Nashorn cannot execute node.js's express module 7.29 + * 7.30 + * @test 7.31 + * @run 7.32 + */ 7.33 + 7.34 +function checkNullProto() { 7.35 + var obj = {}; 7.36 + obj.__proto__ = null; 7.37 + var proto = Object.getPrototypeOf(obj); 7.38 + if (typeof proto != 'object' || proto !== null) { 7.39 + fail("__proto__ can't be set to null!"); 7.40 + } 7.41 +} 7.42 + 7.43 +checkNullProto(); 7.44 + 7.45 +function checkSetProto(proto) { 7.46 + var obj = {}; 7.47 + obj.__proto__ = proto; 7.48 + if (Object.getPrototypeOf(obj) !== Object.prototype) { 7.49 + fail("obj.__proto__ set not ignored for " + proto); 7.50 + } 7.51 +} 7.52 + 7.53 +checkSetProto(undefined); 7.54 +checkSetProto(42); 7.55 +checkSetProto(false); 7.56 +checkSetProto("hello"); 7.57 + 7.58 +function checkLiteralSetProto(proto) { 7.59 + var obj = { __proto__: proto }; 7.60 + if (obj.__proto__ !== Object.prototype) { 7.61 + fail("object literal _proto__ set not ignored for " + proto); 7.62 + } 7.63 +} 7.64 + 7.65 +checkLiteralSetProto(undefined); 7.66 +checkLiteralSetProto(34); 7.67 +checkLiteralSetProto(true); 7.68 +checkLiteralSetProto("world"); 7.69 + 7.70 +function checkNullProtoFromLiteral() { 7.71 + var obj = { __proto__: null }; 7.72 + var proto = Object.getPrototypeOf(obj); 7.73 + if (typeof proto != 'object' || proto !== null) { 7.74 + fail("__proto__ can't be set to null!"); 7.75 + } 7.76 +} 7.77 + 7.78 +checkNullProtoFromLiteral(); 7.79 + 7.80 +function checkSetPrototypeOf(proto) { 7.81 + try { 7.82 + Object.setPrototypeOf({}, proto); 7.83 + fail("should have thrown error for " + proto); 7.84 + } catch (e) { 7.85 + if (! (e instanceof TypeError)) { 7.86 + fail("should have thrown TypeError, got " + e); 7.87 + } 7.88 + } 7.89 +} 7.90 + 7.91 +checkSetPrototypeOf(undefined); 7.92 +checkSetPrototypeOf(43); 7.93 +checkSetPrototypeOf(false); 7.94 +checkSetPrototypeOf("nashorn"); 7.95 + 7.96 +function checkNullSetPrototypeOf() { 7.97 + var obj = { }; 7.98 + Object.setPrototypeOf(obj, null); 7.99 + var proto = Object.getPrototypeOf(obj); 7.100 + if (typeof proto != 'object' || proto !== null) { 7.101 + fail("__proto__ can't be set to null!"); 7.102 + } 7.103 +} 7.104 + 7.105 +checkNullSetPrototypeOf(); 7.106 + 7.107 +var desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__"); 7.108 + 7.109 +function checkProtoGetterOnPrimitive(value) { 7.110 + // call __proto__ getter on primitive - check ToObject 7.111 + // is called on 'this' value as per draft spec 7.112 + if (desc.get.call(value) !== Object(value).__proto__) { 7.113 + fail("can't call __proto__ getter on " + value); 7.114 + } 7.115 +} 7.116 + 7.117 +checkProtoGetterOnPrimitive(32); 7.118 +checkProtoGetterOnPrimitive(false); 7.119 +checkProtoGetterOnPrimitive("great!"); 7.120 + 7.121 +function checkProtoSetterOnNonObjectThis(self) { 7.122 + try { 7.123 + desc.set.call(self); 7.124 + fail("should have thrown TypeError"); 7.125 + } catch (e) { 7.126 + if (! (e instanceof TypeError)) { 7.127 + fail("should throw TypeError on non-object self, got " +e); 7.128 + } 7.129 + } 7.130 +} 7.131 + 7.132 +checkProtoSetterOnNonObjectThis(undefined); 7.133 +checkProtoSetterOnNonObjectThis(null); 7.134 + 7.135 +function checkProtoSetterReturnValue(obj, p) { 7.136 + if (typeof desc.set.call(obj, p) != "undefined") { 7.137 + fail("__proto__ setter does not return undefined: " + obj + " " + p); 7.138 + } 7.139 +} 7.140 + 7.141 +// try non-object 'this'. setter is expected to return undefined. 7.142 +checkProtoSetterReturnValue(23); 7.143 +checkProtoSetterReturnValue(false); 7.144 +checkProtoSetterReturnValue("foo"); 7.145 + 7.146 +// set proper __proto__. Still return value is undefined. 7.147 +checkProtoSetterReturnValue({}, {}); 7.148 +checkProtoSetterReturnValue({}, null);