1.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/TypeConvertingMethodAdapter.java Sun Aug 10 06:21:50 2014 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,302 +0,0 @@
1.4 -/*
1.5 - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
1.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 - *
1.8 - * This code is free software; you can redistribute it and/or modify it
1.9 - * under the terms of the GNU General Public License version 2 only, as
1.10 - * published by the Free Software Foundation. Oracle designates this
1.11 - * particular file as subject to the "Classpath" exception as provided
1.12 - * by Oracle in the LICENSE file that accompanied this code.
1.13 - *
1.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 - * version 2 for more details (a copy is included in the LICENSE file that
1.18 - * accompanied this code).
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License version
1.21 - * 2 along with this work; if not, write to the Free Software Foundation,
1.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 - *
1.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 - * or visit www.oracle.com if you need additional information or have any
1.26 - * questions.
1.27 - */
1.28 -
1.29 -package java.lang.invoke;
1.30 -
1.31 -import jdk.internal.org.objectweb.asm.MethodVisitor;
1.32 -import jdk.internal.org.objectweb.asm.Opcodes;
1.33 -import jdk.internal.org.objectweb.asm.Type;
1.34 -import sun.invoke.util.BytecodeDescriptor;
1.35 -import sun.invoke.util.Wrapper;
1.36 -import static sun.invoke.util.Wrapper.*;
1.37 -
1.38 -class TypeConvertingMethodAdapter extends MethodVisitor {
1.39 -
1.40 - TypeConvertingMethodAdapter(MethodVisitor mv) {
1.41 - super(Opcodes.ASM5, mv);
1.42 - }
1.43 -
1.44 - private static final int NUM_WRAPPERS = Wrapper.values().length;
1.45 -
1.46 - private static final String NAME_OBJECT = "java/lang/Object";
1.47 - private static final String WRAPPER_PREFIX = "Ljava/lang/";
1.48 -
1.49 - // Same for all primitives; name of the boxing method
1.50 - private static final String NAME_BOX_METHOD = "valueOf";
1.51 -
1.52 - // Table of opcodes for widening primitive conversions; NOP = no conversion
1.53 - private static final int[][] wideningOpcodes = new int[NUM_WRAPPERS][NUM_WRAPPERS];
1.54 -
1.55 - private static final Wrapper[] FROM_WRAPPER_NAME = new Wrapper[16];
1.56 -
1.57 - // Table of wrappers for primitives, indexed by ASM type sorts
1.58 - private static final Wrapper[] FROM_TYPE_SORT = new Wrapper[16];
1.59 -
1.60 - static {
1.61 - for (Wrapper w : Wrapper.values()) {
1.62 - if (w.basicTypeChar() != 'L') {
1.63 - int wi = hashWrapperName(w.wrapperSimpleName());
1.64 - assert (FROM_WRAPPER_NAME[wi] == null);
1.65 - FROM_WRAPPER_NAME[wi] = w;
1.66 - }
1.67 - }
1.68 -
1.69 - for (int i = 0; i < NUM_WRAPPERS; i++) {
1.70 - for (int j = 0; j < NUM_WRAPPERS; j++) {
1.71 - wideningOpcodes[i][j] = Opcodes.NOP;
1.72 - }
1.73 - }
1.74 -
1.75 - initWidening(LONG, Opcodes.I2L, BYTE, SHORT, INT, CHAR);
1.76 - initWidening(LONG, Opcodes.F2L, FLOAT);
1.77 - initWidening(FLOAT, Opcodes.I2F, BYTE, SHORT, INT, CHAR);
1.78 - initWidening(FLOAT, Opcodes.L2F, LONG);
1.79 - initWidening(DOUBLE, Opcodes.I2D, BYTE, SHORT, INT, CHAR);
1.80 - initWidening(DOUBLE, Opcodes.F2D, FLOAT);
1.81 - initWidening(DOUBLE, Opcodes.L2D, LONG);
1.82 -
1.83 - FROM_TYPE_SORT[Type.BYTE] = Wrapper.BYTE;
1.84 - FROM_TYPE_SORT[Type.SHORT] = Wrapper.SHORT;
1.85 - FROM_TYPE_SORT[Type.INT] = Wrapper.INT;
1.86 - FROM_TYPE_SORT[Type.LONG] = Wrapper.LONG;
1.87 - FROM_TYPE_SORT[Type.CHAR] = Wrapper.CHAR;
1.88 - FROM_TYPE_SORT[Type.FLOAT] = Wrapper.FLOAT;
1.89 - FROM_TYPE_SORT[Type.DOUBLE] = Wrapper.DOUBLE;
1.90 - FROM_TYPE_SORT[Type.BOOLEAN] = Wrapper.BOOLEAN;
1.91 - }
1.92 -
1.93 - private static void initWidening(Wrapper to, int opcode, Wrapper... from) {
1.94 - for (Wrapper f : from) {
1.95 - wideningOpcodes[f.ordinal()][to.ordinal()] = opcode;
1.96 - }
1.97 - }
1.98 -
1.99 - /**
1.100 - * Class name to Wrapper hash, derived from Wrapper.hashWrap()
1.101 - * @param xn
1.102 - * @return The hash code 0-15
1.103 - */
1.104 - private static int hashWrapperName(String xn) {
1.105 - if (xn.length() < 3) {
1.106 - return 0;
1.107 - }
1.108 - return (3 * xn.charAt(1) + xn.charAt(2)) % 16;
1.109 - }
1.110 -
1.111 - private Wrapper wrapperOrNullFromDescriptor(String desc) {
1.112 - if (!desc.startsWith(WRAPPER_PREFIX)) {
1.113 - // Not a class type (array or method), so not a boxed type
1.114 - // or not in the right package
1.115 - return null;
1.116 - }
1.117 - // Pare it down to the simple class name
1.118 - String cname = desc.substring(WRAPPER_PREFIX.length(), desc.length() - 1);
1.119 - // Hash to a Wrapper
1.120 - Wrapper w = FROM_WRAPPER_NAME[hashWrapperName(cname)];
1.121 - if (w == null || w.wrapperSimpleName().equals(cname)) {
1.122 - return w;
1.123 - } else {
1.124 - return null;
1.125 - }
1.126 - }
1.127 -
1.128 - private static String wrapperName(Wrapper w) {
1.129 - return "java/lang/" + w.wrapperSimpleName();
1.130 - }
1.131 -
1.132 - private static String unboxMethod(Wrapper w) {
1.133 - return w.primitiveSimpleName() + "Value";
1.134 - }
1.135 -
1.136 - private static String boxingDescriptor(Wrapper w) {
1.137 - return String.format("(%s)L%s;", w.basicTypeChar(), wrapperName(w));
1.138 - }
1.139 -
1.140 - private static String unboxingDescriptor(Wrapper w) {
1.141 - return "()" + w.basicTypeChar();
1.142 - }
1.143 -
1.144 - void boxIfTypePrimitive(Type t) {
1.145 - Wrapper w = FROM_TYPE_SORT[t.getSort()];
1.146 - if (w != null) {
1.147 - box(w);
1.148 - }
1.149 - }
1.150 -
1.151 - void widen(Wrapper ws, Wrapper wt) {
1.152 - if (ws != wt) {
1.153 - int opcode = wideningOpcodes[ws.ordinal()][wt.ordinal()];
1.154 - if (opcode != Opcodes.NOP) {
1.155 - visitInsn(opcode);
1.156 - }
1.157 - }
1.158 - }
1.159 -
1.160 - void box(Wrapper w) {
1.161 - visitMethodInsn(Opcodes.INVOKESTATIC,
1.162 - wrapperName(w),
1.163 - NAME_BOX_METHOD,
1.164 - boxingDescriptor(w));
1.165 - }
1.166 -
1.167 - /**
1.168 - * Convert types by unboxing. The source type is known to be a primitive wrapper.
1.169 - * @param ws A primitive wrapper corresponding to wrapped reference source type
1.170 - * @param wt A primitive wrapper being converted to
1.171 - */
1.172 - void unbox(String sname, Wrapper wt) {
1.173 - visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1.174 - sname,
1.175 - unboxMethod(wt),
1.176 - unboxingDescriptor(wt));
1.177 - }
1.178 -
1.179 - private String descriptorToName(String desc) {
1.180 - int last = desc.length() - 1;
1.181 - if (desc.charAt(0) == 'L' && desc.charAt(last) == ';') {
1.182 - // In descriptor form
1.183 - return desc.substring(1, last);
1.184 - } else {
1.185 - // Already in internal name form
1.186 - return desc;
1.187 - }
1.188 - }
1.189 -
1.190 - void cast(String ds, String dt) {
1.191 - String ns = descriptorToName(ds);
1.192 - String nt = descriptorToName(dt);
1.193 - if (!nt.equals(ns) && !nt.equals(NAME_OBJECT)) {
1.194 - visitTypeInsn(Opcodes.CHECKCAST, nt);
1.195 - }
1.196 - }
1.197 -
1.198 - private boolean isPrimitive(Wrapper w) {
1.199 - return w != OBJECT;
1.200 - }
1.201 -
1.202 - private Wrapper toWrapper(String desc) {
1.203 - char first = desc.charAt(0);
1.204 - if (first == '[' || first == '(') {
1.205 - first = 'L';
1.206 - }
1.207 - return Wrapper.forBasicType(first);
1.208 - }
1.209 -
1.210 - /**
1.211 - * Convert an argument of type 'arg' to be passed to 'target' assuring that it is 'functional'.
1.212 - * Insert the needed conversion instructions in the method code.
1.213 - * @param arg
1.214 - * @param target
1.215 - * @param functional
1.216 - */
1.217 - void convertType(Class<?> arg, Class<?> target, Class<?> functional) {
1.218 - if (arg.equals(target) && arg.equals(functional)) {
1.219 - return;
1.220 - }
1.221 - if (arg == Void.TYPE || target == Void.TYPE) {
1.222 - return;
1.223 - }
1.224 - if (arg.isPrimitive()) {
1.225 - Wrapper wArg = Wrapper.forPrimitiveType(arg);
1.226 - if (target.isPrimitive()) {
1.227 - // Both primitives: widening
1.228 - widen(wArg, Wrapper.forPrimitiveType(target));
1.229 - } else {
1.230 - // Primitive argument to reference target
1.231 - String dTarget = BytecodeDescriptor.unparse(target);
1.232 - Wrapper wPrimTarget = wrapperOrNullFromDescriptor(dTarget);
1.233 - if (wPrimTarget != null) {
1.234 - // The target is a boxed primitive type, widen to get there before boxing
1.235 - widen(wArg, wPrimTarget);
1.236 - box(wPrimTarget);
1.237 - } else {
1.238 - // Otherwise, box and cast
1.239 - box(wArg);
1.240 - cast(wrapperName(wArg), dTarget);
1.241 - }
1.242 - }
1.243 - } else {
1.244 - String dArg = BytecodeDescriptor.unparse(arg);
1.245 - String dSrc;
1.246 - if (functional.isPrimitive()) {
1.247 - dSrc = dArg;
1.248 - } else {
1.249 - // Cast to convert to possibly more specific type, and generate CCE for invalid arg
1.250 - dSrc = BytecodeDescriptor.unparse(functional);
1.251 - cast(dArg, dSrc);
1.252 - }
1.253 - String dTarget = BytecodeDescriptor.unparse(target);
1.254 - if (target.isPrimitive()) {
1.255 - Wrapper wTarget = toWrapper(dTarget);
1.256 - // Reference argument to primitive target
1.257 - Wrapper wps = wrapperOrNullFromDescriptor(dSrc);
1.258 - if (wps != null) {
1.259 - if (wps.isSigned() || wps.isFloating()) {
1.260 - // Boxed number to primitive
1.261 - unbox(wrapperName(wps), wTarget);
1.262 - } else {
1.263 - // Character or Boolean
1.264 - unbox(wrapperName(wps), wps);
1.265 - widen(wps, wTarget);
1.266 - }
1.267 - } else {
1.268 - // Source type is reference type, but not boxed type,
1.269 - // assume it is super type of target type
1.270 - String intermediate;
1.271 - if (wTarget.isSigned() || wTarget.isFloating()) {
1.272 - // Boxed number to primitive
1.273 - intermediate = "java/lang/Number";
1.274 - } else {
1.275 - // Character or Boolean
1.276 - intermediate = wrapperName(wTarget);
1.277 - }
1.278 - cast(dSrc, intermediate);
1.279 - unbox(intermediate, wTarget);
1.280 - }
1.281 - } else {
1.282 - // Both reference types: just case to target type
1.283 - cast(dSrc, dTarget);
1.284 - }
1.285 - }
1.286 - }
1.287 -
1.288 - /**
1.289 - * The following method is copied from
1.290 - * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very small
1.291 - * and fast Java bytecode manipulation framework.
1.292 - * Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved.
1.293 - */
1.294 - void iconst(final int cst) {
1.295 - if (cst >= -1 && cst <= 5) {
1.296 - mv.visitInsn(Opcodes.ICONST_0 + cst);
1.297 - } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
1.298 - mv.visitIntInsn(Opcodes.BIPUSH, cst);
1.299 - } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
1.300 - mv.visitIntInsn(Opcodes.SIPUSH, cst);
1.301 - } else {
1.302 - mv.visitLdcInsn(cst);
1.303 - }
1.304 - }
1.305 -}