Showing the changes to java/pkg/java/lang/invoke/MethodHandleNatives.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,403 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 5 | * This code is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 only, as | ||
| 7 | * published by the Free Software Foundation. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | |||
| 26 | package java.lang.invoke; | ||
| 27 | |||
| 28 | import java.lang.invoke.MethodHandles.Lookup; | ||
| 29 | import java.lang.reflect.AccessibleObject; | ||
| 30 | import java.lang.reflect.Field; | ||
| 31 | import static java.lang.invoke.MethodHandleNatives.Constants.*; | ||
| 32 | import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * The JVM interface for the method handles package is all here. | ||
| 36 | * This is an interface internal and private to an implemetantion of JSR 292. | ||
| 37 | * <em>This class is not part of the JSR 292 standard.</em> | ||
| 38 | * @author jrose | ||
| 39 | */ | ||
| 40 | class MethodHandleNatives { | ||
| 41 | |||
| 42 | private MethodHandleNatives() { } // static only | ||
| 43 | |||
| 44 | /// MethodName support | ||
| 45 | |||
| 46 | static native void init(MemberName self, Object ref); | ||
| 47 | static native void expand(MemberName self); | ||
| 48 | static native void resolve(MemberName self, Class<?> caller); | ||
| 49 | static native int getMembers(Class<?> defc, String matchName, String matchSig, | ||
| 50 | int matchFlags, Class<?> caller, int skip, MemberName[] results); | ||
| 51 | |||
| 52 | /// MethodHandle support | ||
| 53 | |||
| 54 | /** Initialize the method handle to adapt the call. */ | ||
| 55 | static native void init(AdapterMethodHandle self, MethodHandle target, int argnum); | ||
| 56 | /** Initialize the method handle to call the correct method, directly. */ | ||
| 57 | static native void init(BoundMethodHandle self, Object target, int argnum); | ||
| 58 | /** Initialize the method handle to call as if by an invoke* instruction. */ | ||
| 59 | static native void init(DirectMethodHandle self, Object ref, boolean doDispatch, Class<?> caller); | ||
| 60 | |||
| 61 | /** Initialize a method type, once per form. */ | ||
| 62 | static native void init(MethodType self); | ||
| 63 | |||
| 64 | /** Tell the JVM about a class's bootstrap method. */ | ||
| 65 | static native void registerBootstrap(Class<?> caller, MethodHandle bootstrapMethod); | ||
| 66 | |||
| 67 | /** Ask the JVM about a class's bootstrap method. */ | ||
| 68 | static native MethodHandle getBootstrap(Class<?> caller); | ||
| 69 | |||
| 70 | /** Tell the JVM that we need to change the target of an invokedynamic. */ | ||
| 71 | static native void setCallSiteTarget(CallSite site, MethodHandle target); | ||
| 72 | |||
| 73 | /** Fetch the vmtarget field. | ||
| 74 | * It will be sanitized as necessary to avoid exposing non-Java references. | ||
| 75 | * This routine is for debugging and reflection. | ||
| 76 | */ | ||
| 77 | static native Object getTarget(MethodHandle self, int format); | ||
| 78 | |||
| 79 | /** Fetch the name of the handled method, if available. | ||
| 80 | * This routine is for debugging and reflection. | ||
| 81 | */ | ||
| 82 | static MemberName getMethodName(MethodHandle self) { | ||
| 83 | return (MemberName) getTarget(self, ETF_METHOD_NAME); | ||
| 84 | } | ||
| 85 | |||
| 86 | /** Fetch the reflective version of the handled method, if available. | ||
| 87 | */ | ||
| 88 | static AccessibleObject getTargetMethod(MethodHandle self) { | ||
| 89 | return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD); | ||
| 90 | } | ||
| 91 | |||
| 92 | /** Fetch the target of this method handle. | ||
| 93 | * If it directly targets a method, return a MemberName for the method. | ||
| 94 | * If it is chained to another method handle, return that handle. | ||
| 95 | */ | ||
| 96 | static Object getTargetInfo(MethodHandle self) { | ||
| 97 | return getTarget(self, ETF_HANDLE_OR_METHOD_NAME); | ||
| 98 | } | ||
| 99 | |||
| 100 | static Object[] makeTarget(Class<?> defc, String name, String sig, int mods, Class<?> refc) { | ||
| 101 | return new Object[] { defc, name, sig, mods, refc }; | ||
| 102 | } | ||
| 103 | |||
| 104 | /** Fetch MH-related JVM parameter. | ||
| 105 | * which=0 retrieves MethodHandlePushLimit | ||
| 106 | * which=1 retrieves stack slot push size (in address units) | ||
| 107 | */ | ||
| 108 | static native int getConstant(int which); | ||
| 109 | |||
| 110 | /** Java copy of MethodHandlePushLimit in range 2..255. */ | ||
| 111 | static final int JVM_PUSH_LIMIT; | ||
| 112 | /** JVM stack motion (in words) after one slot is pushed, usually -1. | ||
| 113 | */ | ||
| 114 | static final int JVM_STACK_MOVE_UNIT; | ||
| 115 | |||
| 116 | /** Which conv-ops are implemented by the JVM? */ | ||
| 117 | static final int CONV_OP_IMPLEMENTED_MASK; | ||
| 118 | /** Derived mode flag. Only false on some old JVM implementations. */ | ||
| 119 | static final boolean HAVE_RICOCHET_FRAMES; | ||
| 120 | |||
| 121 | static final int OP_ROT_ARGS_DOWN_LIMIT_BIAS; | ||
| 122 | |||
| 123 | private static native void registerNatives(); | ||
| 124 | static { | ||
| 125 | registerNatives(); | ||
| 126 | int k; | ||
| 127 | JVM_PUSH_LIMIT = getConstant(Constants.GC_JVM_PUSH_LIMIT); | ||
| 128 | JVM_STACK_MOVE_UNIT = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT); | ||
| 129 | k = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK); | ||
| 130 | CONV_OP_IMPLEMENTED_MASK = (k != 0) ? k : DEFAULT_CONV_OP_IMPLEMENTED_MASK; | ||
| 131 | k = getConstant(Constants.GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS); | ||
| 132 | OP_ROT_ARGS_DOWN_LIMIT_BIAS = (k != 0) ? (byte)k : -1; | ||
| 133 | HAVE_RICOCHET_FRAMES = (CONV_OP_IMPLEMENTED_MASK & (1<<OP_COLLECT_ARGS)) != 0; | ||
| 134 | //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init"); | ||
| 135 | } | ||
| 136 | |||
| 137 | // All compile-time constants go here. | ||
| 138 | // There is an opportunity to check them against the JVM's idea of them. | ||
| 139 | static class Constants { | ||
| 140 | Constants() { } // static only | ||
| 141 | // MethodHandleImpl | ||
| 142 | static final int // for getConstant | ||
| 143 | GC_JVM_PUSH_LIMIT = 0, | ||
| 144 | GC_JVM_STACK_MOVE_UNIT = 1, | ||
| 145 | GC_CONV_OP_IMPLEMENTED_MASK = 2, | ||
| 146 | GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS = 3; | ||
| 147 | static final int | ||
| 148 | ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) | ||
| 149 | ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self) | ||
| 150 | ETF_METHOD_NAME = 2, // ultimate method as MemberName | ||
| 151 | ETF_REFLECT_METHOD = 3; // ultimate method as java.lang.reflect object (sans refClass) | ||
| 152 | |||
| 153 | // MemberName | ||
| 154 | // The JVM uses values of -2 and above for vtable indexes. | ||
| 155 | // Field values are simple positive offsets. | ||
| 156 | // Ref: src/share/vm/oops/methodOop.hpp | ||
| 157 | // This value is negative enough to avoid such numbers, | ||
| 158 | // but not too negative. | ||
| 159 | static final int | ||
| 160 | MN_IS_METHOD = 0x00010000, // method (not constructor) | ||
| 161 | MN_IS_CONSTRUCTOR = 0x00020000, // constructor | ||
| 162 | MN_IS_FIELD = 0x00040000, // field | ||
| 163 | MN_IS_TYPE = 0x00080000, // nested type | ||
| 164 | MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers | ||
| 165 | MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers | ||
| 166 | VM_INDEX_UNINITIALIZED = -99; | ||
| 167 | |||
| 168 | // BoundMethodHandle | ||
| 169 | /** Constants for decoding the vmargslot field, which contains 2 values. */ | ||
| 170 | static final int | ||
| 171 | ARG_SLOT_PUSH_SHIFT = 16, | ||
| 172 | ARG_SLOT_MASK = (1<<ARG_SLOT_PUSH_SHIFT)-1; | ||
| 173 | |||
| 174 | // AdapterMethodHandle | ||
| 175 | /** Conversions recognized by the JVM. | ||
| 176 | * They must align with the constants in java.lang.invoke.AdapterMethodHandle, | ||
| 177 | * in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp. | ||
| 178 | */ | ||
| 179 | static final int | ||
| 180 | OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype | ||
| 181 | OP_RETYPE_RAW = 0x1, // straight retype, trusted (void->int, Object->T) | ||
| 182 | OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument | ||
| 183 | OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another | ||
| 184 | OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive | ||
| 185 | OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper | ||
| 186 | OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg) | ||
| 187 | OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg) | ||
| 188 | OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS) | ||
| 189 | OP_DROP_ARGS = 0x9, // remove one or more argument slots | ||
| 190 | OP_COLLECT_ARGS = 0xA, // combine arguments using an auxiliary function | ||
| 191 | OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size) | ||
| 192 | OP_FOLD_ARGS = 0xC, // combine but do not remove arguments; prepend result | ||
| 193 | //OP_UNUSED_13 = 0xD, // unused code, perhaps for reified argument lists | ||
| 194 | CONV_OP_LIMIT = 0xE; // limit of CONV_OP enumeration | ||
| 195 | /** Shift and mask values for decoding the AMH.conversion field. | ||
| 196 | * These numbers are shared with the JVM for creating AMHs. | ||
| 197 | */ | ||
| 198 | static final int | ||
| 199 | CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field | ||
| 200 | CONV_TYPE_MASK = 0x0F, // fits T_ADDRESS and below | ||
| 201 | CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use | ||
| 202 | CONV_VMINFO_SHIFT = 0, // position of bits in CONV_VMINFO_MASK | ||
| 203 | CONV_OP_SHIFT = 8, // position of bits in CONV_OP_MASK | ||
| 204 | CONV_DEST_TYPE_SHIFT = 12, // byte 2 has the adapter BasicType (if needed) | ||
| 205 | CONV_SRC_TYPE_SHIFT = 16, // byte 2 has the source BasicType (if needed) | ||
| 206 | CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change | ||
| 207 | CONV_STACK_MOVE_MASK = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1; | ||
| 208 | |||
| 209 | /** Which conv-ops are implemented by the JVM? */ | ||
| 210 | static final int DEFAULT_CONV_OP_IMPLEMENTED_MASK = | ||
| 211 | // Value to use if the corresponding JVM query fails. | ||
| 212 | ((1<<OP_RETYPE_ONLY) | ||
| 213 | |(1<<OP_RETYPE_RAW) | ||
| 214 | |(1<<OP_CHECK_CAST) | ||
| 215 | |(1<<OP_PRIM_TO_PRIM) | ||
| 216 | |(1<<OP_REF_TO_PRIM) | ||
| 217 | |(1<<OP_SWAP_ARGS) | ||
| 218 | |(1<<OP_ROT_ARGS) | ||
| 219 | |(1<<OP_DUP_ARGS) | ||
| 220 | |(1<<OP_DROP_ARGS) | ||
| 221 | //|(1<<OP_SPREAD_ARGS) | ||
| 222 | ); | ||
| 223 | |||
| 224 | /** | ||
| 225 | * Basic types as encoded in the JVM. These code values are not | ||
| 226 | * intended for use outside this class. They are used as part of | ||
| 227 | * a private interface between the JVM and this class. | ||
| 228 | */ | ||
| 229 | static final int | ||
| 230 | T_BOOLEAN = 4, | ||
| 231 | T_CHAR = 5, | ||
| 232 | T_FLOAT = 6, | ||
| 233 | T_DOUBLE = 7, | ||
| 234 | T_BYTE = 8, | ||
| 235 | T_SHORT = 9, | ||
| 236 | T_INT = 10, | ||
| 237 | T_LONG = 11, | ||
| 238 | T_OBJECT = 12, | ||
| 239 | //T_ARRAY = 13 | ||
| 240 | T_VOID = 14, | ||
| 241 | //T_ADDRESS = 15 | ||
| 242 | T_ILLEGAL = 99; | ||
| 243 | |||
| 244 | /** | ||
| 245 | * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries. | ||
| 246 | */ | ||
| 247 | static final int | ||
| 248 | REF_getField = 1, | ||
| 249 | REF_getStatic = 2, | ||
| 250 | REF_putField = 3, | ||
| 251 | REF_putStatic = 4, | ||
| 252 | REF_invokeVirtual = 5, | ||
| 253 | REF_invokeStatic = 6, | ||
| 254 | REF_invokeSpecial = 7, | ||
| 255 | REF_newInvokeSpecial = 8, | ||
| 256 | REF_invokeInterface = 9; | ||
| 257 | } | ||
| 258 | |||
| 259 | private static native int getNamedCon(int which, Object[] name); | ||
| 260 | static boolean verifyConstants() { | ||
| 261 | Object[] box = { null }; | ||
| 262 | for (int i = 0; ; i++) { | ||
| 263 | box[0] = null; | ||
| 264 | int vmval = getNamedCon(i, box); | ||
| 265 | if (box[0] == null) break; | ||
| 266 | String name = (String) box[0]; | ||
| 267 | try { | ||
| 268 | Field con = Constants.class.getDeclaredField(name); | ||
| 269 | int jval = con.getInt(null); | ||
| 270 | if (jval == vmval) continue; | ||
| 271 | String err = (name+": JVM has "+vmval+" while Java has "+jval); | ||
| 272 | if (name.equals("CONV_OP_LIMIT")) { | ||
| 273 | System.err.println("warning: "+err); | ||
| 274 | continue; | ||
| 275 | } | ||
| 276 | throw new InternalError(err); | ||
| 277 | } catch (Exception ex) { | ||
| 278 | if (ex instanceof NoSuchFieldException) { | ||
| 279 | String err = (name+": JVM has "+vmval+" which Java does not define"); | ||
| 280 | // ignore exotic ops the JVM cares about; we just wont issue them | ||
| 281 | if (name.startsWith("OP_") || name.startsWith("GC_")) { | ||
| 282 | System.err.println("warning: "+err); | ||
| 283 | continue; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | throw new InternalError(name+": access failed, got "+ex); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | return true; | ||
| 290 | } | ||
| 291 | static { | ||
| 292 | assert(verifyConstants()); | ||
| 293 | } | ||
| 294 | |||
| 295 | // Up-calls from the JVM. | ||
| 296 | // These must NOT be public. | ||
| 297 | |||
| 298 | /** | ||
| 299 | * The JVM is linking an invokedynamic instruction. Create a reified call site for it. | ||
| 300 | */ | ||
| 301 | static CallSite makeDynamicCallSite(MethodHandle bootstrapMethod, | ||
| 302 | String name, MethodType type, | ||
| 303 | Object info, | ||
| 304 | MemberName callerMethod, int callerBCI) { | ||
| 305 | return CallSite.makeSite(bootstrapMethod, name, type, info, callerMethod, callerBCI); | ||
| 306 | } | ||
| 307 | |||
| 308 | /** | ||
| 309 | * Called by the JVM to check the length of a spread array. | ||
| 310 | */ | ||
| 311 | static void checkSpreadArgument(Object av, int n) { | ||
| 312 | MethodHandleStatics.checkSpreadArgument(av, n); | ||
| 313 | } | ||
| 314 | |||
| 315 | /** | ||
| 316 | * The JVM wants a pointer to a MethodType. Oblige it by finding or creating one. | ||
| 317 | */ | ||
| 318 | static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) { | ||
| 319 | return MethodType.makeImpl(rtype, ptypes, true); | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * The JVM wants to use a MethodType with inexact invoke. Give the runtime fair warning. | ||
| 324 | */ | ||
| 325 | static void notifyGenericMethodType(MethodType type) { | ||
| 326 | type.form().notifyGenericMethodType(); | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * The JVM wants to raise an exception. Here's the path. | ||
| 331 | */ | ||
| 332 | static void raiseException(int code, Object actual, Object required) { | ||
| 333 | String message = null; | ||
| 334 | switch (code) { | ||
| 335 | case 190: // arraylength | ||
| 336 | try { | ||
| 337 | String reqLength = ""; | ||
| 338 | if (required instanceof AdapterMethodHandle) { | ||
| 339 | int conv = ((AdapterMethodHandle)required).getConversion(); | ||
| 340 | int spChange = AdapterMethodHandle.extractStackMove(conv); | ||
| 341 | reqLength = " of length "+(spChange+1); | ||
| 342 | } | ||
| 343 | int actualLength = actual == null ? 0 : java.lang.reflect.Array.getLength(actual); | ||
| 344 | message = "required array"+reqLength+", but encountered wrong length "+actualLength; | ||
| 345 | break; | ||
| 346 | } catch (IllegalArgumentException ex) { | ||
| 347 | } | ||
| 348 | required = Object[].class; // should have been an array | ||
| 349 | code = 192; // checkcast | ||
| 350 | break; | ||
| 351 | case 191: // athrow | ||
| 352 | // JVM is asking us to wrap an exception which happened during resolving | ||
| 353 | if (required == BootstrapMethodError.class) { | ||
| 354 | throw new BootstrapMethodError((Throwable) actual); | ||
| 355 | } | ||
| 356 | break; | ||
| 357 | } | ||
| 358 | // disregard the identity of the actual object, if it is not a class: | ||
| 359 | if (message == null) { | ||
| 360 | if (!(actual instanceof Class) && !(actual instanceof MethodType)) | ||
| 361 | actual = actual.getClass(); | ||
| 362 | if (actual != null) | ||
| 363 | message = "required "+required+" but encountered "+actual; | ||
| 364 | else | ||
| 365 | message = "required "+required; | ||
| 366 | } | ||
| 367 | switch (code) { | ||
| 368 | case 190: // arraylength | ||
| 369 | throw new ArrayIndexOutOfBoundsException(message); | ||
| 370 | case 50: //_aaload | ||
| 371 | throw new ClassCastException(message); | ||
| 372 | case 192: // checkcast | ||
| 373 | throw new ClassCastException(message); | ||
| 374 | default: | ||
| 375 | throw new InternalError("unexpected code "+code+": "+message); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | /** | ||
| 380 | * The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help. | ||
| 381 | * It will make an up-call to this method. (Do not change the name or signature.) | ||
| 382 | */ | ||
| 383 | static MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind, | ||
| 384 | Class<?> defc, String name, Object type) { | ||
| 385 | try { | ||
| 386 | Lookup lookup = IMPL_LOOKUP.in(callerClass); | ||
| 387 | return lookup.linkMethodHandleConstant(refKind, defc, name, type); | ||
| 388 | } catch (ReflectiveOperationException ex) { | ||
| 389 | Error err = new IncompatibleClassChangeError(); | ||
| 390 | err.initCause(ex); | ||
| 391 | throw err; | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | /** | ||
| 396 | * This assertion marks code which was written before ricochet frames were implemented. | ||
| 397 | * Such code will go away when the ports catch up. | ||
| 398 | */ | ||
| 399 | static boolean workaroundWithoutRicochetFrames() { | ||
| 400 | assert(!HAVE_RICOCHET_FRAMES) : "this code should not be executed if `-XX:+UseRicochetFrames is enabled"; | ||
| 401 | return true; | ||
| 402 | } | ||
| 403 | } | ||