# HG changeset patch # User Gilles Duboscq # Date 1341402952 -7200 # Node ID 99e186e7ad62f7d6b3994343786c3114d2a897f8 # Parent 30876d0bb92db2e8c4141f6182692dcb3d3984f6# Parent 12706c5b39bc4a5e69e7f4899092925ccc9ea45e Merge diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.api.interpreter/src/com/oracle/graal/api/interpreter/Interpreter.java --- a/graal/com.oracle.graal.api.interpreter/src/com/oracle/graal/api/interpreter/Interpreter.java Wed Jul 04 13:55:03 2012 +0200 +++ b/graal/com.oracle.graal.api.interpreter/src/com/oracle/graal/api/interpreter/Interpreter.java Wed Jul 04 13:55:52 2012 +0200 @@ -25,5 +25,6 @@ import com.oracle.graal.api.meta.*; public interface Interpreter extends VirtualMachineComponent { - Object execute(ResolvedJavaMethod method, Object... arguments); + boolean initialize(String args); + Object execute(ResolvedJavaMethod method, Object... arguments) throws Throwable; } diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.api.interpreter/src/com/oracle/graal/api/interpreter/RuntimeInterpreterInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.interpreter/src/com/oracle/graal/api/interpreter/RuntimeInterpreterInterface.java Wed Jul 04 13:55:52 2012 +0200 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 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. + * + * 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 com.oracle.graal.api.interpreter; + +import com.oracle.graal.api.meta.*; + +/** + * Please note: The parameters of the interface are currently in reversed order + * since it was derived from the java ByteCodeInterpreter implementation. There + * it was simpler to use the parameters in reversed order since they are popped from + * the stack in reversed order. + */ +public interface RuntimeInterpreterInterface { + + Object invoke(ResolvedJavaMethod method, Object... args); + + void monitorEnter(Object value); + + void monitorExit(Object value); + + Object newObject(ResolvedJavaType type) throws InstantiationException; + + Object getFieldObject(Object base, ResolvedJavaField field); + + boolean getFieldBoolean(Object base, ResolvedJavaField field); + + byte getFieldByte(Object base, ResolvedJavaField field); + + char getFieldChar(Object base, ResolvedJavaField field); + + short getFieldShort(Object base, ResolvedJavaField field); + + int getFieldInt(Object base, ResolvedJavaField field); + + long getFieldLong(Object base, ResolvedJavaField field); + + double getFieldDouble(Object base, ResolvedJavaField field); + + float getFieldFloat(Object base, ResolvedJavaField field); + + void setFieldObject(Object value, Object base, ResolvedJavaField field); + + void setFieldInt(int value, Object base, ResolvedJavaField field); + + void setFieldFloat(float value, Object base, ResolvedJavaField field); + + void setFieldDouble(double value, Object base, ResolvedJavaField field); + + void setFieldLong(long value, Object base, ResolvedJavaField field); + + byte getArrayByte(long index, Object array); + + char getArrayChar(long index, Object array); + + short getArrayShort(long index, Object array); + + int getArrayInt(long index, Object array); + + long getArrayLong(long index, Object array); + + double getArrayDouble(long index, Object array); + + float getArrayFloat(long index, Object array); + + Object getArrayObject(long index, Object array); + + void setArrayByte(byte value, long index, Object array); + + void setArrayChar(char value, long index, Object array); + + void setArrayShort(short value, long index, Object array); + + void setArrayInt(int value, long index, Object array); + + void setArrayLong(long value, long index, Object array); + + void setArrayFloat(float value, long index, Object array); + + void setArrayDouble(double value, long index, Object array); + + void setArrayObject(Object value, long index, Object array); + +} diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Wed Jul 04 13:55:03 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Wed Jul 04 13:55:52 2012 +0200 @@ -25,6 +25,7 @@ import java.lang.reflect.*; import com.oracle.graal.api.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.interpreter.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.target.*; @@ -52,6 +53,7 @@ private HotSpotRuntime runtime; private GraalCompiler compiler; private TargetDescription target; + private HotSpotRuntimeInterpreterInterface runtimeInterpreterInterface; private volatile HotSpotGraphCache cache; private final HotSpotVMConfig config; @@ -176,6 +178,13 @@ return compilerToVm.Signature_lookupType(returnType, accessingClass, eagerResolve); } + public HotSpotRuntimeInterpreterInterface getRuntimeInterpreterInterface() { + if (runtimeInterpreterInterface == null) { + runtimeInterpreterInterface = new HotSpotRuntimeInterpreterInterface(getRuntime()); + } + return runtimeInterpreterInterface; + } + public HotSpotRuntime getRuntime() { if (runtime == null) { runtime = new HotSpotRuntime(config, this); @@ -210,6 +219,12 @@ if (clazz == GraalCompiler.class) { return (T) getCompiler(); } + if (clazz == MetaAccessProvider.class) { + return (T) getRuntime(); + } + if (clazz == RuntimeInterpreterInterface.class) { + return (T) getRuntimeInterpreterInterface(); + } return null; } } diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeInterpreterInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeInterpreterInterface.java Wed Jul 04 13:55:52 2012 +0200 @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2012, 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. + * + * 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 com.oracle.graal.hotspot; + +import java.lang.reflect.*; + +import sun.misc.*; + +import com.oracle.graal.api.interpreter.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; + +public class HotSpotRuntimeInterpreterInterface implements RuntimeInterpreterInterface { + + private static final Unsafe unsafe = loadUnsafe(); + + private final MetaAccessProvider metaProvider; + + public HotSpotRuntimeInterpreterInterface(MetaAccessProvider metaProvider) { + this.metaProvider = metaProvider; + } + + public native Object invoke(ResolvedJavaMethod method, Object... args); + + public void monitorEnter(Object value) { + nullCheck(value); + unsafe.monitorEnter(value); + } + + public void monitorExit(Object value) { + nullCheck(value); + unsafe.monitorExit(value); + } + + public Object newObject(ResolvedJavaType type) throws InstantiationException { + return unsafe.allocateInstance(type.toJava()); + } + + public Object getFieldObject(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getObjectVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getObject(resolveBase(base, field), offset); + } + } + + public boolean getFieldBoolean(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getBooleanVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getBoolean(resolveBase(base, field), offset); + } + } + + public byte getFieldByte(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getByteVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getByte(resolveBase(base, field), offset); + } + } + + public char getFieldChar(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getCharVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getChar(resolveBase(base, field), offset); + } + } + + public short getFieldShort(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getShortVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getShort(resolveBase(base, field), offset); + } + } + + public int getFieldInt(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getIntVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getInt(resolveBase(base, field), offset); + } + } + + public long getFieldLong(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getLongVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getLong(resolveBase(base, field), offset); + } + } + + public double getFieldDouble(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getDoubleVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getDouble(resolveBase(base, field), offset); + } + } + + public float getFieldFloat(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getFloatVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getFloat(resolveBase(base, field), offset); + } + } + + public void setFieldObject(Object value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putObjectVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putObject(resolveBase(base, field), offset, value); + } + } + + public void setFieldInt(int value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putIntVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putInt(resolveBase(base, field), offset, value); + } + } + + + public void setFieldFloat(float value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putFloatVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putFloat(resolveBase(base, field), offset, value); + } + } + + public void setFieldDouble(double value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putDouble(resolveBase(base, field), offset, value); + } + } + + public void setFieldLong(long value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putDouble(resolveBase(base, field), offset, value); + } + } + + public byte getArrayByte(long index, Object array) { + checkArray(array, index); + return unsafe.getByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index); + } + + public char getArrayChar(long index, Object array) { + checkArray(array, index); + return unsafe.getChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index); + } + + public short getArrayShort(long index, Object array) { + checkArray(array, index); + return unsafe.getShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index); + } + + public int getArrayInt(long index, Object array) { + checkArray(array, index); + return unsafe.getInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index); + } + + public long getArrayLong(long index, Object array) { + checkArray(array, index); + return unsafe.getLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index); + } + + public double getArrayDouble(long index, Object array) { + checkArray(array, index); + return unsafe.getDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index); + } + + public float getArrayFloat(long index, Object array) { + checkArray(array, index); + return unsafe.getFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index); + } + + public Object getArrayObject(long index, Object array) { + checkArray(array, index); + return unsafe.getObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index); + } + + public void setArrayByte(byte value, long index, Object array) { + checkArray(array, index); + if (array instanceof boolean[]) { + checkArrayType(array, boolean.class); + } else { + checkArrayType(array, byte.class); + } + unsafe.putByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index, value); + } + + public void setArrayChar(char value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, char.class); + unsafe.putChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index, value); + } + + public void setArrayShort(short value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, short.class); + unsafe.putShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index, value); + } + + public void setArrayInt(int value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, int.class); + unsafe.putInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index, value); + } + + public void setArrayLong(long value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, long.class); + unsafe.putLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index, value); + } + + public void setArrayFloat(float value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, float.class); + unsafe.putFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index, value); + } + + public void setArrayDouble(double value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, double.class); + unsafe.putDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index, value); + } + + public void setArrayObject(Object value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, value != null ? value.getClass() : null); + unsafe.putObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index, value); + } + + private static void nullCheck(Object value) { + if (value == null) { + throw new NullPointerException(); + } + } + + private void checkArrayType(Object array, Class arrayType) { + if (arrayType == null) { + return; + } + ResolvedJavaType type = metaProvider.getResolvedJavaType(array.getClass()).componentType(); + if (!type.toJava().isAssignableFrom(arrayType)) { + throw new ArrayStoreException(arrayType.getName()); + } + } + + private void checkArray(Object array, long index) { + nullCheck(array); + ResolvedJavaType type = metaProvider.getResolvedJavaType(array.getClass()); + if (!type.isArrayClass()) { + throw new ArrayStoreException(array.getClass().getName()); + } + if (index < 0 || index >= arrayLength(array)) { + throw new ArrayIndexOutOfBoundsException((int) index); + } + } + + private static int arrayLength(Object array) { + assert array != null; + return Array.getLength(array); + } + + private static boolean isVolatile(ResolvedJavaField field) { + return Modifier.isVolatile(field.accessFlags()); + } + + private static long resolveOffset(ResolvedJavaField field) { + return ((HotSpotResolvedJavaField) field).offset(); + } + + private static Object resolveBase(Object base, ResolvedJavaField field) { + Object accessorBase = base; + if (accessorBase == null) { + accessorBase = field.holder().toJava(); + } + return accessorBase; + } + + private static Unsafe loadUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException e) { + } + try { + Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeInstance.setAccessible(true); + return (Unsafe) theUnsafeInstance.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); + } + } +} diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jul 04 13:55:03 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jul 04 13:55:52 2012 +0200 @@ -61,7 +61,7 @@ public int instanceHeaderPrototypeOffset; public int threadExceptionOopOffset; public int threadExceptionPcOffset; - public int threadMultiNewArrayStorage; + public int threadMultiNewArrayStorageOffset; public long cardtableStartAddress; public int cardtableShift; public long safepointPollingAddress; diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotXirGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotXirGenerator.java Wed Jul 04 13:55:03 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotXirGenerator.java Wed Jul 04 13:55:52 2012 +0200 @@ -447,7 +447,7 @@ XirOperand rank = asm.createRegisterTemp("rank", Kind.Int, AMD64.rbx); XirOperand sizes = asm.createRegisterTemp("sizes", Kind.Long, AMD64.rcx); XirOperand thread = asm.createRegisterTemp("thread", Kind.Long, AMD64.r15); - asm.add(sizes, thread, asm.l(config.threadMultiNewArrayStorage)); + asm.add(sizes, thread, asm.l(config.threadMultiNewArrayStorageOffset)); for (int i = 0; i < dimensions; i++) { XirParameter length = asm.createInputParameter("length" + i, Kind.Int, true); asm.pstore(Kind.Int, sizes, asm.i(i * target.sizeInBytes(Kind.Int)), length, false); diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java --- a/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java Wed Jul 04 13:55:03 2012 +0200 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java Wed Jul 04 13:55:52 2012 +0200 @@ -25,6 +25,7 @@ import java.lang.reflect.*; import java.util.*; +import com.oracle.graal.api.*; import com.oracle.graal.api.interpreter.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.bytecode.*; @@ -49,7 +50,7 @@ private static final boolean TRACE = false; private static final boolean TRACE_BYTE_CODE = false; - private static final int DEFAULT_MAX_STACK_SIZE = 200; + private static final int DEFAULT_MAX_STACK_SIZE = 1500; private static final int NEXT = -1; private static final int BRANCH = -2; @@ -58,28 +59,32 @@ private InterpreterFrame callFrame; - //TODO try to remove this reference - private ExceptionHandler catchAllExceptionHandler; + private Map methodDelegates; - private final Map methodDelegates = new HashMap<>(); - - private int maxStackFrames = DEFAULT_MAX_STACK_SIZE; + private int maxStackFrames; private int stackFrameDepth; - private final ResolvedJavaMethod rootMethod; - private final VMAdapter vm; + private ResolvedJavaMethod rootMethod; + private RuntimeInterpreterInterface runtimeInterface; + private MetaAccessProvider metaAccessProvider; + + public boolean initialize(String args) { + methodDelegates = new HashMap<>(); + maxStackFrames = DEFAULT_MAX_STACK_SIZE; - public BytecodeInterpreter() { - this(VMAdapter.getInstance()); - } + GraalRuntime runtime = Graal.getRuntime(); + this.runtimeInterface = runtime.getCapability(RuntimeInterpreterInterface.class); + if (this.runtimeInterface == null) { + throw new UnsupportedOperationException("The provided graal runtime does not support the required capability " + RuntimeInterpreterInterface.class.getName() + "."); + } + this.metaAccessProvider = runtime.getCapability(MetaAccessProvider.class); + if (this.metaAccessProvider == null) { + throw new UnsupportedOperationException("The provided graal runtime does not support the required capability " + MetaAccessProvider.class.getName() + "."); + } - public BytecodeInterpreter(VMAdapter accessor) { - if (accessor == null) { - throw new NullPointerException(); - } - this.vm = accessor; this.rootMethod = resolveRootMethod(); registerDelegates(); + return parseArguments(args); } @Override @@ -89,19 +94,18 @@ } } - private void registerDelegates() { addDelegate(findMethod(Throwable.class, "fillInStackTrace"), new InterpreterCallable() { @Override - public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable { - setBackTrace(caller, (Throwable) base, createStackTraceElements(caller)); + public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object[] arguments) throws Throwable { + setBackTrace(caller, (Throwable) arguments[0], createStackTraceElements(caller)); return null; } }); addDelegate(findMethod(Throwable.class, "getStackTraceDepth"), new InterpreterCallable() { @Override - public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable { - StackTraceElement[] elements = getBackTrace(caller, (Throwable) base); + public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object[] arguments) throws Throwable { + StackTraceElement[] elements = getBackTrace(caller, (Throwable) arguments[0]); if (elements != null) { return elements.length; } @@ -110,8 +114,8 @@ }); addDelegate(findMethod(Throwable.class, "getStackTraceElement", int.class), new InterpreterCallable() { @Override - public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable { - StackTraceElement[] elements = getBackTrace(caller, (Throwable) base); + public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object[] arguments) throws Throwable { + StackTraceElement[] elements = getBackTrace(caller, (Throwable) arguments[0]); if (elements != null) { Integer index = (Integer) arguments[0]; if (index != null) { @@ -123,6 +127,12 @@ }); } + @SuppressWarnings("unused") + private boolean parseArguments(String stringArgs) { + // TODO: parse the arguments + return true; + } + public void setMaxStackFrames(int maxStackSize) { this.maxStackFrames = maxStackSize; } @@ -132,53 +142,55 @@ } public void addDelegate(Method method, InterpreterCallable callable) { - ResolvedJavaMethod resolvedMethod = vm.getRuntime().getResolvedJavaMethod(method); + ResolvedJavaMethod resolvedMethod = metaAccessProvider.getResolvedJavaMethod(method); if (methodDelegates.containsKey(resolvedMethod)) { throw new IllegalArgumentException("Delegate for method " + method + " already added."); } - methodDelegates.put(resolvedMethod, callable); + + methodDelegates.put(resolvedMethod, new MethodRedirectionInfo(callable)); } public void removeDelegate(Method method) { - methodDelegates.remove(vm.getRuntime().getResolvedJavaMethod(method)); + methodDelegates.remove(metaAccessProvider.getResolvedJavaMethod(method)); } @Override - public Object execute(ResolvedJavaMethod method, Object... boxedArguments) { - Signature signature = method.signature(); - assert boxedArguments != null; - assert signature.argumentCount(false) == boxedArguments.length; + public Object execute(ResolvedJavaMethod method, Object... boxedArguments) throws Throwable { + try { + boolean receiver = hasReceiver(method); + Signature signature = method.signature(); + assert boxedArguments != null; + assert signature.argumentCount(receiver) == boxedArguments.length; - if (!Modifier.isStatic(method.accessFlags())) { - throw new UnsupportedOperationException("The interpreter can currently only be started with static methods."); - } - - InterpreterFrame rootFrame = new InterpreterFrame(rootMethod, signature.argumentSlots(true)); - rootFrame.pushObject(this); - rootFrame.pushObject(method); - rootFrame.pushObject(boxedArguments); + InterpreterFrame rootFrame = new InterpreterFrame(rootMethod, signature.argumentSlots(true)); + rootFrame.pushObject(this); + rootFrame.pushObject(method); + rootFrame.pushObject(boxedArguments); - for (int i = 0; i < boxedArguments.length; i++) { - pushAsObject(rootFrame, signature.argumentKindAt(i), boxedArguments[i]); - } + int index = 0; + if (receiver) { + pushAsObject(rootFrame, Kind.Object, boxedArguments[index]); + index++; + } - InterpreterFrame frame = rootFrame.create(method, false); + for (int i = 0; i < boxedArguments.length; i++, index++) { + pushAsObject(rootFrame, signature.argumentKindAt(i), boxedArguments[index]); + } - try { + InterpreterFrame frame = rootFrame.create(method, receiver); executeRoot(rootFrame, frame); - } catch (Throwable e) { - // clear backtrace for compatibilty and store it in stacktrace - StackTraceElement[] backtrace = getBackTrace(rootFrame, e); - setBackTrace(rootFrame, e, null); - setStackTrace(rootFrame, e, backtrace); - throw new InterpreterException(e); + return popAsObject(rootFrame, signature.returnKind()); + } catch (Exception e) { + throw e; } - - return popAsObject(rootFrame, signature.returnKind()); } - public Object execute(Method javaMethod, Object... boxedArguments) throws InterpreterException { - return execute(vm.getRuntime().getResolvedJavaMethod(javaMethod), boxedArguments); + public Object execute(Method javaMethod, Object... boxedArguments) throws Throwable { + return execute(metaAccessProvider.getResolvedJavaMethod(javaMethod), boxedArguments); + } + + private boolean hasReceiver(ResolvedJavaMethod method) { + return !Modifier.isStatic(method.accessFlags()); } private void executeRoot(InterpreterFrame root, InterpreterFrame frame) throws Throwable { @@ -392,28 +404,28 @@ frame.pushObject(frame.getObject(frame.resolveLocalIndex(3))); break; case Bytecodes.IALOAD : - frame.pushInt(vm.getArrayInt(frame.popInt(), frame.popObject())); + frame.pushInt(runtimeInterface.getArrayInt(frame.popInt(), frame.popObject())); break; case Bytecodes.LALOAD : - frame.pushLong(vm.getArrayLong(frame.popInt(), frame.popObject())); + frame.pushLong(runtimeInterface.getArrayLong(frame.popInt(), frame.popObject())); break; case Bytecodes.FALOAD : - frame.pushFloat(vm.getArrayFloat(frame.popInt(), frame.popObject())); + frame.pushFloat(runtimeInterface.getArrayFloat(frame.popInt(), frame.popObject())); break; case Bytecodes.DALOAD : - frame.pushDouble(vm.getArrayDouble(frame.popInt(), frame.popObject())); + frame.pushDouble(runtimeInterface.getArrayDouble(frame.popInt(), frame.popObject())); break; case Bytecodes.AALOAD : - frame.pushObject(vm.getArrayObject(frame.popInt(), frame.popObject())); + frame.pushObject(runtimeInterface.getArrayObject(frame.popInt(), frame.popObject())); break; case Bytecodes.BALOAD : - frame.pushInt(vm.getArrayByte(frame.popInt(), frame.popObject())); + frame.pushInt(runtimeInterface.getArrayByte(frame.popInt(), frame.popObject())); break; case Bytecodes.CALOAD : - frame.pushInt(vm.getArrayChar(frame.popInt(), frame.popObject())); + frame.pushInt(runtimeInterface.getArrayChar(frame.popInt(), frame.popObject())); break; case Bytecodes.SALOAD: - frame.pushInt(vm.getArrayShort(frame.popInt(), frame.popObject())); + frame.pushInt(runtimeInterface.getArrayShort(frame.popInt(), frame.popObject())); break; case Bytecodes.ISTORE: frame.setInt(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popInt()); @@ -491,28 +503,28 @@ frame.setObject(frame.resolveLocalIndex(3), frame.popObject()); break; case Bytecodes.IASTORE : - vm.setArrayInt(frame.popInt(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayInt(frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.LASTORE : - vm.setArrayLong(frame.popLong(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayLong(frame.popLong(), frame.popInt(), frame.popObject()); break; case Bytecodes.FASTORE : - vm.setArrayFloat(frame.popFloat(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayFloat(frame.popFloat(), frame.popInt(), frame.popObject()); break; case Bytecodes.DASTORE : - vm.setArrayDouble(frame.popDouble(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayDouble(frame.popDouble(), frame.popInt(), frame.popObject()); break; case Bytecodes.AASTORE : - vm.setArrayObject(frame.popObject(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayObject(frame.popObject(), frame.popInt(), frame.popObject()); break; case Bytecodes.BASTORE : - vm.setArrayByte((byte) frame.popInt(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayByte((byte) frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.CASTORE : - vm.setArrayChar((char) frame.popInt(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayChar((char) frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.SASTORE : - vm.setArrayShort((short) frame.popInt(), frame.popInt(), frame.popObject()); + runtimeInterface.setArrayShort((short) frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.POP : frame.popVoid(1); @@ -849,7 +861,7 @@ } return CALL; case Bytecodes.XXXUNUSEDXXX : - assert false : "unused bytecode used. behaviour unspecfied."; + assert false : "unused bytecode used. behaviour unspecified."; // nop break; case Bytecodes.NEW : @@ -873,10 +885,10 @@ instanceOf(frame, bs.readCPI()); break; case Bytecodes.MONITORENTER : - vm.monitorEnter(frame.popObject()); + runtimeInterface.monitorEnter(frame.popObject()); break; case Bytecodes.MONITOREXIT : - vm.monitorExit(frame.popObject()); + runtimeInterface.monitorExit(frame.popObject()); break; case Bytecodes.WIDE : assert false; @@ -912,11 +924,6 @@ currentFrame = popFrame(currentFrame); } else { // found a handler -> execute it - if (handler.isCatchAll()) { - catchAllExceptionHandler = handler; - } else { - catchAllExceptionHandler = null; - } currentFrame.setBCI(handler.handlerBCI()); currentFrame.popStack(); currentFrame.pushObject(t); @@ -940,11 +947,11 @@ private void setStackTrace(InterpreterFrame frame, Throwable t, StackTraceElement[] stackTrace) { - vm.setField(stackTrace, t, findThrowableField(frame, "stackTrace")); + runtimeInterface.setFieldObject(stackTrace, t, findThrowableField(frame, "stackTrace")); } private StackTraceElement[] getBackTrace(InterpreterFrame frame, Throwable t) { - Object value = vm.getField(t, findThrowableField(frame, "backtrace")); + Object value = runtimeInterface.getFieldObject(t, findThrowableField(frame, "backtrace")); if (value instanceof StackTraceElement[]) { return (StackTraceElement[]) value; } @@ -952,19 +959,18 @@ } private void setBackTrace(InterpreterFrame frame, Throwable t, StackTraceElement[] backtrace) { - vm.setField(backtrace, t, findThrowableField(frame, "backtrace")); + runtimeInterface.setFieldObject(backtrace, t, findThrowableField(frame, "backtrace")); } private ExceptionHandler resolveExceptionHandlers(InterpreterFrame frame, int bci, Throwable t) { ExceptionHandler[] handlers = frame.getMethod().exceptionHandlers(); for (int i = 0; i < handlers.length; i++) { ExceptionHandler handler = handlers[i]; - if (bci >= handler.startBCI() - && bci <= handler.endBCI() - && (catchAllExceptionHandler == null || !handler.isCatchAll())) { + if (bci >= handler.startBCI() && bci <= handler.endBCI()) { ResolvedJavaType catchType = null; if (!handler.isCatchAll()) { - catchType = resolveType(frame, bci, (char) handler.catchTypeCPI()); + // exception handlers are similar to instanceof bytecodes, so we pass instanceof + catchType = resolveType(frame, Bytecodes.INSTANCEOF, (char) handler.catchTypeCPI()); } if (catchType == null @@ -997,36 +1003,33 @@ traceOp("Method monitor enter"); } if (Modifier.isStatic(nextFrame.getMethod().accessFlags())) { - vm.monitorEnter(nextFrame.getMethod().holder().toJava()); + runtimeInterface.monitorEnter(nextFrame.getMethod().holder().toJava()); } else { Object enterObject = nextFrame.getObject(frame.resolveLocalIndex(0)); assert enterObject != null; - vm.monitorEnter(enterObject); + runtimeInterface.monitorEnter(enterObject); } } return nextFrame; } finally { - // catch all exception handlers are not allowed to call any method anyway. - catchAllExceptionHandler = null; callFrame = null; bs.next(); } } private InterpreterFrame popFrame(InterpreterFrame frame) { - catchAllExceptionHandler = null; InterpreterFrame parent = frame.getParentFrame(); if (Modifier.isSynchronized(frame.getMethod().accessFlags())) { if (TRACE) { traceOp("Method monitor exit"); } if (Modifier.isStatic(frame.getMethod().accessFlags())) { - vm.monitorExit(frame.getMethod().holder().toJava()); + runtimeInterface.monitorExit(frame.getMethod().holder().toJava()); } else { Object exitObject = frame.getObject(frame.resolveLocalIndex(0)); if (exitObject != null) { - vm.monitorExit(exitObject); + runtimeInterface.monitorExit(exitObject); } } } @@ -1196,7 +1199,7 @@ } private ResolvedJavaType resolveType(InterpreterFrame frame, Class javaClass) { - return vm.getRuntime().getResolvedJavaType(javaClass).resolve(frame.getMethod().holder()); + return metaAccessProvider.getResolvedJavaType(javaClass).resolve(frame.getMethod().holder()); } private ResolvedJavaMethod resolveMethod(InterpreterFrame frame, int opcode, char cpi) { @@ -1319,104 +1322,91 @@ return invoke(frame, m, nullCheck(frame.peekReceiver(m))); } - private void invokeReflective(InterpreterFrame frame, ResolvedJavaMethod method, boolean hasReceiver) throws Throwable { - Class[] parameterTypes = resolveMethodArguments(method); - Object[] parameters = popArgumentsAsObject(frame, method); - Class javaClass = method.holder().toJava(); - - Object parentObject = null; - if (hasReceiver) { - parentObject = frame.popObject(); - nullCheck(parentObject); - } - Object returnValue = null; + private Object[] popArgumentsAsObject(InterpreterFrame frame, ResolvedJavaMethod method, boolean hasReceiver) { + Signature signature = method.signature(); + int argumentCount = method.signature().argumentCount(hasReceiver); + Object[] parameters = new Object[argumentCount]; - if (redirect(method)) { - if (TRACE) { - traceCall(frame, "Delegate " + method); - } - try { - returnValue = methodDelegates.get(method).invoke(frame, method, parentObject, parameters); - } catch (Throwable e) { - throw e; - } - } else { - if (TRACE) { - traceCall(frame, "Reflective " + method); - } - try { - Method javaMethod = javaClass.getDeclaredMethod(method.name(), parameterTypes); - javaMethod.setAccessible(true); - returnValue = javaMethod.invoke(parentObject, parameters); - } catch (InvocationTargetException e) { - e.printStackTrace(System.out); - throw e.getTargetException(); - } catch (NoSuchMethodException | SecurityException e) { - throw new AbstractMethodError(); - } + int lastSignatureIndex = hasReceiver ? 1 : 0; + for (int i = argumentCount - 1; i >= lastSignatureIndex; i--) { + ResolvedJavaType type = signature.argumentTypeAt(i - lastSignatureIndex, method.holder()).resolve(method.holder()); + parameters[i] = popAsObject(frame, type.kind()); } - pushAsObject(frame, method.signature().returnKind(), returnValue); - } - - private Object[] popArgumentsAsObject(InterpreterFrame frame, ResolvedJavaMethod method) { - Signature signature = method.signature(); - int argumentCount = method.signature().argumentCount(false); - Object[] parameters = new Object[argumentCount]; - for (int i = argumentCount - 1; i >= 0; i--) { - ResolvedJavaType type = signature.argumentTypeAt(i, method.holder()).resolve(method.holder()); - parameters[i] = popAsObject(frame, type.kind()); + if (hasReceiver) { + parameters[0] = frame.popObject(); } return parameters; } - private Class[] resolveMethodArguments(ResolvedJavaMethod method) { - Signature signature = method.signature(); - int argumentCount = signature.argumentCount(false); - Class[] parameterTypes = new Class[argumentCount]; - - for (int i = 0; i < argumentCount; i++) { - JavaType type = signature.argumentTypeAt(i, method.holder()); - ResolvedJavaType resolvedType = type.resolve(method.holder()); - parameterTypes[i] = resolvedType.toJava(); - } - return parameterTypes; - } - - private InterpreterFrame invoke(InterpreterFrame parent, ResolvedJavaMethod method, Object receiver) throws Throwable { + private InterpreterFrame invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object receiver) throws Throwable { if (stackFrameDepth >= maxStackFrames) { throw new StackOverflowError("Maximum callstack of " + maxStackFrames + " exceeded."); } - if (redirect(method)) { - invokeReflective(parent, method, receiver != null); - // returning null results in a jump to the next instruction - // since the method is already successfully invoked. - return null; + if (Modifier.isNative(method.accessFlags())) { + return invokeNativeMethodViaVM(caller, method, receiver != null); } else { - if (Modifier.isNative(method.accessFlags())) { - invokeReflective(parent, method, receiver != null); - return null; + MethodRedirectionInfo redirectedMethod = methodDelegates.get(method); + if (redirectedMethod != null) { + return invokeRedirectedMethodViaVM(caller, method, redirectedMethod, receiver != null); } else { - return parent.create(method, receiver != null); + return invokeOptimized(caller, method, receiver != null); } } } - private boolean redirect(ResolvedJavaMethod method) { - return methodDelegates.containsKey(method); + private InterpreterFrame invokeNativeMethodViaVM(InterpreterFrame caller, ResolvedJavaMethod method, boolean hasReceiver) throws Throwable { + assert !methodDelegates.containsKey(method) : "must not be redirected"; + if (TRACE) { + traceCall(caller, "Native " + method); + } + + // mark the current thread as high level and execute the native method + Object[] parameters = popArgumentsAsObject(caller, method, hasReceiver); + Object returnValue = runtimeInterface.invoke(method, parameters); + pushAsObject(caller, method.signature().returnKind(), returnValue); + + return null; } + private InterpreterFrame invokeRedirectedMethodViaVM(InterpreterFrame caller, ResolvedJavaMethod originalMethod, MethodRedirectionInfo redirectionInfo, boolean hasReceiver) throws Throwable { + assert methodDelegates.containsKey(originalMethod) : "must be redirected"; + if (TRACE) { + traceCall(caller, "Delegate " + originalMethod); + } + + // current thread is low level and we also execute the target method in the low-level interpreter + Object[] originalCalleeParameters = popArgumentsAsObject(caller, originalMethod, hasReceiver); + Object[] parameters = new Object[] {caller, originalMethod, originalCalleeParameters}; + Object returnValue = redirectionInfo.getTargetMethod().invoke(redirectionInfo.getReceiver(), parameters); + pushAsObject(caller, originalMethod.signature().returnKind(), returnValue); + + return null; + } + + private InterpreterFrame invokeOptimized(InterpreterFrame parent, ResolvedJavaMethod method, boolean hasReceiver) throws Throwable { + return parent.create(method, hasReceiver); + } private Object allocateMultiArray(InterpreterFrame frame, char cpi, int dimension) { - ResolvedJavaType type = resolveType(frame, Bytecodes.MULTIANEWARRAY, cpi); + ResolvedJavaType type = getLastDimensionType(resolveType(frame, Bytecodes.MULTIANEWARRAY, cpi)); + int[] dimensions = new int[dimension]; - for (int i = 0; i < dimension; i++) { + for (int i = dimension - 1; i >= 0; i--) { dimensions[i] = frame.popInt(); } return Array.newInstance(type.toJava(), dimensions); } + private ResolvedJavaType getLastDimensionType(ResolvedJavaType type) { + ResolvedJavaType result = type; + while (result.isArrayClass()) { + result = result.componentType(); + } + return result; + } + private Object allocateArray(InterpreterFrame frame, char cpi) { ResolvedJavaType type = resolveType(frame, Bytecodes.ANEWARRAY, cpi); return Array.newInstance(type.toJava(), frame.popInt()); @@ -1448,7 +1438,7 @@ } private Object allocateInstance(InterpreterFrame frame, char cpi) throws InstantiationException { - return vm.newObject(resolveType(frame, Bytecodes.NEW, cpi)); + return runtimeInterface.newObject(resolveType(frame, Bytecodes.NEW, cpi)); } private void iinc(InterpreterFrame frame, BytecodeStream bs) { @@ -1471,19 +1461,19 @@ case Char : case Short : case Int : - vm.setFieldInt(frame.popInt(), null, field); + runtimeInterface.setFieldInt(frame.popInt(), null, field); break; case Double : - vm.setFieldDouble(frame.popDouble(), null, field); + runtimeInterface.setFieldDouble(frame.popDouble(), null, field); break; case Float : - vm.setFieldFloat(frame.popFloat(), null, field); + runtimeInterface.setFieldFloat(frame.popFloat(), null, field); break; case Long : - vm.setFieldLong(frame.popLong(), null, field); + runtimeInterface.setFieldLong(frame.popLong(), null, field); break; case Object : - vm.setField(frame.popObject(), null, field); + runtimeInterface.setFieldObject(frame.popObject(), null, field); break; default : assert false : "unexpected case"; @@ -1497,19 +1487,19 @@ case Char : case Short : case Int : - vm.setFieldInt(frame.popInt(), nullCheck(frame.popObject()), field); + runtimeInterface.setFieldInt(frame.popInt(), nullCheck(frame.popObject()), field); break; case Double : - vm.setFieldDouble(frame.popDouble(), nullCheck(frame.popObject()), field); + runtimeInterface.setFieldDouble(frame.popDouble(), nullCheck(frame.popObject()), field); break; case Float : - vm.setFieldFloat(frame.popFloat(), nullCheck(frame.popObject()), field); + runtimeInterface.setFieldFloat(frame.popFloat(), nullCheck(frame.popObject()), field); break; case Long : - vm.setFieldLong(frame.popLong(), nullCheck(frame.popObject()), field); + runtimeInterface.setFieldLong(frame.popLong(), nullCheck(frame.popObject()), field); break; case Object : - vm.setField(frame.popObject(), nullCheck(frame.popObject()), field); + runtimeInterface.setFieldObject(frame.popObject(), nullCheck(frame.popObject()), field); break; default : assert false : "unexpected case"; @@ -1520,23 +1510,31 @@ ResolvedJavaField field = resolveField(frame, opcode, cpi); switch (field.kind()) { case Boolean : + frame.pushInt(runtimeInterface.getFieldBoolean(base, field) ? 1 : 0); + break; case Byte : + frame.pushInt(runtimeInterface.getFieldByte(base, field)); + break; case Char : + frame.pushInt(runtimeInterface.getFieldChar(base, field)); + break; case Short : + frame.pushInt(runtimeInterface.getFieldShort(base, field)); + break; case Int : - frame.pushInt(vm.getFieldInt(base, field)); + frame.pushInt(runtimeInterface.getFieldInt(base, field)); break; case Double : - frame.pushDouble(vm.getFieldDouble(base, field)); + frame.pushDouble(runtimeInterface.getFieldDouble(base, field)); break; case Float : - frame.pushFloat(vm.getFieldFloat(base, field)); + frame.pushFloat(runtimeInterface.getFieldFloat(base, field)); break; case Long : - frame.pushLong(vm.getFieldLong(base, field)); + frame.pushLong(runtimeInterface.getFieldLong(base, field)); break; case Object : - frame.pushObject(vm.getField(base, field)); + frame.pushObject(runtimeInterface.getFieldObject(base, field)); break; default : assert false : "unexpected case"; @@ -1611,7 +1609,7 @@ private ResolvedJavaMethod resolveRootMethod() { try { - return vm.getRuntime().getResolvedJavaMethod(BytecodeInterpreter.class.getDeclaredMethod("execute", Method.class, Object[].class)); + return metaAccessProvider.getResolvedJavaMethod(BytecodeInterpreter.class.getDeclaredMethod("execute", Method.class, Object[].class)); } catch (Exception e) { throw new RuntimeException(e); } @@ -1655,4 +1653,31 @@ return null; } + private class MethodRedirectionInfo { + private InterpreterCallable receiver; + private Method method; + + public MethodRedirectionInfo(InterpreterCallable instance) { + this.receiver = instance; + this.method = resolveMethod(instance); + } + + public InterpreterCallable getReceiver() { + return receiver; + } + + public Method getTargetMethod() { + return method; + } + + private Method resolveMethod(InterpreterCallable instance) { + try { + return instance.getClass().getMethod(InterpreterCallable.INTERPRETER_CALLABLE_INVOKE_NAME, InterpreterCallable.INTERPRETER_CALLABLE_INVOKE_SIGNATURE); + } catch (NoSuchMethodException e) { + throw new InterpreterException(e); + } catch (SecurityException e) { + throw new InterpreterException(e); + } + } + } } diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterCallable.java --- a/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterCallable.java Wed Jul 04 13:55:03 2012 +0200 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterCallable.java Wed Jul 04 13:55:52 2012 +0200 @@ -26,7 +26,10 @@ public interface InterpreterCallable { + // static final fields + String INTERPRETER_CALLABLE_INVOKE_NAME = "invoke"; + Class[] INTERPRETER_CALLABLE_INVOKE_SIGNATURE = {InterpreterFrame.class, ResolvedJavaMethod.class, Object[].class}; - Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable; - + // methods + Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object[] arguments) throws Throwable; } diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterFrame.java --- a/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterFrame.java Wed Jul 04 13:55:03 2012 +0200 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterFrame.java Wed Jul 04 13:55:52 2012 +0200 @@ -245,6 +245,7 @@ } private void decrementTos(int size) { + assert tos - size >= stackTos(); tos -= size; } diff -r 30876d0bb92d -r 99e186e7ad62 graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/VMAdapter.java --- a/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/VMAdapter.java Wed Jul 04 13:55:03 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2012, 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. - * - * 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 com.oracle.graal.interpreter; - -import java.lang.reflect.*; - -import sun.misc.*; - -import com.oracle.graal.api.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.meta.*; - - -/** - * This class encapsulates all vm specific methods for the {@link BytecodeInterpreter}. - */ -public class VMAdapter { - - private static final Unsafe unsafe = loadUnsafe(); - - protected VMAdapter() { - } - - public MetaAccessProvider getRuntime() { - return Graal.getRuntime().getCapability(MetaAccessProvider.class); - } - - public void monitorEnter(Object value) { - nullCheck(value); - unsafe.monitorEnter(value); - } - - public void monitorExit(Object value) { - nullCheck(value); - unsafe.monitorExit(value); - } - - public Object newObject(ResolvedJavaType type) throws InstantiationException { - return unsafe.allocateInstance(type.toJava()); - } - - public Object getField(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getObjectVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getObject(resolveBase(base, field), offset); - } - } - - public int getFieldInt(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getIntVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getInt(resolveBase(base, field), offset); - } - } - - public long getFieldLong(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getLongVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getLong(resolveBase(base, field), offset); - } - } - - public double getFieldDouble(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getDoubleVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getDouble(resolveBase(base, field), offset); - } - } - - public float getFieldFloat(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getFloatVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getFloat(resolveBase(base, field), offset); - } - } - - public void setField(Object value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putObjectVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putObject(resolveBase(base, field), offset, value); - } - } - - public void setFieldInt(int value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putIntVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putInt(resolveBase(base, field), offset, value); - } - } - - - public void setFieldFloat(float value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putFloatVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putFloat(resolveBase(base, field), offset, value); - } - } - - public void setFieldDouble(double value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putDouble(resolveBase(base, field), offset, value); - } - } - - public void setFieldLong(long value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putDouble(resolveBase(base, field), offset, value); - } - } - - public byte getArrayByte(long index, Object array) { - checkArray(array, index); - return unsafe.getByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index); - } - - public char getArrayChar(long index, Object array) { - checkArray(array, index); - return unsafe.getChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index); - } - - public short getArrayShort(long index, Object array) { - checkArray(array, index); - return unsafe.getShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index); - } - - public int getArrayInt(long index, Object array) { - checkArray(array, index); - return unsafe.getInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index); - } - - public long getArrayLong(long index, Object array) { - checkArray(array, index); - return unsafe.getLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index); - } - - public double getArrayDouble(long index, Object array) { - checkArray(array, index); - return unsafe.getDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index); - } - - public float getArrayFloat(long index, Object array) { - checkArray(array, index); - return unsafe.getFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index); - } - - public Object getArrayObject(long index, Object array) { - checkArray(array, index); - return unsafe.getObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index); - } - - public void setArrayByte(byte value, long index, Object array) { - checkArray(array, index); - if (array instanceof boolean[]) { - checkArrayType(array, boolean.class); - } else { - checkArrayType(array, byte.class); - } - unsafe.putByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index, value); - } - - public void setArrayChar(char value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, char.class); - unsafe.putChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index, value); - } - - public void setArrayShort(short value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, short.class); - unsafe.putShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index, value); - } - - public void setArrayInt(int value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, int.class); - unsafe.putInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index, value); - } - - public void setArrayLong(long value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, long.class); - unsafe.putLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index, value); - } - - public void setArrayFloat(float value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, float.class); - unsafe.putFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index, value); - } - - public void setArrayDouble(double value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, double.class); - unsafe.putDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index, value); - } - - public void setArrayObject(Object value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, value != null ? value.getClass() : null); - unsafe.putObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index, value); - } - - private static void nullCheck(Object value) { - if (value == null) { - throw new NullPointerException(); - } - } - - private void checkArrayType(Object array, Class arrayType) { - if (arrayType == null) { - return; - } - ResolvedJavaType type = getRuntime().getResolvedJavaType(array.getClass()).componentType(); - if (!type.toJava().isAssignableFrom(arrayType)) { - throw new ArrayStoreException(arrayType.getName()); - } - } - - private void checkArray(Object array, long index) { - nullCheck(array); - ResolvedJavaType type = getRuntime().getResolvedJavaType(array.getClass()); - if (!type.isArrayClass()) { - throw new ArrayStoreException(array.getClass().getName()); - } - if (index < 0 || index >= arrayLength(array)) { - throw new ArrayIndexOutOfBoundsException((int) index); - } - } - - private static int arrayLength(Object array) { - assert array != null; - return Array.getLength(array); - } - - private static boolean isVolatile(ResolvedJavaField field) { - return Modifier.isVolatile(field.accessFlags()); - } - - private static long resolveOffset(ResolvedJavaField field) { - return ((HotSpotResolvedJavaField) field).offset(); - } - - private static Object resolveBase(Object base, ResolvedJavaField field) { - Object accessorBase = base; - if (accessorBase == null) { - accessorBase = field.holder().toJava(); - } - return accessorBase; - } - - private static Unsafe loadUnsafe() { - try { - return Unsafe.getUnsafe(); - } catch (SecurityException e) { - } - try { - Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafeInstance.setAccessible(true); - return (Unsafe) theUnsafeInstance.get(Unsafe.class); - } catch (Exception e) { - throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); - } - } - - private static final VMAdapter instance = new VMAdapter(); - public static VMAdapter getInstance() { - return instance; - } - - -} diff -r 30876d0bb92d -r 99e186e7ad62 src/cpu/x86/vm/jniTypes_x86.hpp --- a/src/cpu/x86/vm/jniTypes_x86.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/cpu/x86/vm/jniTypes_x86.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -127,6 +127,12 @@ static inline oop get_obj (intptr_t *from) { return *(oop *) from; } static inline jfloat get_float (intptr_t *from) { return *(jfloat *) from; } static inline jdouble get_double(intptr_t *from) { return *(jdouble *)(from + _JNI_SLOT_OFFSET); } + + static inline jint get_int (intptr_t *from, int& pos) { return get_int(from + pos++); } + static inline jlong get_long (intptr_t *from, int& pos) { return get_long(from + pos); pos += 2; } + static inline oop get_obj (intptr_t *from, int& pos) { return get_obj(from + pos++); } + static inline jfloat get_float (intptr_t *from, int& pos) { return get_float(from + pos++); } + static inline jdouble get_double(intptr_t *from, int& pos) { return get_double(from + pos); pos += 2; } #undef _JNI_SLOT_OFFSET }; diff -r 30876d0bb92d -r 99e186e7ad62 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -1340,7 +1340,7 @@ methodOopDesc::invocation_counter_offset() + InvocationCounter::counter_offset()); const Address access_flags(rbx, methodOopDesc::access_flags_offset()); - + // get parameter size (always needed) __ load_unsigned_short(rcx, size_of_parameters); diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/classfile/javaClasses.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -255,6 +255,7 @@ public: // Instance creation static oop create(); + static int java_thread_offset_in_bytes() { return _eetop_offset; } // Returns the JavaThread associated with the thread obj static JavaThread* thread(oop java_thread); // Set JavaThread for instance diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -352,6 +352,10 @@ template(callbackInternal_name, "callbackInternal") \ template(callback_signature, "(Ljava/lang/Object;)Ljava/lang/Object;") \ template(MethodInvalidatedException, "com/oracle/graal/api/meta/InstalledCode$MethodInvalidatedException") \ + /* graal.api.interpreter */ \ + template(com_oracle_graal_api_interpreter_Interpreter, "com/oracle/graal/api/interpreter/Interpreter") \ + template(interpreter_execute_name, "execute") \ + template(interpreter_execute_signature, "(Lcom/oracle/graal/api/meta/ResolvedJavaMethod;[Ljava/lang/Object;)Ljava/lang/Object;") \ \ \ /* common method and field names */ \ diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalCodeInstaller.hpp --- a/src/share/vm/graal/graalCodeInstaller.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -21,6 +21,9 @@ * questions. */ +#ifndef SHARE_VM_GRAAL_GRAAL_CODE_INSTALLER_HPP +#define SHARE_VM_GRAAL_GRAAL_CODE_INSTALLER_HPP + /* * This class handles the conversion from a InstalledCode to a CodeBlob or an nmethod. */ @@ -112,3 +115,4 @@ }; +#endif // SHARE_VM_GRAAL_GRAAL_CODE_INSTALLER_HPP diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalCompiler.hpp --- a/src/share/vm/graal/graalCompiler.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalCompiler.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -21,6 +21,9 @@ * questions. */ +#ifndef SHARE_VM_GRAAL_GRAAL_COMPILER_HPP +#define SHARE_VM_GRAAL_GRAAL_COMPILER_HPP + #include "compiler/abstractCompiler.hpp" #define LEAF_GRAPH_ARRAY_SIZE (8192) @@ -110,5 +113,4 @@ #define TRACE_graal_4 if (!(TraceGraal >= 4 && (tty->print(" TraceGraal-4: "), true))) ; else tty->print_cr #define TRACE_graal_5 if (!(TraceGraal >= 5 && (tty->print(" TraceGraal-5: "), true))) ; else tty->print_cr - - +#endif // SHARE_VM_GRAAL_GRAAL_COMPILER_HPP diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -802,7 +802,7 @@ set_int(env, config, "instanceHeaderPrototypeOffset", in_bytes(Klass::prototype_header_offset())); set_int(env, config, "threadExceptionOopOffset", in_bytes(JavaThread::exception_oop_offset())); set_int(env, config, "threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset())); - set_int(env, config, "threadMultiNewArrayStorage", in_bytes(JavaThread::graal_multinewarray_storage_offset())); + set_int(env, config, "threadMultiNewArrayStorageOffset", in_bytes(JavaThread::graal_multinewarray_storage_offset())); set_int(env, config, "classMirrorOffset", in_bytes(Klass::java_mirror_offset())); set_int(env, config, "methodDataOopDataOffset", in_bytes(methodDataOopDesc::data_offset())); @@ -966,48 +966,6 @@ return JNIHandles::make_local(element); } -class JavaArgumentPusher : public SignatureIterator { - protected: - JavaCallArguments* _jca; - arrayOop _args; - int _index; - - oop next_arg(BasicType expectedType) { - assert(_index < _args->length(), "out of bounds"); - oop arg = ((oop*) _args->base(T_OBJECT))[_index++]; - assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); - return arg; - } - - public: - JavaArgumentPusher(Symbol* signature, JavaCallArguments* jca, arrayOop args, bool is_static) : SignatureIterator(signature) { - this->_return_type = T_ILLEGAL; - _jca = jca; - _index = 0; - _args = args; - if (!is_static) { - _jca->push_oop(next_arg(T_OBJECT)); - } - iterate(); - assert(_index == args->length(), "arg count mismatch with signature"); - } - - inline void do_bool() { if (!is_return_type()) _jca->push_int(next_arg(T_BOOLEAN)->bool_field(java_lang_boxing_object::value_offset_in_bytes(T_BOOLEAN))); } - inline void do_char() { if (!is_return_type()) _jca->push_int(next_arg(T_CHAR)->char_field(java_lang_boxing_object::value_offset_in_bytes(T_CHAR))); } - inline void do_short() { if (!is_return_type()) _jca->push_int(next_arg(T_SHORT)->short_field(java_lang_boxing_object::value_offset_in_bytes(T_SHORT))); } - inline void do_byte() { if (!is_return_type()) _jca->push_int(next_arg(T_BYTE)->byte_field(java_lang_boxing_object::value_offset_in_bytes(T_BYTE))); } - inline void do_int() { if (!is_return_type()) _jca->push_int(next_arg(T_INT)->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT))); } - - inline void do_long() { if (!is_return_type()) _jca->push_long(next_arg(T_LONG)->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG))); } - inline void do_float() { if (!is_return_type()) _jca->push_float(next_arg(T_FLOAT)->float_field(java_lang_boxing_object::value_offset_in_bytes(T_FLOAT))); } - inline void do_double() { if (!is_return_type()) _jca->push_double(next_arg(T_DOUBLE)->double_field(java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE))); } - - inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); } - inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } - inline void do_array(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } - inline void do_void() { } -}; - // public Object executeCompiledMethodVarargs(HotSpotCompiledMethod method, Object... args); JNIEXPORT jobject JNICALL Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_executeCompiledMethodVarargs(JNIEnv *env, jobject, jobject method, jobject args) { TRACE_graal_3("CompilerToVM::executeCompiledMethod"); @@ -1021,7 +979,7 @@ Symbol* signature = mh->signature(); JavaCallArguments jca; - JavaArgumentPusher jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); + JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); JavaValue result(jap.get_ret_type()); nmethod* nm = (nmethod*) HotSpotCompiledMethod::nmethod(method); diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalCompilerToVM.hpp --- a/src/share/vm/graal/graalCompilerToVM.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -21,13 +21,59 @@ * questions. */ +#ifndef SHARE_VM_GRAAL_GRAAL_COMPILER_TO_VM_HPP +#define SHARE_VM_GRAAL_GRAAL_COMPILER_TO_VM_HPP + #include "prims/jni.h" extern JNINativeMethod CompilerToVM_methods[]; int CompilerToVM_methods_count(); +methodOop getMethodFromHotSpotMethod(jobject hotspotMethod); methodOop getMethodFromHotSpotMethod(oop hotspotMethod); +class JavaArgumentUnboxer : public SignatureIterator { + protected: + JavaCallArguments* _jca; + arrayOop _args; + int _index; + + oop next_arg(BasicType expectedType) { + assert(_index < _args->length(), "out of bounds"); + oop arg = ((oop*) _args->base(T_OBJECT))[_index++]; + assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); + return arg; + } + + public: + JavaArgumentUnboxer(Symbol* signature, JavaCallArguments* jca, arrayOop args, bool is_static) : SignatureIterator(signature) { + this->_return_type = T_ILLEGAL; + _jca = jca; + _index = 0; + _args = args; + if (!is_static) { + _jca->push_oop(next_arg(T_OBJECT)); + } + iterate(); + assert(_index == args->length(), "arg count mismatch with signature"); + } + + inline void do_bool() { if (!is_return_type()) _jca->push_int(next_arg(T_BOOLEAN)->bool_field(java_lang_boxing_object::value_offset_in_bytes(T_BOOLEAN))); } + inline void do_char() { if (!is_return_type()) _jca->push_int(next_arg(T_CHAR)->char_field(java_lang_boxing_object::value_offset_in_bytes(T_CHAR))); } + inline void do_short() { if (!is_return_type()) _jca->push_int(next_arg(T_SHORT)->short_field(java_lang_boxing_object::value_offset_in_bytes(T_SHORT))); } + inline void do_byte() { if (!is_return_type()) _jca->push_int(next_arg(T_BYTE)->byte_field(java_lang_boxing_object::value_offset_in_bytes(T_BYTE))); } + inline void do_int() { if (!is_return_type()) _jca->push_int(next_arg(T_INT)->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT))); } + + inline void do_long() { if (!is_return_type()) _jca->push_long(next_arg(T_LONG)->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG))); } + inline void do_float() { if (!is_return_type()) _jca->push_float(next_arg(T_FLOAT)->float_field(java_lang_boxing_object::value_offset_in_bytes(T_FLOAT))); } + inline void do_double() { if (!is_return_type()) _jca->push_double(next_arg(T_DOUBLE)->double_field(java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE))); } + + inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_array(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_void() { } +}; + // nothing here - no need to define the jni method implementations in a header file - +#endif // SHARE_VM_GRAAL_GRAAL_COMPILER_TO_VM_HPP diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalEnv.hpp --- a/src/share/vm/graal/graalEnv.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalEnv.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -139,4 +139,3 @@ }; #endif // SHARE_VM_GRAAL_GRAALENV_HPP - diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalInterpreterToVM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/graal/graalInterpreterToVM.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011, 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. + * + * 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. + */ + +#include "precompiled.hpp" +#include "prims/jni.h" +#include "graal/graalInterpreterToVM.hpp" +#include "graal/graalCompiler.hpp" +#include "graal/graalCompilerToVM.hpp" + +#ifdef HIGH_LEVEL_INTERPRETER + +// public Object invoke(HotSpotResolvedJavaMethod method, boolean highLevel, Object... args); +JNIEXPORT jobject JNICALL Java_com_oracle_graal_hotspot_HotSpotRuntimeInterpreterInterface_invoke(JNIEnv *env, jobject, jobject method, jobject args) { + TRACE_graal_3("InterpreterToVM::invoke"); + + VM_ENTRY_MARK; + HandleMark hm; + + assert(method != NULL, "just checking"); + assert(thread->is_Java_thread(), "must be"); + methodHandle mh = getMethodFromHotSpotMethod(method); + + JavaCallArguments jca; + JavaArgumentUnboxer jap(mh->signature(), &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); + +#ifndef PRODUCT + if (PrintHighLevelInterpreterVMTransitions) { + ResourceMark rm; + tty->print_cr("High level interpreter -> VM (%s)", mh->name_and_sig_as_C_string()); + } +#endif + + JavaValue result(jap.get_ret_type()); + thread->set_high_level_interpreter_in_vm(true); + JavaCalls::call(&result, mh, &jca, THREAD); + thread->set_high_level_interpreter_in_vm(false); + +#ifndef PRODUCT + if (PrintHighLevelInterpreterVMTransitions) { + ResourceMark rm; + tty->print_cr("VM (%s) -> high level interpreter", mh->name_and_sig_as_C_string()); + } +#endif + + if (thread->has_pending_exception()) { + return NULL; + } + + if (jap.get_ret_type() == T_VOID) { + return NULL; + } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { + return JNIHandles::make_local((oop) result.get_jobject()); + } else { + oop o = java_lang_boxing_object::create(jap.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL); + return JNIHandles::make_local(o); + } +} + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(Java_com_oracle_graal_hotspot_HotSpotRuntimeInterpreterInterface_##f)) + +#define RESOLVED_METHOD "Lcom/oracle/graal/api/meta/ResolvedJavaMethod;" +#define OBJECT "Ljava/lang/Object;" + +JNINativeMethod InterpreterToVM_methods[] = { + {CC"invoke", CC"("RESOLVED_METHOD "["OBJECT")"OBJECT, FN_PTR(invoke)} +}; + +int InterpreterToVM_methods_count() { + return sizeof(InterpreterToVM_methods) / sizeof(JNINativeMethod); +} + +#endif // HIGH_LEVEL_INTERPRETER diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalInterpreterToVM.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/graal/graalInterpreterToVM.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +#ifdef HIGH_LEVEL_INTERPRETER +#ifndef SHARE_VM_GRAAL_GRAAL_INTERPRETER_TO_VM_HPP +#define SHARE_VM_GRAAL_GRAAL_INTERPRETER_TO_VM_HPP + +#include "prims/jni.h" + +extern JNINativeMethod InterpreterToVM_methods[]; +int InterpreterToVM_methods_count(); + +// nothing here - no need to define the jni method implementations in a header file + +#endif // SHARE_VM_GRAAL_GRAAL_INTERPRETER_TO_VM_HPP +#endif // HIGH_LEVEL_INTERPRETER diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -21,6 +21,9 @@ * questions. */ +#ifndef SHARE_VM_GRAAL_GRAAL_JAVA_ACCESS_HPP +#define SHARE_VM_GRAAL_GRAAL_JAVA_ACCESS_HPP + void graal_compute_offsets(); #include "classfile/systemDictionary.hpp" @@ -294,3 +297,5 @@ #undef STATIC_OOP_FIELD void compute_offset(int &dest_offset, klassOop klass_oop, const char* name, const char* signature, bool static_field); + +#endif // SHARE_VM_GRAAL_GRAAL_JAVA_ACCESS_HPP diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalRuntime.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -27,5 +27,6 @@ // JVM_InitializeGraalRuntime JVM_ENTRY(jobject, JVM_InitializeGraalRuntime(JNIEnv *env, jclass graalclass)) + VMToCompiler::compilerInstance(); return VMToCompiler::compilerPermObject(); JVM_END \ No newline at end of file diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalRuntime.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -21,6 +21,9 @@ * questions. */ +#ifndef SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP +#define SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP + class GraalRuntime : public AllStatic { private: @@ -29,4 +32,6 @@ public: static jobject instance() { return _runtimeObject; } -}; \ No newline at end of file +}; + +#endif // SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalVMToCompiler.hpp --- a/src/share/vm/graal/graalVMToCompiler.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalVMToCompiler.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -21,6 +21,9 @@ * questions. */ +#ifndef SHARE_VM_GRAAL_GRAAL_VM_TO_COMPILER_HPP +#define SHARE_VM_GRAAL_GRAAL_VM_TO_COMPILER_HPP + #include "memory/allocation.hpp" #include "oops/oop.hpp" #include "runtime/handles.hpp" @@ -122,3 +125,4 @@ } } +#endif // SHARE_VM_GRAAL_GRAAL_VM_TO_COMPILER_HPP diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalVMToInterpreter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/graal/graalVMToInterpreter.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +#include "precompiled.hpp" +#include "graal/graalVMToInterpreter.hpp" +#include "graal/graalInterpreterToVM.hpp" +#include "classfile/systemDictionary.hpp" +#include "classfile/vmSymbols.hpp" +#include "graal/graalCompiler.hpp" + +#ifdef HIGH_LEVEL_INTERPRETER + +// those are *global* handles +jobject VMToInterpreter::_interpreterPermObject = NULL; +jobject VMToInterpreter::_interpreterPermKlass = NULL; + +class JavaArgumentBoxer : public SignatureIterator { + protected: + JavaCallArguments* _args; + Thread* _thread; + objArrayHandle _obj_array; + int _index; + int _position; + + public: + JavaArgumentBoxer(Symbol* signature, objArrayHandle obj_array, JavaCallArguments* args, bool is_static, TRAPS) : SignatureIterator(signature) { + _obj_array = obj_array; + _args = args; + _index = _position = 0; + _thread = THREAD; + if (!is_static) { + push(next_object(T_OBJECT)); + } + iterate(); + assert(_index == _obj_array->length(), "arg count mismatch with signature"); + } + + inline void do_bool() { + if (!is_return_type()) { + jvalue value; + value.z = (jboolean)_args->get_int(_position); + push(java_lang_boxing_object::create(T_BOOLEAN, &value, _thread)); + } + } + inline void do_char() { + if (!is_return_type()) { + jvalue value; + value.c = (jchar)_args->get_int(_position); + push(java_lang_boxing_object::create(T_CHAR, &value, _thread)); + } + } + inline void do_short() { + if (!is_return_type()) { + jvalue value; + value.s = (jshort)_args->get_int(_position); + push(java_lang_boxing_object::create(T_SHORT, &value, _thread)); + } + } + inline void do_byte() { + if (!is_return_type()) { + jvalue value; + value.b = (jbyte)_args->get_int(_position); + push(java_lang_boxing_object::create(T_BYTE, &value, _thread)); + } + } + inline void do_int() { + if (!is_return_type()) { + jvalue value; + value.i = (jint)_args->get_int(_position); + push(java_lang_boxing_object::create(T_INT, &value, _thread)); + } + } + + inline void do_long() { + if (!is_return_type()) { + jvalue value; + value.j = (jlong)_args->get_long(_position); + push(java_lang_boxing_object::create(T_LONG, &value, _thread)); + } + } + + inline void do_float() { + if (!is_return_type()) { + jvalue value; + value.f = (jfloat)_args->get_float(_position); + push(java_lang_boxing_object::create(T_FLOAT, &value, _thread)); + } + } + + inline void do_double() { + if (!is_return_type()) { + jvalue value; + value.d = (jdouble)_args->get_double(_position); + push(java_lang_boxing_object::create(T_DOUBLE, &value, _thread)); + } + } + + inline void do_object(int begin, int end) { if (!is_return_type()) push(next_object(T_OBJECT)); } + inline void do_array(int begin, int end) { if (!is_return_type()) push(next_object(T_ARRAY)); } + inline void do_void() { } + + inline oop next_object(BasicType type) { + assert(type == T_OBJECT || type == T_ARRAY, "must be"); + return *(_args->get_raw_oop(_position)); + } + + inline void push(oop obj) { + _obj_array->obj_at_put(_index, obj); + _index++; + } +}; + +bool VMToInterpreter::allocate_interpreter(const char* interpreter_class_name, const char* interpreter_arguments, TRAPS) { + assert(_interpreterPermObject == NULL && _interpreterPermKlass == NULL, "no need to allocate twice"); + + HandleMark hm; + // load the interpreter class using its fully qualified class name + Symbol* class_name = SymbolTable::lookup(interpreter_class_name, (int)strlen(interpreter_class_name), CHECK_false); + instanceKlassHandle interpreter_klass = SystemDictionary::resolve_or_null(class_name, SystemDictionary::java_system_loader(), NULL, CHECK_false); + if (interpreter_klass.is_null()) { + tty->print_cr("Could not load HighLevelInterpreterClass '%s'", interpreter_class_name); + return false; + } + + // allocate an interpreter instance + interpreter_klass->initialize(CHECK_false); + instanceHandle interpreter_instance = interpreter_klass->allocate_instance_handle(CHECK_false); + + // initialize the interpreter instance + Handle args; + if (interpreter_arguments != NULL) { + args = java_lang_String::create_from_platform_dependent_str(interpreter_arguments, CHECK_false); + } + + JavaValue result(T_BOOLEAN); + JavaCalls::call_virtual(&result, interpreter_instance, interpreter_klass, vmSymbols::initialize_name(), vmSymbols::setOption_signature(), args, CHECK_false); + if (result.get_jboolean() != JNI_TRUE) { + tty->print_cr("Could not invoke '%s::initialize(String)'", interpreter_class_name); + return false; + } + + // store the instance globally and keep it alive + _interpreterPermObject = JNIHandles::make_global(interpreter_instance); + _interpreterPermKlass = JNIHandles::make_global(interpreter_klass); + + // register the native functions that are needed by the interpreter + { + assert(THREAD->is_Java_thread(), "must be"); + JavaThread* thread = (JavaThread*) THREAD; + ThreadToNativeFromVM trans(thread); + JNIEnv *env = thread->jni_environment(); + jclass klass = env->FindClass("com/oracle/graal/hotspot/HotSpotRuntimeInterpreterInterface"); + if (klass == NULL) { + tty->print_cr("Could not find class HotSpotRuntimeInterpreterInterface"); + return false; + } + env->RegisterNatives(klass, InterpreterToVM_methods, InterpreterToVM_methods_count()); + if (thread->has_pending_exception()) { + tty->print_cr("Could not register HotSpotRuntimeInterpreterInterface native methods"); + return false; + } + } + + return true; +} + +Handle VMToInterpreter::interpreter_instance() { + return Handle(JNIHandles::resolve_non_null(_interpreterPermObject)); +} + +KlassHandle VMToInterpreter::interpreter_klass() { + return KlassHandle(JNIHandles::resolve_non_null(_interpreterPermKlass)); +} + +void VMToInterpreter::execute(JavaValue* result, methodHandle* m, JavaCallArguments* args, BasicType expected_result_type, TRAPS) { + assert(interpreter_instance().not_null(), "must be allocated before the first call"); + assert(THREAD->is_Java_thread(), "must be"); + assert(m != NULL, "must be"); + assert(args != NULL, "must be"); + + JavaThread* thread = (JavaThread*)THREAD; + methodHandle method = *m; + int parameter_count = ArgumentCount(method->signature()).size() + (method->is_static() ? 0 : 1); + objArrayHandle args_array = oopFactory::new_objArray(SystemDictionary::Object_klass(), parameter_count, CHECK); + JavaArgumentBoxer jab(method->signature(), args_array, args, method->is_static(), thread); + Handle hotspot_method = GraalCompiler::createHotSpotResolvedJavaMethod(method, CHECK); + + JavaValue boxed_result(T_OBJECT); + JavaCallArguments boxed_args; + boxed_args.set_receiver(interpreter_instance()); + boxed_args.push_oop(hotspot_method); + boxed_args.push_oop(args_array); + +#ifndef PRODUCT + if (PrintHighLevelInterpreterVMTransitions) { + ResourceMark m; + tty->print_cr("VM -> high level interpreter (%s)", method->name_and_sig_as_C_string()); + } +#endif + + thread->set_high_level_interpreter_in_vm(false); + JavaCalls::call_virtual(&boxed_result, interpreter_klass(), vmSymbols::interpreter_execute_name(), vmSymbols::interpreter_execute_signature(), &boxed_args, thread); + thread->set_high_level_interpreter_in_vm(true); + +#ifndef PRODUCT + if (PrintHighLevelInterpreterVMTransitions) { + ResourceMark m; + tty->print_cr("High level interpreter (%s) -> VM", method->name_and_sig_as_C_string()); + } +#endif + + if (HAS_PENDING_EXCEPTION) { + return; + } + + // unbox the result if necessary + if (is_java_primitive(expected_result_type)) { + unbox_primitive(&boxed_result, result); + } else if (expected_result_type == T_OBJECT || expected_result_type == T_ARRAY) { + result->set_jobject(result->get_jobject()); + } +} + +void VMToInterpreter::unbox_primitive(JavaValue* boxed, JavaValue* result) { + oop box = JNIHandles::resolve(boxed->get_jobject()); + + jvalue value; + BasicType type = java_lang_boxing_object::get_value(box, &value); + switch (type) { + case T_BOOLEAN: + result->set_jint(value.z); + break; + case T_CHAR: + result->set_jint(value.c); + break; + case T_FLOAT: + result->set_jfloat(value.f); + break; + case T_DOUBLE: + result->set_jdouble(value.d); + break; + case T_BYTE: + result->set_jint(value.b); + break; + case T_SHORT: + result->set_jint(value.s); + break; + case T_INT: + result->set_jint(value.i); + break; + case T_LONG: + result->set_jlong(value.j); + break; + default: + ShouldNotReachHere(); + break; + } +} + +#endif // HIGH_LEVEL_INTERPRETER diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalVMToInterpreter.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/graal/graalVMToInterpreter.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +#include "memory/allocation.hpp" +#include "oops/oop.hpp" +#include "runtime/handles.hpp" +#include "runtime/thread.hpp" +#include "classfile/javaClasses.hpp" +#include "runtime/jniHandles.hpp" +#include "runtime/javaCalls.hpp" + +#ifdef HIGH_LEVEL_INTERPRETER +#ifndef SHARE_VM_GRAAL_GRAAL_VM_TO_INTERPRETER_HPP +#define SHARE_VM_GRAAL_GRAAL_VM_TO_INTERPRETER_HPP + +class VMToInterpreter : public AllStatic { + +private: + static jobject _interpreterPermObject; + static jobject _interpreterPermKlass; + + static Handle interpreter_instance(); + static KlassHandle interpreter_klass(); + static void unbox_primitive(JavaValue* boxed, JavaValue* result); + +public: + static bool allocate_interpreter(const char* interpreter_class_name, const char* interpreter_arguments, TRAPS); + + // invokes the interpreter method execute(ResolvedJavaMethod method, Object... arguments) + static void execute(JavaValue* result, methodHandle* m, JavaCallArguments* args, BasicType expected_result_type, TRAPS); +}; + +#endif // SHARE_VM_GRAAL_GRAAL_VM_TO_INTERPRETER_HPP +#endif // HIGH_LEVEL_INTERPRETER diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/graal/graalVmIds.hpp --- a/src/share/vm/graal/graalVmIds.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/graal/graalVmIds.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -21,6 +21,9 @@ * questions. */ +#ifndef SHARE_VM_GRAAL_GRAAL_VM_IDS_HPP +#define SHARE_VM_GRAAL_GRAAL_VM_IDS_HPP + #include "memory/allocation.hpp" #include "utilities/growableArray.hpp" #include "oops/oop.hpp" @@ -80,3 +83,4 @@ return obj->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG)); } +#endif // SHARE_VM_GRAAL_GRAAL_VM_IDS_HPP diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/prims/jni.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -32,6 +32,9 @@ #ifdef GRAAL #include "graal/graalCompiler.hpp" #endif +#ifdef HIGH_LEVEL_INTERPRETER +#include "graal/graalVMToInterpreter.hpp" +#endif #ifndef SERIALGC #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #endif // SERIALGC @@ -1317,6 +1320,7 @@ } +static bool first_time_InvokeMain = true; static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) { methodHandle method(THREAD, JNIHandles::resolve_jmethod_id(method_id)); @@ -1325,6 +1329,8 @@ // the jni parser ResourceMark rm(THREAD); int number_of_parameters = method->size_of_parameters(); + + // Invoke the method. Result is returned as oop. JavaCallArguments java_args(number_of_parameters); args->set_java_argument_object(&java_args); @@ -1332,16 +1338,35 @@ // Fill out JavaCallArguments object args->iterate( Fingerprinter(method).fingerprint() ); - // Initialize result type + // Initialize result type (must be done after args->iterate()) result->set_type(args->get_ret_type()); - // Invoke the method. Result is returned as oop. +#ifdef HIGH_LEVEL_INTERPRETER + // TODO (chaeubl): this is quite a hack. The launcher should take care about that instead. + bool invoked_main_method = false; + if (HighLevelInterpreterClass != NULL && first_time_InvokeMain && method->name() == vmSymbols::main_name() && method->result_type() == T_VOID) { + assert(THREAD->is_Java_thread(), "other threads must not call into java"); + JavaThread* thread = (JavaThread*)THREAD; + first_time_InvokeMain = false; + invoked_main_method = true; + thread->set_high_level_interpreter_in_vm(true); + } +#endif + JavaCalls::call(result, method, &java_args, CHECK); // Convert result if (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY) { result->set_jobject(JNIHandles::make_local(env, (oop) result->get_jobject())); } + +#ifdef HIGH_LEVEL_INTERPRETER + if (invoked_main_method) { + assert(THREAD->is_Java_thread(), "other threads must not call into java"); + JavaThread* thread = (JavaThread*)THREAD; + thread->set_high_level_interpreter_in_vm(false); + } +#endif } @@ -5144,6 +5169,16 @@ compiler->initialize(); #endif +#ifdef HIGH_LEVEL_INTERPRETER + if (HighLevelInterpreterClass != NULL) { + bool result = VMToInterpreter::allocate_interpreter(HighLevelInterpreterClass, HighLevelInterpreterArguments, thread); + if (!result) { + vm_abort(false); + return JNI_ERR; + } + } +#endif + // Tracks the time application was running before GC RuntimeService::record_application_start(); diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -1291,6 +1291,7 @@ if (TraceDeoptimization) { tty->print_cr(" bci=%d pc=%d, relative_pc=%d, method=%s", trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name()->as_C_string()); +#ifdef GRAAL if (thread->graal_deopt_info() != NULL) { oop deopt_info = thread->graal_deopt_info(); if (java_lang_String::is_instance(deopt_info)) { @@ -1303,6 +1304,7 @@ } thread->set_graal_deopt_info(NULL); } +#endif } methodHandle trap_method = trap_scope->method(); diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/runtime/globals.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -631,6 +631,15 @@ develop(bool, InlineAtomicLong, true, \ "inline sun.misc.AtomicLong") \ \ + product(ccstr, HighLevelInterpreterClass, NULL, \ + "fully qualified class name of the high-level interpreter") \ + \ + product(ccstr, HighLevelInterpreterArguments, NULL, \ + "arguments that are passed to the high-level interpreter") \ + \ + notproduct(bool, PrintHighLevelInterpreterVMTransitions, false, \ + "print transitions between VM and high-level interpreter") \ + \ develop(bool, InlineThreadNatives, true, \ "inline Thread.currentThread, etc") \ \ diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/runtime/javaCalls.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -39,6 +39,9 @@ #include "runtime/mutexLocker.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#ifdef HIGH_LEVEL_INTERPRETER +# include "graal/graalVMToInterpreter.hpp" +#endif #ifdef TARGET_OS_FAMILY_linux # include "thread_linux.inline.hpp" #endif @@ -437,7 +440,13 @@ ShouldNotReachHere(); #endif } - + +#ifdef HIGH_LEVEL_INTERPRETER + if (thread->high_level_interpreter_in_vm() && !method->is_native() && Interpreter::contains(entry_point)) { + assert(nm == NULL || !nm->is_alive(), "otherwise nm should be invoked"); + VMToInterpreter::execute(result, m, args, result->get_type(), thread); + } else +#endif // do call { JavaCallWrapper link(method, receiver, result, CHECK); { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner @@ -473,7 +482,6 @@ } } - //-------------------------------------------------------------------------------------- // Implementation of JavaCallArguments diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/runtime/javaCalls.hpp --- a/src/share/vm/runtime/javaCalls.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/runtime/javaCalls.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -159,6 +159,12 @@ inline void push_float(float f) { _is_oop[_size] = false; JNITypes::put_float(f, _value, _size); } + inline oop* get_raw_oop(int& pos) { return (oop*)JNITypes::get_obj(_value, pos); } + inline jint get_int(int& pos) { return JNITypes::get_int(_value, pos); } + inline jdouble get_double(int& pos) { return JNITypes::get_double(_value, pos); } + inline jlong get_long(int& pos) { return JNITypes::get_long(_value, pos); } + inline jfloat get_float(int& pos) { return JNITypes::get_float(_value, pos); } + // receiver Handle receiver() { assert(_size > 0, "must at least be one argument"); @@ -191,7 +197,7 @@ class JavaCalls: AllStatic { static void call_helper(JavaValue* result, methodHandle* method, nmethod* nm, JavaCallArguments* args, TRAPS); - public: +public: // Optimized Constuctor call static void call_default_constructor(JavaThread* thread, methodHandle method, Handle receiver, TRAPS); diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/runtime/thread.cpp Wed Jul 04 13:55:52 2012 +0200 @@ -1303,8 +1303,13 @@ _in_deopt_handler = 0; _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; +#ifdef GRAAL _graal_deopt_info = NULL; _graal_alternate_call_target = NULL; +#endif +#ifdef HIGH_LEVEL_INTERPRETER + _high_level_interpreter_in_vm = false; +#endif _exception_oop = NULL; _exception_pc = 0; _exception_handler_pc = 0; @@ -2622,7 +2627,9 @@ f->do_oop((oop*) &_threadObj); f->do_oop((oop*) &_vm_result); f->do_oop((oop*) &_vm_result_2); +#ifdef GRAAL f->do_oop((oop*) &_graal_deopt_info); +#endif f->do_oop((oop*) &_exception_oop); f->do_oop((oop*) &_pending_async_exception); diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/runtime/thread.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -866,11 +866,16 @@ private: +#ifdef GRAAL // graal needs some place to put the dimensions - jint graal_multinewarray_storage[256]; + jint _graal_multinewarray_storage[256]; volatile oop _graal_deopt_info; address _graal_alternate_call_target; +#endif +#ifdef HIGH_LEVEL_INTERPRETER + bool _high_level_interpreter_in_vm; +#endif StackGuardState _stack_guard_state; @@ -1234,10 +1239,16 @@ MemRegion deferred_card_mark() const { return _deferred_card_mark; } void set_deferred_card_mark(MemRegion mr) { _deferred_card_mark = mr; } +#ifdef GRAAL oop graal_deopt_info() const { return _graal_deopt_info; } void set_graal_deopt_info(oop o) { _graal_deopt_info = o; } - + void set_graal_alternate_call_target(address a) { _graal_alternate_call_target = a; } +#endif +#ifdef HIGH_LEVEL_INTERPRETER + bool high_level_interpreter_in_vm() { return _high_level_interpreter_in_vm; } + void set_high_level_interpreter_in_vm(bool value) { _high_level_interpreter_in_vm = value; } +#endif // Exception handling for compiled methods oop exception_oop() const { return _exception_oop; } @@ -1318,15 +1329,20 @@ static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state ); } static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc ); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread ); } +#ifdef GRAAL static ByteSize graal_deopt_info_offset() { return byte_offset_of(JavaThread, _graal_deopt_info ); } static ByteSize graal_alternate_call_target_offset() { return byte_offset_of(JavaThread, _graal_alternate_call_target); } + static ByteSize graal_multinewarray_storage_offset() { return byte_offset_of(JavaThread, _graal_multinewarray_storage); } +#endif +#ifdef HIGH_LEVEL_INTERPRETER + static ByteSize high_level_interpreter_in_vm_offset() { return byte_offset_of(JavaThread, _high_level_interpreter_in_vm); } +#endif static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop ); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } static ByteSize stack_guard_state_offset() { return byte_offset_of(JavaThread, _stack_guard_state ); } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags ); } - static ByteSize graal_multinewarray_storage_offset() { return byte_offset_of(JavaThread, graal_multinewarray_storage); } static ByteSize do_not_unlock_if_synchronized_offset() { return byte_offset_of(JavaThread, _do_not_unlock_if_synchronized); } static ByteSize should_post_on_exceptions_flag_offset() { diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/utilities/globalDefinitions.hpp --- a/src/share/vm/utilities/globalDefinitions.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/utilities/globalDefinitions.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -106,9 +106,9 @@ // log2_intptr(sizeof(class JavaThread)) - log2_intptr(64); // see os::set_memory_serialize_page() #ifdef _LP64 -const int SerializePageShiftCount = 5; +const int SerializePageShiftCount = GRAAL_ONLY(5) NOT_GRAAL(4); #else -const int SerializePageShiftCount = 4; +const int SerializePageShiftCount = GRAAL_ONLY(4) NOT_GRAAL(3); #endif // An opaque struct of heap-word width, so that HeapWord* can be a generic diff -r 30876d0bb92d -r 99e186e7ad62 src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Wed Jul 04 13:55:03 2012 +0200 +++ b/src/share/vm/utilities/macros.hpp Wed Jul 04 13:55:52 2012 +0200 @@ -80,7 +80,15 @@ #else #define GRAAL_ONLY(code) #define NOT_GRAAL(code) code -#endif +#endif // GRAAL + +#ifdef HIGH_LEVEL_INTERPRETER +#define HIGH_LEVEL_INTERPRETER_ONLY(code) code +#define NOT_HIGH_LEVEL_INTERPRETER(code) +#else +#define HIGH_LEVEL_INTERPRETER_ONLY(code) +#define NOT_HIGH_LEVEL_INTERPRETER(code) code +#endif // HIGH_LEVEL_INTERPRETER #ifdef TIERED #define TIERED_ONLY(code) code