/** * Copyright 2013, Landz and its contributors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package z.znr.invoke.linux.x64; import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.MethodVisitor; import z.znr.invoke.types.ParameterType; import z.znr.invoke.types.SignatureType; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.util.Map; import static jdk.internal.org.objectweb.asm.Opcodes.*; final class AsmUtil { private AsmUtil() {} public static MethodVisitor newTraceMethodVisitor(MethodVisitor mv) { try { Class<? extends MethodVisitor> tmvClass = Class.forName("jdk.internal.org.objectweb.asm.util.TraceMethodVisitor").asSubclass(MethodVisitor.class); Constructor<? extends MethodVisitor> c = tmvClass.getDeclaredConstructor(MethodVisitor.class); return c.newInstance(mv); } catch (Throwable t) { return mv; } } public static ClassVisitor newTraceClassVisitor(ClassVisitor cv, OutputStream out) { return newTraceClassVisitor(cv, new PrintWriter(out, true)); } public static ClassVisitor newTraceClassVisitor(ClassVisitor cv, PrintWriter out) { try { Class<? extends ClassVisitor> tmvClass = Class.forName("jdk.internal.org.objectweb.asm.util.TraceClassVisitor").asSubclass(ClassVisitor.class); Constructor<? extends ClassVisitor> c = tmvClass.getDeclaredConstructor(ClassVisitor.class, PrintWriter.class); return c.newInstance(cv, out); } catch (Throwable t) { return cv; } } public static ClassVisitor newTraceClassVisitor(PrintWriter out) { try { Class<? extends ClassVisitor> tmvClass = Class.forName("jdk.internal.org.objectweb.asm.util.TraceClassVisitor").asSubclass(ClassVisitor.class); Constructor<? extends ClassVisitor> c = tmvClass.getDeclaredConstructor(PrintWriter.class); return c.newInstance(out); } catch (Throwable t) { throw new RuntimeException(t); } } public static ClassVisitor newCheckClassAdapter(ClassVisitor cv) { try { Class<? extends ClassVisitor> tmvClass = Class.forName("jdk.internal.org.objectweb.asm.util.CheckClassAdapter").asSubclass(ClassVisitor.class); Constructor<? extends ClassVisitor> c = tmvClass.getDeclaredConstructor(ClassVisitor.class); return c.newInstance(cv); } catch (Throwable t) { return cv; } } static void emitReturnOp(SkinnyMethodAdapter mv, Class returnType) { if (!returnType.isPrimitive()) { mv.areturn(); } else if (long.class == returnType) { mv.lreturn(); } else if (float.class == returnType) { mv.freturn(); } else if (double.class == returnType) { mv.dreturn(); } else if (void.class == returnType) { mv.voidreturn(); } else { mv.ireturn(); } } /** * Calculates the size of a local variable * * @param type The type of parameter * @return The size in parameter units */ static int calculateLocalVariableSpace(Class type) { return long.class == type || double.class == type ? 2 : 1; } /** * Calculates the size of a local variable * * @param type The type of parameter * @return The size in parameter units */ static int calculateLocalVariableSpace(SignatureType type) { return calculateLocalVariableSpace(type.javaType()); } /** * Calculates the size of a list of types in the local variable area. * * @param types The type of parameter * @return The size in parameter units */ static int calculateLocalVariableSpace(Class... types) { int size = 0; for (int i = 0; i < types.length; ++i) { size += calculateLocalVariableSpace(types[i]); } return size; } /** * Calculates the size of a list of types in the local variable area. * * @param types The type of parameter * @return The size in parameter units */ static int calculateLocalVariableSpace(SignatureType... types) { int size = 0; for (SignatureType type : types) { size += calculateLocalVariableSpace(type); } return size; } static LocalVariable[] getParameterVariables(ParameterType[] parameterTypes, boolean isStatic) { LocalVariable[] lvars = new LocalVariable[parameterTypes.length]; int lvar = isStatic ? 0 : 1; for (int i = 0; i < parameterTypes.length; i++) { lvars[i] = new LocalVariable(parameterTypes[i].javaType(), lvar); lvar += calculateLocalVariableSpace(parameterTypes[i]); } return lvars; } static void load(SkinnyMethodAdapter mv, Class parameterType, LocalVariable parameter) { if (!parameterType.isPrimitive()) { mv.aload(parameter); } else if (long.class == parameterType) { mv.lload(parameter); } else if (float.class == parameterType) { mv.fload(parameter); } else if (double.class == parameterType) { mv.dload(parameter); } else { mv.iload(parameter); } } static void store(SkinnyMethodAdapter mv, Class type, LocalVariable var) { if (!type.isPrimitive()) { mv.astore(var); } else if (long.class == type) { mv.lstore(var); } else if (double.class == type) { mv.dstore(var); } else if (float.class == type) { mv.fstore(var); } else { mv.istore(var); } } static void tryfinally(SkinnyMethodAdapter mv, Runnable codeBlock, Runnable finallyBlock) { Label before = new Label(), after = new Label(), ensure = new Label(), done = new Label(); mv.trycatch(before, after, ensure, null); mv.label(before); codeBlock.run(); mv.label(after); if (finallyBlock != null) finallyBlock.run(); mv.go_to(done); if (finallyBlock != null) { mv.label(ensure); finallyBlock.run(); mv.athrow(); } mv.label(done); } static void emitDefaultConstructor(ClassVisitor cv) { SkinnyMethodAdapter init = new SkinnyMethodAdapter(cv, ACC_PUBLIC, "<init>", CodegenUtils.sig(void.class), null, null); init.start(); init.aload(0); init.invokespecial(CodegenUtils.p(Object.class), "<init>", CodegenUtils.sig(void.class)); init.voidreturn(); init.visitMaxs(10, 10); init.visitEnd(); } static void emitStaticFieldInitialization(AsmBuilder builder, ClassVisitor cv) { // Create the static class initializer to set the instance fields Map<String, Object> fields = builder.getObjectFieldMap(); if (!fields.isEmpty()) { String classID = builder.getClassNamePath(); AsmRuntime.setStaticClassData(classID, fields); SkinnyMethodAdapter clinit = new SkinnyMethodAdapter(cv, ACC_PUBLIC | ACC_STATIC, "<clinit>", CodegenUtils.sig(void.class), null, null); clinit.start(); clinit.ldc(classID); clinit.invokestatic(AsmRuntime.class, "getStaticClassData", Map.class, String.class); clinit.astore(0); for (AsmBuilder.ObjectField f : builder.getObjectFieldArray()) { if (f.klass.isPrimitive()) { cv.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, f.name, CodegenUtils.ci(f.klass), null, f.value).visitEnd(); } else { cv.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, f.name, CodegenUtils.ci(f.klass), null, null).visitEnd(); clinit.aload(0); clinit.ldc(f.name); clinit.invokeinterface(Map.class, "get", Object.class, Object.class); clinit.checkcast(f.klass); clinit.putstatic(builder.getClassNamePath(), f.name, CodegenUtils.ci(f.klass)); } } clinit.voidreturn(); clinit.visitMaxs(10, 10); clinit.visitEnd(); } } }