aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/lookup/Lookup.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/lookup/Lookup.java')
-rw-r--r--src/jdk/nashorn/internal/lookup/Lookup.java212
1 files changed, 212 insertions, 0 deletions
diff --git a/src/jdk/nashorn/internal/lookup/Lookup.java b/src/jdk/nashorn/internal/lookup/Lookup.java
new file mode 100644
index 00000000..a454527a
--- /dev/null
+++ b/src/jdk/nashorn/internal/lookup/Lookup.java
@@ -0,0 +1,212 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.lookup;
+
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.Property;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ * MethodHandle Lookup management for Nashorn.
+ */
+public final class Lookup {
+
+ /**
+ * A global singleton that points to the {@link MethodHandleFunctionality}. This is basically
+ * a collection of wrappers to the standard methods in {@link MethodHandle}, {@link MethodHandles} and
+ * {@link java.lang.invoke.MethodHandles.Lookup}, but instrumentation and debugging purposes we need
+ * intercept points.
+ * <p>
+ * All method handle operations in Nashorn should go through this field, not directly to the classes
+ * in {@code java.lang.invoke}
+ */
+ public static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
+
+ /** Method handle to the empty getter */
+ public static final MethodHandle EMPTY_GETTER = findOwnMH("emptyGetter", Object.class, Object.class);
+
+ /** Method handle to the empty setter */
+ public static final MethodHandle EMPTY_SETTER = findOwnMH("emptySetter", void.class, Object.class, Object.class);
+
+ /** Method handle to a getter that only throws type error */
+ public static final MethodHandle TYPE_ERROR_THROWER_GETTER = findOwnMH("typeErrorThrowerGetter", Object.class, Object.class);
+
+ /** Method handle to a setter that only throws type error */
+ public static final MethodHandle TYPE_ERROR_THROWER_SETTER = findOwnMH("typeErrorThrowerSetter", void.class, Object.class, Object.class);
+
+ /** Method handle to the most generic of getters, the one that returns an Object */
+ public static final MethodType GET_OBJECT_TYPE = MH.type(Object.class, Object.class);
+
+ /** Method handle to the most generic of setters, the one that takes an Object */
+ public static final MethodType SET_OBJECT_TYPE = MH.type(void.class, Object.class, Object.class);
+
+ private Lookup() {
+ }
+
+ /**
+ * Empty getter implementation. Nop
+ * @param self self reference
+ * @return undefined
+ */
+ public static Object emptyGetter(final Object self) {
+ return UNDEFINED;
+ }
+
+ /**
+ * Empty setter implementation. Nop
+ * @param self self reference
+ * @param value value (ignored)
+ */
+ public static void emptySetter(final Object self, final Object value) {
+ // do nothing!!
+ }
+
+ /**
+ * Return a method handle to the empty getter, with a different
+ * return type value. It will still be undefined cast to whatever
+ * return value property was specified
+ *
+ * @param type return value type
+ *
+ * @return undefined as return value type
+ */
+ public static MethodHandle emptyGetter(final Class<?> type) {
+ return filterReturnType(EMPTY_GETTER, type);
+ }
+
+ /**
+ * Getter function that always throws type error
+ *
+ * @param self self reference
+ * @return undefined (but throws error before return point)
+ */
+ public static Object typeErrorThrowerGetter(final Object self) {
+ throw typeError("strict.getter.setter.poison", ScriptRuntime.safeToString(self));
+ }
+
+ /**
+ * Getter function that always throws type error
+ *
+ * @param self self reference
+ * @param value (ignored)
+ */
+ public static void typeErrorThrowerSetter(final Object self, final Object value) {
+ throw typeError("strict.getter.setter.poison", ScriptRuntime.safeToString(self));
+ }
+
+ /**
+ * Create a new {@link Property}
+ *
+ * @param map property map
+ * @param key property key
+ * @param flags property flags
+ * @param propertyGetter getter for property if available, null otherwise
+ * @param propertySetter setter for property if available, null otherwise
+ *
+ * @return new property map, representing {@code PropertyMap} with the new property added to it
+ */
+ @SuppressWarnings("fallthrough")
+ public static PropertyMap newProperty(final PropertyMap map, final String key, final int flags, final MethodHandle propertyGetter, final MethodHandle propertySetter) {
+ MethodHandle getter = propertyGetter;
+ MethodHandle setter = propertySetter;
+
+ // TODO: this is temporary code. This code exists to support reflective
+ // field reader/writer handles generated by "unreflect" lookup.
+
+ switch (getter.type().parameterCount()) {
+ case 0:
+ // A static field reader, so drop the 'self' argument.
+ getter = MH.dropArguments(getter, 0, Object.class);
+ if (setter != null) {
+ setter = MH.dropArguments(setter, 0, Object.class);
+ }
+ // fall through
+ case 1:
+ // standard getter that accepts 'self'.
+ break;
+ default:
+ // Huh!! something wrong..
+ throw new IllegalArgumentException("getter/setter has wrong arguments");
+ }
+
+ return map.newProperty(key, flags, -1, getter, setter);
+ }
+
+ /**
+ * This method filters primitive return types using JavaScript semantics. For example,
+ * an (int) cast of a double in Java land is not the same thing as invoking toInt32 on it.
+ * If you are returning values to JavaScript that have to be of a specific type, this is
+ * the correct return value filter to use, as the explicitCastArguments just uses the
+ * Java boxing equivalents
+ *
+ * @param mh method handle for which to filter return value
+ * @param type new return type
+ * @return method handle for appropriate return type conversion
+ */
+ public static MethodHandle filterReturnType(final MethodHandle mh, final Class<?> type) {
+ final Class<?> retType = mh.type().returnType();
+
+ if (retType == int.class) {
+ //fallthru
+ } else if (retType == long.class) {
+ //fallthru
+ } else if (retType == double.class) {
+ if (type == int.class) {
+ return MH.filterReturnValue(mh, JSType.TO_INT32_D.methodHandle());
+ } else if (type == long.class) {
+ return MH.filterReturnValue(mh, JSType.TO_UINT32_D.methodHandle());
+ }
+ //fallthru
+ } else if (!retType.isPrimitive()) {
+ if (type == int.class) {
+ return MH.filterReturnValue(mh, JSType.TO_INT32.methodHandle());
+ } else if (type == long.class) {
+ return MH.filterReturnValue(mh, JSType.TO_UINT32.methodHandle());
+ } else if (type == double.class) {
+ return MH.filterReturnValue(mh, JSType.TO_NUMBER.methodHandle());
+ } else if (!type.isPrimitive()) {
+ return mh;
+ }
+
+ assert false : "unsupported Lookup.filterReturnType type " + retType + " -> " + type;
+ }
+
+ //use a standard cast - we don't need to check JavaScript special cases
+ return MH.explicitCastArguments(mh, mh.type().changeReturnType(type));
+ }
+
+ private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
+ return MH.findStatic(MethodHandles.lookup(), Lookup.class, name, MH.type(rtype, types));
+ }
+
+}