8027037: Make ScriptObjectMirror conversions work for any JSObject
authorattila
Tue, 22 Oct 2013 17:52:37 +0200
changeset 21450 419e5d51f319
parent 21449 72d51df5ed85
child 21451 ea5d24a4fb35
8027037: Make ScriptObjectMirror conversions work for any JSObject Reviewed-by: jlaskey, lagergren, sundar
nashorn/src/jdk/nashorn/api/scripting/JSObject.java
nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
nashorn/src/jdk/nashorn/internal/runtime/JSType.java
nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
--- a/nashorn/src/jdk/nashorn/api/scripting/JSObject.java	Tue Oct 22 16:43:27 2013 +0200
+++ b/nashorn/src/jdk/nashorn/api/scripting/JSObject.java	Tue Oct 22 17:52:37 2013 +0200
@@ -234,4 +234,13 @@
     public boolean isArray() {
         return false;
     }
+
+    /**
+     * Returns this object's numeric value.
+     *
+     * @return this object's numeric value.
+     */
+    public double toNumber() {
+        return Double.NaN;
+    }
 }
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Tue Oct 22 16:43:27 2013 +0200
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Tue Oct 22 17:52:37 2013 +0200
@@ -707,39 +707,7 @@
         }
     }
 
-    /**
-     * JavaScript compliant Object to int32 conversion
-     * See ECMA 9.5 ToInt32
-     *
-     * @return this object's int32 representation
-     */
-    public int toInt32() {
-        return inGlobal(new Callable<Integer>() {
-            @Override public Integer call() {
-                return JSType.toInt32(sobj);
-            }
-        });
-    }
-
-    /**
-     * JavaScript compliant Object to int64 conversion
-     *
-     * @return this object's int64 representation
-     */
-    public long toInt64() {
-        return inGlobal(new Callable<Long>() {
-            @Override public Long call() {
-                return JSType.toInt64(sobj);
-            }
-        });
-    }
-
-    /**
-     * JavaScript compliant conversion of Object to number
-     * See ECMA 9.3 ToNumber
-     *
-     * @return this object's number representation
-     */
+    @Override
     public double toNumber() {
         return inGlobal(new Callable<Double>() {
             @Override public Double call() {
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Tue Oct 22 16:43:27 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Tue Oct 22 17:52:37 2013 +0200
@@ -631,17 +631,6 @@
     }
 
     /**
-     * JavaScript compliant Object to int32 conversion
-     * See ECMA 9.5 ToInt32
-     *
-     * @param obj an object
-     * @return an int32
-     */
-    public static int toInt32(final ScriptObject obj) {
-        return toInt32(toNumber(obj));
-    }
-
-    /**
      * JavaScript compliant long to int32 conversion
      *
      * @param num a long
@@ -672,16 +661,6 @@
     }
 
     /**
-     * JavaScript compliant Object to int64 conversion
-     *
-     * @param obj an object
-     * @return an int64
-     */
-    public static long toInt64(final ScriptObject obj) {
-        return toInt64(toNumber(obj));
-    }
-
-    /**
      * JavaScript compliant number to int64 conversion
      *
      * @param num a number
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Tue Oct 22 16:43:27 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Tue Oct 22 17:52:37 2013 +0200
@@ -38,7 +38,6 @@
 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.nashorn.api.scripting.JSObject;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
 import jdk.nashorn.internal.runtime.JSType;
@@ -81,16 +80,17 @@
 
     @Override
     public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType) throws Exception {
-        if(!sourceType.isAssignableFrom(ScriptObjectMirror.class)) {
+        final boolean sourceIsAlwaysJSObject = JSObject.class.isAssignableFrom(sourceType);
+        if(!sourceIsAlwaysJSObject && !sourceType.isAssignableFrom(JSObject.class)) {
             return null;
         }
 
-        final MethodHandle converter = MIRROR_CONVERTERS.get(targetType);
+        final MethodHandle converter = CONVERTERS.get(targetType);
         if(converter == null) {
             return null;
         }
 
-        return new GuardedInvocation(converter, sourceType == ScriptObjectMirror.class ? null : IS_MIRROR_GUARD).asType(MethodType.methodType(targetType, sourceType));
+        return new GuardedInvocation(converter, sourceIsAlwaysJSObject ? null : IS_JSOBJECT_GUARD).asType(MethodType.methodType(targetType, sourceType));
     }
 
 
@@ -157,11 +157,6 @@
     }
 
     @SuppressWarnings("unused")
-    private static boolean isScriptObjectMirror(final Object self) {
-        return self instanceof ScriptObjectMirror;
-    }
-
-    @SuppressWarnings("unused")
     private static Object get(final Object jsobj, final Object key) {
         if (key instanceof Integer) {
             return ((JSObject)jsobj).getSlot((Integer)key);
@@ -187,6 +182,25 @@
         }
     }
 
+    @SuppressWarnings("unused")
+    private static int toInt32(final JSObject obj) {
+        return JSType.toInt32(toNumber(obj));
+    }
+
+    @SuppressWarnings("unused")
+    private static long toInt64(final JSObject obj) {
+        return JSType.toInt64(toNumber(obj));
+    }
+
+    private static double toNumber(final JSObject obj) {
+        return obj == null ? 0 : obj.toNumber();
+    }
+
+    @SuppressWarnings("unused")
+    private static boolean toBoolean(final JSObject obj) {
+        return obj != null;
+    }
+
     private static int getIndex(final Number n) {
         final double value = n.doubleValue();
         return JSType.isRepresentableAsInt(value) ? (int)value : -1;
@@ -196,7 +210,6 @@
 
     // method handles of the current class
     private static final MethodHandle IS_JSOBJECT_GUARD  = findOwnMH("isJSObject", boolean.class, Object.class);
-    private static final MethodHandle IS_MIRROR_GUARD    = findOwnMH("isScriptObjectMirror", boolean.class, Object.class);
     private static final MethodHandle JSOBJECTLINKER_GET = findOwnMH("get", Object.class, Object.class, Object.class);
     private static final MethodHandle JSOBJECTLINKER_PUT = findOwnMH("put", Void.TYPE, Object.class, Object.class, Object.class);
 
@@ -207,12 +220,12 @@
     private static final MethodHandle JSOBJECT_CALL       = findJSObjectMH("call", Object.class, Object.class, Object[].class);
     private static final MethodHandle JSOBJECT_NEW        = findJSObjectMH("newObject", Object.class, Object[].class);
 
-    private static final Map<Class<?>, MethodHandle> MIRROR_CONVERTERS = new HashMap<>();
+    private static final Map<Class<?>, MethodHandle> CONVERTERS = new HashMap<>();
     static {
-        MIRROR_CONVERTERS.put(boolean.class, MH.dropArguments(MH.constant(boolean.class, Boolean.TRUE), 0, Object.class));
-        MIRROR_CONVERTERS.put(int.class, findMirrorMH("toInt32", int.class));
-        MIRROR_CONVERTERS.put(long.class, findMirrorMH("toInt64", long.class));
-        MIRROR_CONVERTERS.put(double.class, findMirrorMH("toNumber", double.class));
+        CONVERTERS.put(boolean.class, findOwnMH("toBoolean", boolean.class, JSObject.class));
+        CONVERTERS.put(int.class, findOwnMH("toInt32", int.class, JSObject.class));
+        CONVERTERS.put(long.class, findOwnMH("toInt64", long.class, JSObject.class));
+        CONVERTERS.put(double.class, findOwnMH("toNumber", double.class, JSObject.class));
     }
 
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
@@ -223,10 +236,6 @@
         return findMH(name, JSObject.class, rtype, types);
     }
 
-    private static MethodHandle findMirrorMH(final String name, final Class<?> rtype, final Class<?>... types) {
-        return findMH(name, ScriptObjectMirror.class, rtype, types);
-    }
-
     private static MethodHandle findMH(final String name, final Class<?> target, final Class<?> rtype, final Class<?>... types) {
         final MethodType mt  = MH.type(rtype, types);
         try {