# HG changeset patch # User Thomas Wuerthinger # Date 1392641321 -3600 # Node ID d68f5d0c97f0ba38779027353bc30dfc25d576d8 # Parent 8df3615355305ac3bc90ca24c41cfd333965e1df# Parent 4eda2fa64da6bd441123621991699479383ea7d0 Merge. diff -r 8df361535530 -r d68f5d0c97f0 CHANGELOG.md --- a/CHANGELOG.md Thu Feb 06 17:41:51 2014 +0100 +++ b/CHANGELOG.md Mon Feb 17 13:48:41 2014 +0100 @@ -1,19 +1,24 @@ # GraalVM Changelog -## Tip +## `tip` +### Graal +* ... -* Graal - * ... -* Truffle - * ... +### Truffle +* ... ## Version 0.1 5-Feb-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/b124e22eb772) -* Graal - * Initial version of a dynamic Java compiler written in Java. - * Support for multiple co-existing GPU backends ([GRAAL-1](https://bugs.openjdk.java.net/browse/GRAAL-1)). - * Fixed a compiler bug when running RuneScape ([Graal-7](https://bugs.openjdk.java.net/browse/GRAAL-7)). - * Bug fixes ([GRAAL-4](https://bugs.openjdk.java.net/browse/GRAAL-4), [GRAAL-5](https://bugs.openjdk.java.net/browse/GRAAL-5)). -* Truffle - * Initial version of a multi-language framework on top of Graal. - * Update of the [Truffle inlining API](http://mail.openjdk.java.net/pipermail/graal-dev/2014-January/001516.html). + +### Graal + +* Initial version of a dynamic Java compiler written in Java. +* Support for multiple co-existing GPU backends ([GRAAL-1](https://bugs.openjdk.java.net/browse/GRAAL-1)). +* Fixed a compiler bug when running RuneScape ([GRAAL-7](https://bugs.openjdk.java.net/browse/GRAAL-7)). +* Bug fixes ([GRAAL-4](https://bugs.openjdk.java.net/browse/GRAAL-4), [GRAAL-5](https://bugs.openjdk.java.net/browse/GRAAL-5)). + +### Truffle + +* Initial version of a multi-language framework on top of Graal. +* Update of the [Truffle Inlining API](http://mail.openjdk.java.net/pipermail/graal-dev/2014-January/001516.html). + diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Mon Feb 17 13:48:41 2014 +0100 @@ -116,6 +116,26 @@ this.numStack = numStack; this.numLocks = numLocks; assert !rethrowException || numStack == 1 : "must have exception on top of the stack"; + assert validateFormat(); + } + + /** + * Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the + * slot following a double word item. This should really be checked in FrameState itself but + * because of Word type rewriting that can't be done. If a frame makes it into this code, then + * could be materialized by the JVM so it must follow the rules. it + */ + private boolean validateFormat() { + for (int i = 0; i < numLocals + numStack; i++) { + if (values[i] != null) { + Kind kind = values[i].getKind(); + if (kind == Kind.Long || kind == Kind.Double) { + assert values.length > i + 1 : String.format("missing second word %s", this); + assert values[i + 1] == null || values[i + 1].getKind() == Kind.Illegal; + } + } + } + return true; } /** diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Mon Feb 17 13:48:41 2014 +0100 @@ -288,6 +288,14 @@ } } + public int getAlignment() { + if (externalData instanceof ConstantData) { + return ((ConstantData) externalData).getAlignment(); + } else { + return 0; + } + } + public String getDataString() { if (inlineData != null) { return inlineData.toString(); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionHandle.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionHandle.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionHandle.java Mon Feb 17 13:48:41 2014 +0100 @@ -23,28 +23,25 @@ package com.oracle.graal.api.code; /** - * The handle of a native foreign function. Use a {@code NativeFunctionHandle} to invoke native - * target functions. - *

- * The user of a {@code NativeFunctionHandle} has to pack the boxed arguments into an - * {@code Object[]} according to the ABI of the target platform (e.g. Unix AMD64 system: - * {@link "http://www.uclibc.org/docs/psABI-x86_64.pdf"}). The {@code NativeFunctionHandle} unboxes - * the arguments and places them into the right location (register / stack) according to the ABI. - *

- * A {@code NativeFunctionHandle} returns the boxed return value of the native target function. The - * boxed value is the return value as specified by the ABI. + * A handle that can be used to {@linkplain #call(Object[]) call} a native function. */ public interface NativeFunctionHandle { /** - * Calls the native foreign function. + * Calls the native function. + *

+ * The caller is responsible for ensuring {@code args} comply with the platform ABI (e.g. Unix AMD64 ABI). If the library + * function has struct parameters, the fields of the struct must be passed as individual + * arguments. * - * @param args the arguments that will be passed to the native foreign function + * @param args the arguments that will be passed to the native function + * @return boxed return value of the function call */ - Object call(Object[] args); + Object call(Object... args); /** - * Returns the installed code of the call stub for the native foreign function call. + * Returns the installed code of the call stub for the native function call. * * @return the installed code of the native call stub */ diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionInterface.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionInterface.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionInterface.java Mon Feb 17 13:48:41 2014 +0100 @@ -23,91 +23,100 @@ package com.oracle.graal.api.code; /** - * Interface to resolve a {@code NativeFunctionHandle} or a {@code NativeFunctionPointer} to a - * native foreign function and a {@code NativeLibraryHandle} of a library. A - * {@code NativeFunctionPointer} wraps the raw function pointer. A {@code NativeFunctionHandle} is a - * callable representation of a native target function in Java. - *

- * To resolve a {@code NativeFunctionHandle}, one has to provide the signature of the native target - * function according to the calling convention of the target platform (e.g. Unix AMD64: - * {@link "http://www.uclibc.org/docs/psABI-x86_64.pdf"}). The signature contains the type (e.g. - * {@code int.class} for a C integer, ( {@code long.class} for a 64bit pointer) of each value, which - * is passed to the native target function. + * Interface to get a {@linkplain NativeFunctionHandle handle} or {@linkplain NativeFunctionPointer + * pointer} to a native function or a {@linkplain NativeLibraryHandle handle} to an open native + * library. */ public interface NativeFunctionInterface { /** - * Resolves and returns a library handle. + * Resolves and returns a handle to an open native library. This method will open the library + * only if it is not already open. * * @param libPath the absolute path to the library * @return the resolved library handle + * @throws UnsatisfiedLinkError if the library could not be found or opened */ NativeLibraryHandle getLibraryHandle(String libPath); /** - * Resolves the {@code NativeFunctionHandle} of a native function that can be called. Use a - * {@code NativeFunctionHandle} to invoke the native target function. + * Determines if the underlying platform/runtime supports the notion of a default library search + * path. For example, on *nix systems, this is typically defined by the {@code LD_LIBRARY_PATH} + * environment variable. + */ + boolean isDefaultLibrarySearchSupported(); + + /** + * Resolves the function pointer {@code NativeFunctionPointer} of a native function. * - * @param libraryHandle the handle to a resolved library - * @param functionName the name of the function to be resolved + * @param libraries the ordered list of libraries to search for the function + * @param name the name of the function to be resolved + * @return a pointer to the native function + * @throws UnsatisfiedLinkError if the function could not be resolved + */ + NativeFunctionPointer getFunctionPointer(NativeLibraryHandle[] libraries, String name); + + /** + * Resolves a function name to a {@linkplain NativeFunctionHandle handle} that can be called + * with a given signature. The signature contains the types of the arguments that will be passed + * to the handle when it is {@linkplain NativeFunctionHandle#call(Object...) called}. + * + * @param library the handle to a resolved library + * @param name the name of the function to be resolved * @param returnType the type of the return value * @param argumentTypes the types of the arguments - * @return the function handle of the native foreign function + * @return the function handle of the native function + * @throws UnsatisfiedLinkError if the function handle could not be resolved */ - NativeFunctionHandle getFunctionHandle(NativeLibraryHandle libraryHandle, String functionName, Class returnType, Class[] argumentTypes); - - /** - * Resolves the {@code NativeFunctionHandle} of a native function that can be called. Use a - * {@code NativeFunctionHandle} to invoke the native target function. - * - * @param functionPointer the function pointer - * @param returnType the type of the return value - * @param argumentTypes the types of the arguments - * @return the function handle of the native foreign function - */ - NativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class returnType, Class[] argumentTypes); + NativeFunctionHandle getFunctionHandle(NativeLibraryHandle library, String name, Class returnType, Class... argumentTypes); /** - * Resolves the function pointer {@code NativeFunctionPointer} of a native function. A - * {@code NativeFunctionPointer} wraps the raw pointer value. + * Resolves a function pointer to a {@linkplain NativeFunctionHandle handle} that can be called + * with a given signature. The signature contains the types of the arguments that will be passed + * to the handle when it is {@linkplain NativeFunctionHandle#call(Object...) called}. * - * @param libraryHandles the handles to a various resolved library, the first library containing - * the method wins - * @param functionName the name of the function to be resolved - * @return the function handle of the native foreign function + * @param functionPointer a function pointer + * @param returnType the type of the return value + * @param argumentTypes the types of the arguments + * @return the function handle of the native function + * @throws UnsatisfiedLinkError the function handle could not be created */ - NativeFunctionPointer getFunctionPointer(NativeLibraryHandle[] libraryHandles, String functionName); + NativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class returnType, Class... argumentTypes); /** - * Resolves the {@code NativeFunctionHandle} of a native function that can be called. Use a - * {@code NativeFunctionHandle} to invoke the native target function. + * Resolves a function name to a {@linkplain NativeFunctionHandle handle} that can be called + * with a given signature. The signature contains the types of the arguments that will be passed + * to the handle when it is {@linkplain NativeFunctionHandle#call(Object...) called}. * - * @param libraryHandles the handles to a various resolved library, the first library containing - * the method wins - * @param functionName the name of the function to be resolved + * @param libraries the ordered list of libraries to search for the function + * @param name the name of the function to be resolved * @param returnType the type of the return value * @param argumentTypes the types of the arguments - * @return the function handle of the native foreign function + * @return the function handle of the native function + * @throws UnsatisfiedLinkError if the function handle could not be created */ - NativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraryHandles, String functionName, Class returnType, Class[] argumentTypes); + NativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraries, String name, Class returnType, Class... argumentTypes); /** - * Resolves the {@code NativeFunctionHandle} of a native function that can be called. Use a - * {@code NativeFunctionHandle} to invoke the native target function. + * Resolves a function name to a {@linkplain NativeFunctionHandle handle} that can be called + * with a given signature. The signature contains the types of the arguments that will be passed + * to the handle when it is {@linkplain NativeFunctionHandle#call(Object...) called}. * - * @param functionName the name of the function to be resolved + * @param name the name of the function to be resolved * @param returnType the type of the return value * @param argumentTypes the types of the arguments - * @return the function handle of the native foreign function + * @return the function handle of the native function + * @throws UnsatisfiedLinkError if default library searching is not + * {@linkplain #isDefaultLibrarySearchSupported() supported} or if the function + * could not be resolved */ - NativeFunctionHandle getFunctionHandle(String functionName, Class returnType, Class[] argumentTypes); + NativeFunctionHandle getFunctionHandle(String name, Class returnType, Class... argumentTypes); /** - * Creates {@code NativeFunctionPointer} from raw value. A {@code NativeFunctionPointer} wraps - * the raw pointer value. + * Creates a {@link NativeFunctionPointer} from a raw value. * - * @param rawValue Raw pointer value - * @return {@code NativeFunctionPointer} of the raw pointer + * @param rawValue raw function pointer + * @return {@code NativeFunctionPointer} for {@code rawValue} */ NativeFunctionPointer getNativeFunctionPointerFromRawValue(long rawValue); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionPointer.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionPointer.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionPointer.java Mon Feb 17 13:48:41 2014 +0100 @@ -23,32 +23,19 @@ package com.oracle.graal.api.code; /** - * Wraps the raw function pointer value. + * An opaque representation of a native function pointer. *

- * Use the {@code NativeFunctionInterface} to resolve a {@code NativeFunctionHandle} of this pointer - * to invoke the native target function. + * Use {@code NativeFunctionInterface#getFunctionHandle(NativeFunctionPointer, Class, Class...)} to + * get a handle enabling the native function to be {@linkplain NativeFunctionHandle#call(Object...) + * called}. */ public interface NativeFunctionPointer { /** - * Returns whether the pointer is valid. - * - * @return true if the pointer is valid - */ - boolean isValid(); - - /** - * Returns function pointer as raw value. - * - * @return raw value of function pointer - */ - long asRawValue(); - - /** * Returns the name of the function. * * @return name of the function */ - String getFunctionName(); + String getName(); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeLibraryHandle.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeLibraryHandle.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeLibraryHandle.java Mon Feb 17 13:48:41 2014 +0100 @@ -23,24 +23,15 @@ package com.oracle.graal.api.code; /** - * The library handle of the native library. - *

- * The {@code NativeFunctionInterface} can use a {@code NativeLibraryHandle} to look up a - * {@code NativeFunctionPointer} or a {@code NativeFunctionHandle} in this library. + * An opaque representation of a native library handle. A handle is obtained via + * {@link NativeFunctionInterface#getLibraryHandle(String)}. A handle is used to resolve a string to + * a {@linkplain NativeFunctionInterface#getFunctionHandle(String, Class, Class...) handle} or + * {@linkplain NativeFunctionInterface#getFunctionPointer(NativeLibraryHandle[], String) pointer}. */ public interface NativeLibraryHandle { - /** - * Returns whether the handle is valid. - * - * @return true if the handle is valid + * Gets a name for this library. This may be the path for the file from which the library was + * loaded. */ - boolean isValid(); - - /** - * Returns function pointer as raw value. - * - * @return raw value of function pointer - */ - long asRawValue(); + String getName(); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java Mon Feb 17 13:48:41 2014 +0100 @@ -86,6 +86,29 @@ return frameRefMap != null && frameRefMap.size() > 0; } + public interface Iterator { + void register(int idx, boolean narrow); + + void stackSlot(int idx, boolean narrow1, boolean narrow2); + } + + public void iterate(Iterator iterator) { + if (hasRegisterRefMap()) { + for (int i = 0; i < registerRefMap.size() / 2; i++) { + if (registerRefMap.get(2 * i)) { + iterator.register(i, registerRefMap.get(2 * i + 1)); + } + } + } + if (hasFrameRefMap()) { + for (int i = 0; i < frameRefMap.size() / 3; i++) { + if (frameRefMap.get(3 * i)) { + iterator.stackSlot(i, frameRefMap.get(3 * i + 1), frameRefMap.get(3 * i + 2)); + } + } + } + } + private static class NumberedRefMapFormatter implements RefMapFormatter { public String formatStackSlot(int frameRefMapIndex) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java --- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java Mon Feb 17 13:48:41 2014 +0100 @@ -290,6 +290,7 @@ "reprofile", "getCompilerStorage", "canBeInlined", + "shouldBeInlined", "getLineNumberTable", "getLocalVariableTable", "isInVirtualMethodTable", diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Mon Feb 17 13:48:41 2014 +0100 @@ -72,12 +72,12 @@ private final Class primitiveJavaClass; private final Class boxedJavaClass; - private Kind(char typeChar, String javaName, boolean isStackInt, Class primitiveJavaClass, Class boxedJavasClass) { + private Kind(char typeChar, String javaName, boolean isStackInt, Class primitiveJavaClass, Class boxedJavaClass) { this.typeChar = typeChar; this.javaName = javaName; this.isStackInt = isStackInt; this.primitiveJavaClass = primitiveJavaClass; - this.boxedJavaClass = boxedJavasClass; + this.boxedJavaClass = boxedJavaClass; assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName()); } @@ -255,19 +255,30 @@ /** * Marker interface for types that should be {@linkplain Kind#format(Object) formatted} with - * their {@link Object#toString()} value. + * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects + * poses a security risk because it can potentially call user code. */ public interface FormatWithToString { } /** + * Classes for which invoking {@link Object#toString()} does not run user code. + */ + private static boolean isToStringSafe(Class c) { + return c == Boolean.class || c == Byte.class || c == Character.class || c == Short.class || c == Integer.class || c == Float.class || c == Long.class || c == Double.class; + } + + /** * Gets a formatted string for a given value of this kind. * * @param value a value of this kind * @return a formatted string for {@code value} based on this kind */ public String format(Object value) { - if (this == Kind.Object) { + if (isPrimitive()) { + assert isToStringSafe(value.getClass()); + return value.toString(); + } else { if (value == null) { return "null"; } else { @@ -280,18 +291,20 @@ } } else if (value instanceof JavaType) { return "JavaType:" + MetaUtil.toJavaName((JavaType) value); - } else if (value instanceof Enum || value instanceof FormatWithToString || value instanceof Number) { + } else if (value instanceof Enum) { + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum) value).name(); + } else if (value instanceof FormatWithToString) { return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); } else if (value instanceof Class) { return "Class:" + ((Class) value).getName(); + } else if (isToStringSafe(value.getClass())) { + return value.toString(); } else if (value.getClass().isArray()) { return formatArray(value); } else { return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); } } - } else { - return value.toString(); } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Mon Feb 17 13:48:41 2014 +0100 @@ -185,6 +185,8 @@ */ boolean canBeInlined(); + boolean shouldBeInlined(); + /** * Returns the LineNumberTable of this method or null if this method does not have a line * numbers table. diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Mon Feb 17 13:48:41 2014 +0100 @@ -229,18 +229,18 @@ } @Override - public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel) { + public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) { boolean mirrored = emitCompare(left, right); Condition finalCondition = mirrored ? cond.mirror() : cond; switch (left.getKind().getStackKind()) { case Int: case Long: case Object: - append(new BranchOp(finalCondition, trueLabel, falseLabel)); + append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); break; case Float: case Double: - append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel)); + append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); break; default: throw GraalInternalError.shouldNotReachHere("" + left.getKind()); @@ -255,22 +255,14 @@ } @Override - public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, boolean negated) { - if (negated) { - append(new BranchOp(ConditionFlag.NoOverflow, noOverflow, overflow)); - } else { - append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow)); - } + public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { + append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability)); } @Override - public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef trueDestination, LabelRef falseDestination) { + public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { emitIntegerTest(left, right); - if (negated) { - append(new BranchOp(Condition.NE, falseDestination, trueDestination)); - } else { - append(new BranchOp(Condition.EQ, trueDestination, falseDestination)); - } + append(new BranchOp(Condition.EQ, trueDestination, falseDestination, trueDestinationProbability)); } @Override diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntBase.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import com.oracle.graal.compiler.hsail.test.infra.*; + +/** + * Tests codegen for an IJ signature {@code IntStream} instance function. + */ +public abstract class ArgsIntBase extends GraalKernelTester { + + static final int NUM = 20; + + @Result public double[] outArray = new double[NUM]; + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + outArray[i] = -i; + } + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntInstIITest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntInstIITest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an II signature {@code IntStream} instance function. + */ +public class ArgsIntInstIITest extends ArgsIntBase { + + public void run(int arg1, int arg2, int gid) { + outArray[gid] = gid + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(NUM, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntInstIJTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntInstIJTest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an IJ signature {@code IntStream} instance function. + */ +public class ArgsIntInstIJTest extends ArgsIntBase { + + public void run(int arg1, long arg2, int gid) { + outArray[gid] = gid + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(NUM, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntStatAIITest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntStatAIITest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an AII signature {@code IntStream} static function. + */ +public class ArgsIntStatAIITest extends ArgsIntBase { + + public static void run(double[] out, int arg1, int arg2, int gid) { + out[gid] = gid + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(NUM, outArray, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntStatAIJTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsIntStatAIJTest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an AIJ signature {@code IntStream} static function. + */ +public class ArgsIntStatAIJTest extends ArgsIntBase { + + public static void run(double[] out, int arg1, long arg2, int gid) { + out[gid] = gid + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(NUM, outArray, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjBase.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import com.oracle.graal.compiler.hsail.test.infra.*; + +/** + * Tests codegen for an IJ signature Object stream instance function. + */ +public abstract class ArgsObjBase extends GraalKernelTester { + + static class MyObj { + public int id; + public double d; + + public MyObj(int id) { + this.id = id; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof MyObj)) { + return false; + } + MyObj oth = (MyObj) other; + return (oth.id == id && oth.d == d); + } + + @Override + public String toString() { + return ("MyObj[" + id + ", " + d + "]"); + } + + @Override + public int hashCode() { + return id; + } + + } + + static final int NUM = 20; + + @Result public MyObj[] outArray = new MyObj[NUM]; + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + outArray[i] = new MyObj(i + 1); + } + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjInstIITest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjInstIITest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an II signature Object stream instance function. + */ +public class ArgsObjInstIITest extends ArgsObjBase { + + public void run(int arg1, int arg2, MyObj myobj) { + myobj.d = myobj.id + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(outArray, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjInstIJTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjInstIJTest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an IJ signature Object stream instance function. + */ +public class ArgsObjInstIJTest extends ArgsObjBase { + + public void run(int arg1, long arg2, MyObj myobj) { + myobj.d = myobj.id + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(outArray, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjStatIITest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjStatIITest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an II signature Object stream static function. + */ +public class ArgsObjStatIITest extends ArgsObjBase { + + public static void run(int arg1, int arg2, MyObj myobj) { + myobj.d = myobj.id + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(outArray, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjStatIJTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ArgsObjStatIJTest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import org.junit.*; + +/** + * Tests codegen for an IJ signature Object stream static function. + */ +public class ArgsObjStatIJTest extends ArgsObjBase { + + public static void run(int arg1, long arg2, MyObj myobj) { + myobj.d = myobj.id + arg1 + arg2; + } + + @Override + public void runTest() { + setupArrays(); + dispatchMethodKernel(outArray, 7, 6); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StringEqualsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StringEqualsTest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 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.compiler.hsail.test; + +import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; +import org.junit.Test; + +public class StringEqualsTest extends GraalKernelTester { + + static final int NUM = 20; + @Result public boolean[] outArray = new boolean[NUM]; + public String[] inArray = new String[NUM]; + + void setupArrays() { + char[] chars = new char[100]; + for (int i = 0; i < chars.length; i++) { + chars[i] = (char) ('A' + i); + } + for (int i = 0; i < NUM; i++) { + inArray[i] = new String(chars, 0, 10 + (i % 3)); + } + } + + public void run(String base, int gid) { + outArray[gid] = inArray[gid].equals(base); + } + + @Override + public void runTest() { + setupArrays(); + + dispatchMethodKernel(NUM, "ABCDEFGHIJ"); + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java --- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Mon Feb 17 13:48:41 2014 +0100 @@ -189,7 +189,7 @@ } @Override - public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination) { + public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { // We don't have to worry about mirroring the condition on HSAIL. Condition finalCondition = cond; Variable result = newVariable(left.getKind()); @@ -210,12 +210,12 @@ } @Override - public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, boolean negated) { + public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { throw GraalInternalError.unimplemented(); } @Override - public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef trueDestination, LabelRef falseDestination) { + public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { throw GraalInternalError.unimplemented(); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Mon Feb 17 13:48:41 2014 +0100 @@ -299,7 +299,7 @@ } @Override - public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination) { + public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { switch (left.getKind().getStackKind()) { case Int: append(new CompareOp(ICMP, cond, left, right, nextPredRegNum)); @@ -327,12 +327,12 @@ } @Override - public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, boolean negated) { + public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { throw GraalInternalError.unimplemented("PTXLIRGenerator.emitOverflowCheckBranch()"); } @Override - public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef trueDestination, LabelRef falseDestination) { + public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { // / emitIntegerTest(left, right); // append(new BranchOp(negated ? Condition.NE : Condition.EQ, label)); throw GraalInternalError.unimplemented("emitIntegerTestBranch()"); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Mon Feb 17 13:48:41 2014 +0100 @@ -230,7 +230,7 @@ } @Override - public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination) { + public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { boolean mirrored = emitCompare(left, right); Condition finalCondition = mirrored ? cond.mirror() : cond; Kind kind = left.getKind().getStackKind(); @@ -254,15 +254,15 @@ } @Override - public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, boolean negated) { + public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { // append(new BranchOp(negated ? ConditionFlag.NoOverflow : ConditionFlag.Overflow, label)); throw GraalInternalError.unimplemented(); } @Override - public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef trueDestination, LabelRef falseDestination) { + public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { emitIntegerTest(left, right); - append(new BranchOp(negated ? Condition.NE : Condition.EQ, trueDestination, falseDestination, left.getKind().getStackKind())); + append(new BranchOp(Condition.EQ, trueDestination, falseDestination, left.getKind().getStackKind())); } private void emitIntegerTest(Value a, Value b) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/nfi/NativeFunctionInterfaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/nfi/NativeFunctionInterfaceTest.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.compiler.test.nfi; + +import static com.oracle.graal.graph.UnsafeAccess.*; +import static java.io.File.*; +import static java.lang.System.*; +import static org.junit.Assert.*; +import static org.junit.Assume.*; + +import java.io.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.runtime.*; + +public class NativeFunctionInterfaceTest { + + public final NativeFunctionInterface nfi; + + public NativeFunctionInterfaceTest() { + RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class); + Assume.assumeTrue(runtimeProvider.getHostBackend() instanceof HostBackend); + nfi = ((HostBackend) runtimeProvider.getHostBackend()).getNativeFunctionInterface(); + } + + private List allocations = new ArrayList<>(); + + protected long malloc(int length) { + long buf = unsafe.allocateMemory(length); + allocations.add(buf); + return buf; + } + + @After + public void cleanup() { + for (long buf : allocations) { + unsafe.freeMemory(buf); + } + } + + private static void assertCStringEquals(long cString, String s) { + for (int i = 0; i < s.length(); i++) { + assertEquals(unsafe.getByte(cString + i) & 0xFF, (byte) s.charAt(i)); + } + assertEquals(unsafe.getByte(cString + s.length()) & 0xFF, (byte) '\0'); + } + + @Test + public void test1() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + NativeFunctionHandle malloc = nfi.getFunctionHandle("malloc", long.class, int.class); + NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class); + NativeFunctionHandle free = nfi.getFunctionHandle("free", void.class, long.class); + + String string = "GRAAL"; + int bufferLength = string.length() + 1; + long cString = (long) malloc.call(bufferLength); + writeCString(string, cString); + + long cStringCopy = malloc(bufferLength); + int result = (int) snprintf.call(cStringCopy, bufferLength, cString); + Assert.assertEquals(string.length(), result); + assertCStringEquals(cString, string); + assertCStringEquals(cStringCopy, string); + + free.call(cString); + } + + @Test + public void test2() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + String formatString = "AB %f%f"; + long formatCString = writeCString("AB %f%f", malloc(formatString.length() + 1)); + + String referenceString = "AB 1.0000001.000000"; + int bufferLength = referenceString.length() + 1; + long buffer = malloc(bufferLength); + + NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, double.class, double.class); + int result = (int) snprintf.call(buffer, bufferLength, formatCString, 1.0D, 1.0D); + + assertCStringEquals(buffer, referenceString); + Assert.assertEquals(referenceString.length(), result); + } + + @Test + public void test3() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + String format = "%i%i%i%i%i%i%i%i%i%i%i%i"; + long formatCString = writeCString(format, malloc(format.length() + 1)); + String referenceString = "01234567891011"; + + int bufferLength = referenceString.length() + 1; + long buffer = malloc(bufferLength); + + NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class, + int.class, int.class, int.class, int.class, int.class); + + int result = (int) snprintf.call(buffer, bufferLength, formatCString, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + assertCStringEquals(buffer, referenceString); + Assert.assertEquals(referenceString.length(), result); + } + + @Test + public void test4() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + long str = malloc(49); + int[] val = new int[12]; + for (int i = 0; i < 12; i++) { + unsafe.putByte(str + 2 * i, (byte) '%'); + unsafe.putByte(str + 2 * i + 1, (byte) 'i'); + val[i] = i; + } + double[] dval = new double[12]; + for (int i = 12; i < 24; i++) { + unsafe.putByte(str + 2 * i, (byte) '%'); + unsafe.putByte(str + 2 * i + 1, (byte) 'f'); + dval[i - 12] = i + 0.5; + } + unsafe.putByte(str + 48, (byte) '\0'); + + String referenceString = "0123456789101112.50000013.50000014.50000015.50000016.50000017.50000018.50000019.50000020.500000" + "21.50000022.50000023.500000"; + int bufferLength = referenceString.length() + 1; + + long buffer = malloc(bufferLength); + + NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class, + int.class, int.class, int.class, int.class, int.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, + double.class, double.class, double.class, double.class); + + int result = (int) snprintf.call(buffer, bufferLength, str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], dval[0], dval[1], dval[2], + dval[3], dval[4], dval[5], dval[6], dval[7], dval[8], dval[9], dval[10], dval[11]); + assertCStringEquals(buffer, referenceString); + Assert.assertEquals(referenceString.length(), result); + } + + @Test + public void test5() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + long str = malloc(73); + int[] val = new int[12]; + for (int i = 0; i < 12; i++) { + unsafe.putByte(str + 2 * i, (byte) '%'); + unsafe.putByte(str + 2 * i + 1, (byte) 'i'); + val[i] = i; + } + double[] dval = new double[12]; + for (int i = 12; i < 24; i++) { + unsafe.putByte(str + 2 * i, (byte) '%'); + unsafe.putByte(str + 2 * i + 1, (byte) 'f'); + dval[i - 12] = i + 0.5; + } + char[] cval = new char[12]; + for (int i = 24; i < 36; i++) { + unsafe.putByte(str + 2 * i, (byte) '%'); + unsafe.putByte(str + 2 * i + 1, (byte) 'c'); + cval[i - 24] = (char) ('a' + (i - 24)); + } + unsafe.putByte(str + 72, (byte) '\0'); + + String referenceString = "0123456789101112.50000013.50000014.50000015.50000016.50000017.50000018.50000019.50000020.50000021.50000022.50000023.500000abcdefghijkl"; + int bufferLength = referenceString.length() + 1; + + long buffer = malloc(bufferLength); + + NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class, + int.class, int.class, int.class, int.class, int.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, + double.class, double.class, double.class, double.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, + char.class, char.class); + + int result = (int) snprintf.call(buffer, bufferLength, str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], dval[0], dval[1], dval[2], + dval[3], dval[4], dval[5], dval[6], dval[7], dval[8], dval[9], dval[10], dval[11], cval[0], cval[1], cval[2], cval[3], cval[4], cval[5], cval[6], cval[7], cval[8], cval[9], + cval[10], cval[11]); + assertCStringEquals(buffer, referenceString); + Assert.assertEquals(referenceString.length(), result); + } + + @Test + public void test6() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + NativeFunctionHandle handle = nfi.getFunctionHandle("pow", double.class, double.class, double.class); + double result = (double) handle.call(3D, 5.5D); + assertEquals(Math.pow(3D, 5.5D), result, 0); + } + + @Test + public void test7() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + double result = 0; + NativeFunctionHandle handle = nfi.getFunctionHandle("pow", double.class, double.class, double.class); + for (int i = 0; i < 10; i++) { + result = (double) handle.call(3D, 5.5D); + } + assertEquals(Math.pow(3D, 5.5D), result, 0); + } + + @Test + public void test8() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + String formatString = "AB %f%f"; + long formatCString = writeCString("AB %f%f", malloc(formatString.length() + 1)); + + String expected = "AB 1.0000001.000000"; + int bufferLength = expected.length() + 1; + byte[] buffer = new byte[bufferLength]; + + NativeFunctionHandle snprintf = nfi.getFunctionHandle("snprintf", int.class, byte[].class, int.class, long.class, double.class, double.class); + int result = (int) snprintf.call(buffer, bufferLength, formatCString, 1.0D, 1.0D); + + // trim trailing '\0' + String actual = new String(buffer, 0, expected.length()); + + assertEquals(expected, actual); + Assert.assertEquals(expected.length(), result); + } + + private static double[] someDoubles = {2454.346D, 98789.22D, Double.MAX_VALUE, Double.MIN_NORMAL, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}; + + @Test + public void test9() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + double[] src = someDoubles.clone(); + double[] dst = new double[src.length]; + + NativeFunctionHandle memcpy = nfi.getFunctionHandle("memcpy", void.class, double[].class, double[].class, int.class); + memcpy.call(dst, src, src.length * (Double.SIZE / Byte.SIZE)); + + assertArrayEquals(src, dst, 0.0D); + } + + private static String getVMName() { + String vmName = System.getProperty("java.vm.name").toLowerCase(); + String vm = null; + if (vmName.contains("server")) { + vm = "server"; + } else if (vmName.contains("graal")) { + vm = "graal"; + } else if (vmName.contains("client")) { + vm = "client"; + } + + Assume.assumeTrue(vm != null); + return vm; + } + + private static String getVMLibPath() { + String vm = getVMName(); + + String path = String.format("%s%c%s%c%s", getProperty("sun.boot.library.path"), separatorChar, vm, separatorChar, mapLibraryName("jvm")); + // Only continue if the library file exists + Assume.assumeTrue(new File(path).exists()); + return path; + } + + @Test + public void test10() { + NativeLibraryHandle vmLib = nfi.getLibraryHandle(getVMLibPath()); + NativeFunctionHandle currentTimeMillis = nfi.getFunctionHandle(vmLib, "JVM_CurrentTimeMillis", long.class); + long time1 = (long) currentTimeMillis.call(); + long time2 = System.currentTimeMillis(); + long delta = time2 - time1; + + // The 2 calls to get the current time should not differ by more than + // 100 milliseconds at the very most + assertTrue(String.valueOf(delta), delta >= 0); + assertTrue(String.valueOf(delta), delta < 100); + } + + private static String getJavaLibPath() { + String path = String.format("%s%c%s", getProperty("sun.boot.library.path"), separatorChar, mapLibraryName("java")); + Assume.assumeTrue(new File(path).exists()); + return path; + } + + private static void testD2L(NativeFunctionHandle d2l) { + for (double d : someDoubles) { + long expected = Double.doubleToRawLongBits(d); + long actual = (long) d2l.call(0L, 0L, d); + assertEquals(Double.toString(d), expected, actual); + } + } + + @Test + public void test11() { + NativeLibraryHandle javaLib = nfi.getLibraryHandle(getJavaLibPath()); + NativeFunctionHandle d2l = nfi.getFunctionHandle(javaLib, "Java_java_lang_Double_doubleToRawLongBits", long.class, long.class, long.class, double.class); + testD2L(d2l); + } + + @Test + public void test12() { + NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; + NativeFunctionHandle d2l = nfi.getFunctionHandle(libs, "Java_java_lang_Double_doubleToRawLongBits", long.class, long.class, long.class, double.class); + testD2L(d2l); + + NativeLibraryHandle[] libsReveresed = {libs[1], libs[0]}; + d2l = nfi.getFunctionHandle(libsReveresed, "Java_java_lang_Double_doubleToRawLongBits", long.class, long.class, long.class, double.class); + testD2L(d2l); + } + + @Test + public void test13() { + NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; + NativeFunctionPointer functionPointer = nfi.getFunctionPointer(libs, "Java_java_lang_Double_doubleToRawLongBits"); + NativeFunctionHandle d2l = nfi.getFunctionHandle(functionPointer, long.class, long.class, long.class, double.class); + testD2L(d2l); + + NativeLibraryHandle[] libsReveresed = {libs[1], libs[0]}; + functionPointer = nfi.getFunctionPointer(libsReveresed, "Java_java_lang_Double_doubleToRawLongBits"); + d2l = nfi.getFunctionHandle(functionPointer, long.class, long.class, long.class, double.class); + testD2L(d2l); + } + + @Test + public void test14() { + if (!nfi.isDefaultLibrarySearchSupported()) { + try { + nfi.getFunctionHandle("snprintf", int.class); + fail(); + } catch (UnsatisfiedLinkError e) { + } + } + } + + @Test + public void test15() { + assumeTrue(nfi.isDefaultLibrarySearchSupported()); + try { + nfi.getFunctionHandle("an invalid function name", int.class); + fail(); + } catch (UnsatisfiedLinkError e) { + } + } + + @Test + public void test16() { + NativeLibraryHandle javaLib = nfi.getLibraryHandle(getJavaLibPath()); + try { + + nfi.getFunctionHandle(javaLib, "an invalid function name", int.class); + fail(); + } catch (UnsatisfiedLinkError e) { + } + } + + @Test + public void test17() { + NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; + try { + nfi.getFunctionPointer(libs, "an invalid function name"); + fail(); + } catch (UnsatisfiedLinkError e) { + } + } + + @Test + public void test18() { + NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())}; + try { + nfi.getFunctionHandle(libs, "an invalid function name", int.class); + fail(); + } catch (UnsatisfiedLinkError e) { + } + } + + @Test + public void test19() { + try { + nfi.getLibraryHandle("an invalid library name"); + fail(); + } catch (UnsatisfiedLinkError e) { + } + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon Feb 17 13:48:41 2014 +0100 @@ -280,7 +280,9 @@ try (Scope s = Debug.scope("ControlFlowOptimizations")) { EdgeMoveOptimizer.optimize(lir); ControlFlowOptimizer.optimize(lir); - RedundantMoveElimination.optimize(lir, frameMap, lirGen.getGraph().method()); + if (lirGen.canEliminateRedundantMoves()) { + RedundantMoveElimination.optimize(lir, frameMap, lirGen.getGraph().method()); + } NullCheckOptimizer.optimize(lir, target.implicitNullCheckLimit); Debug.dump(lir, "After control flow optimization"); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon Feb 17 13:48:41 2014 +0100 @@ -22,7 +22,6 @@ */ package com.oracle.graal.compiler.gen; -import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.api.meta.Value.*; import static com.oracle.graal.lir.LIR.*; @@ -41,7 +40,11 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.JumpOp; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.StandardOp.NoOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; @@ -174,13 +177,7 @@ this.graph = graph; this.providers = providers; this.frameMap = frameMap; - if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { - this.cc = cc; - } else { - JavaType[] parameterTypes = new JavaType[]{getMetaAccess().lookupJavaType(long.class)}; - CallingConvention tmp = frameMap.registerConfig.getCallingConvention(JavaCallee, getMetaAccess().lookupJavaType(void.class), parameterTypes, target(), false); - this.cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0)); - } + this.cc = cc; this.nodeOperands = graph.createNodeMap(); this.lir = lir; this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands); @@ -222,6 +219,14 @@ return null; } + /** + * Returns true if the redundant move elimination optimization should be done after register + * allocation. + */ + public boolean canEliminateRedundantMoves() { + return true; + } + @SuppressWarnings("hiding") protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { return new DebugInfoBuilder(nodeOperands); @@ -655,37 +660,33 @@ @Override public void emitIf(IfNode x) { - emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor())); + emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); } - public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor) { + public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { if (node instanceof IsNullNode) { - emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor); + emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); } else if (node instanceof CompareNode) { - emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor); + emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); } else if (node instanceof LogicConstantNode) { emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor); } else if (node instanceof IntegerTestNode) { - emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor); + emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); } else { throw GraalInternalError.unimplemented(node.toString()); } } - private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor) { - emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, falseSuccessor); + private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability); } - public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor) { - emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor); + public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); } - public void emitOverflowCheckBranch(LabelRef noOverflowBlock, LabelRef overflowBlock) { - emitOverflowCheckBranch(overflowBlock, noOverflowBlock, false); - } - - public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor) { - emitIntegerTestBranch(operand(test.x()), operand(test.y()), false, trueSuccessor, falseSuccessor); + public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { + emitIntegerTestBranch(operand(test.x()), operand(test.y()), trueSuccessor, falseSuccessor, trueSuccessorProbability); } public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { @@ -719,11 +720,11 @@ public abstract void emitJump(LabelRef label); - public abstract void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination); + public abstract void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability); - public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, boolean negated); + public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability); - public abstract void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef trueDestination, LabelRef falseDestination); + public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability); public abstract Variable emitConditionalMove(Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue); @@ -851,7 +852,8 @@ Variable value = load(operand(x.value())); if (keyCount == 1) { assert defaultTarget != null; - emitCompareBranch(load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget); + double probability = x.probability(x.keySuccessor(0)); + emitCompareBranch(load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability); } else { LabelRef[] keyTargets = new LabelRef[keyCount]; Constant[] keyConstants = new Constant[keyCount]; diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java Mon Feb 17 13:48:41 2014 +0100 @@ -49,4 +49,33 @@ throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); } } + + /** + * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The native memory buffer is allocated via + * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when + * it is no longer needed via {@link Unsafe#freeMemory(long)}. + * + * @return the native memory pointer of the C string created from {@code s} + */ + public static long createCString(String s) { + return writeCString(s, unsafe.allocateMemory(s.length() + 1)); + } + + /** + * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The caller is responsible for ensuring the buffer is at least + * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer + * when it is no longer. + * + * @return the value of {@code buf} + */ + public static long writeCString(String s, long buf) { + int size = s.length(); + for (int i = 0; i < size; i++) { + unsafe.putByte(buf + i, (byte) s.charAt(i)); + } + unsafe.putByte(buf + size, (byte) '\0'); + return buf; + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon Feb 17 13:48:41 2014 +0100 @@ -40,15 +40,14 @@ import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nfi.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nfi.hotspot.amd64.*; import com.oracle.graal.nodes.*; /** @@ -311,12 +310,12 @@ @Override public NativeFunctionInterface getNativeFunctionInterface() { - AMD64HotSpotNativeFunctionPointer libraryLoadPointer = new AMD64HotSpotNativeFunctionPointer(getRuntime().getConfig().libraryLoadAddress, "GNFI_UTIL_LOADLIBRARY"); - AMD64HotSpotNativeFunctionPointer functionLookupPointer = new AMD64HotSpotNativeFunctionPointer(getRuntime().getConfig().functionLookupAddress, "GNFI_UTIL_FUNCTIONLOOKUP"); - AMD64HotSpotNativeLibraryHandle rtldDefault = new AMD64HotSpotNativeLibraryHandle(getRuntime().getConfig().rtldDefault); - if (!libraryLoadPointer.isValid() || !functionLookupPointer.isValid()) { - throw GraalInternalError.shouldNotReachHere("Lookup Pointers null"); - } - return new AMD64HotSpotNativeFunctionInterface(this.getProviders(), this, libraryLoadPointer, functionLookupPointer, rtldDefault); + HotSpotVMConfig config = getRuntime().getConfig(); + RawNativeCallNodeFactory factory = new RawNativeCallNodeFactory() { + public FixedWithNextNode createRawCallNode(Kind returnType, Constant functionPointer, ValueNode... args) { + return new AMD64RawNativeCallNode(returnType, functionPointer, args); + } + }; + return new HotSpotNativeFunctionInterface(getProviders(), factory, this, config.dllLoad, config.dllLookup, config.rtldDefault); } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Feb 17 13:48:41 2014 +0100 @@ -158,7 +158,6 @@ CallingConvention incomingArguments = cc; - RegisterValue rbpParam = rbp.asValue(Kind.Long); Value[] params = new Value[incomingArguments.getArgumentCount() + 1]; for (int i = 0; i < params.length - 1; i++) { params[i] = toStackKind(incomingArguments.getArgument(i)); @@ -169,7 +168,7 @@ } } } - params[params.length - 1] = rbpParam; + params[params.length - 1] = rbp.asValue(Kind.Long); emitIncomingValues(params); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 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.amd64; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.amd64.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRGenLowerable { + + private final Constant functionPointer; + @Input private final NodeInputList args; + + public AMD64RawNativeCallNode(Kind returnType, Constant functionPointer, ValueNode[] args) { + super(StampFactory.forKind(returnType)); + this.functionPointer = functionPointer; + this.args = new NodeInputList<>(this, args); + } + + @Override + public void generate(LIRGenerator generator) { + AMD64LIRGenerator gen = (AMD64LIRGenerator) generator; + Value[] parameter = new Value[args.count()]; + JavaType[] parameterTypes = new JavaType[args.count()]; + for (int i = 0; i < args.count(); i++) { + parameter[i] = generator.operand(args.get(i)); + parameterTypes[i] = args.get(i).stamp().javaType(gen.getMetaAccess()); + } + ResolvedJavaType returnType = stamp().javaType(gen.getMetaAccess()); + CallingConvention cc = generator.getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes, generator.target(), false); + gen.emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args)); + if (this.kind() != Kind.Void) { + generator.setResult(this, gen.emitMove(cc.getReturn())); + } + } + + private static int countFloatingTypeArguments(NodeInputList args) { + int count = 0; + for (ValueNode n : args) { + if (n.kind() == Kind.Double || n.kind() == Kind.Float) { + count++; + } + } + if (count > 8) { + return 8; + } + return count; + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java Mon Feb 17 13:48:41 2014 +0100 @@ -26,7 +26,6 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import java.lang.reflect.*; -import java.util.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -63,7 +62,7 @@ private static HotSpotNmethod getCompiledLambda(Class intConsumerClass) { Method acceptMethod = null; for (Method m : intConsumerClass.getMethods()) { - if (m.getName().equals("accept") && Arrays.equals(new Class[]{int.class}, m.getParameterTypes())) { + if (m.getName().equals("accept")) { assert acceptMethod == null : "found more than one implementation of accept(int) in " + intConsumerClass; acceptMethod = m; } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Mon Feb 17 13:48:41 2014 +0100 @@ -48,11 +48,9 @@ import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.hsail.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.replacements.hsail.*; /** * HSAIL specific backend. @@ -107,10 +105,8 @@ lowerer.initialize(providers, config); // Register the replacements used by the HSAIL backend. - Replacements replacements = providers.getReplacements(); - - // Register the substitutions for java.lang.Math routines. - replacements.registerSubstitutions(HSAILMathSubstitutions.class); + HSAILHotSpotReplacementsImpl replacements = (HSAILHotSpotReplacementsImpl) providers.getReplacements(); + replacements.completeInitialization(); } /** @@ -321,7 +317,7 @@ } // Emit the kernel function parameters. for (int i = 0; i < totalParamCount; i++) { - String str = "kernarg_" + paramHsailSizes[i] + " " + paramNames[i]; + String str = "align 8 kernarg_" + paramHsailSizes[i] + " " + paramNames[i]; if (i != totalParamCount - 1) { str += ","; diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java Mon Feb 17 13:48:41 2014 +0100 @@ -30,6 +30,8 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.hsail.*; +import java.util.HashSet; /** * The substitutions and snippets supported by HSAIL. @@ -37,12 +39,31 @@ public class HSAILHotSpotReplacementsImpl extends ReplacementsImpl { private final Replacements host; + private HashSet ignoredResolvedMethods = new HashSet<>(); public HSAILHotSpotReplacementsImpl(Providers providers, Assumptions assumptions, TargetDescription target, Replacements host) { super(providers, assumptions, target); this.host = host; } + public void addIgnoredResolvedMethod(Class cls, String methName, Class... params) { + try { + Method m = cls.getMethod(methName, params); + ResolvedJavaMethod rjm = providers.getMetaAccess().lookupJavaMethod(m); + ignoredResolvedMethods.add(rjm); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void completeInitialization() { + // Register the substitutions for java.lang.Math routines. + registerSubstitutions(HSAILMathSubstitutions.class); + + // Register the ignored substitutions + addIgnoredResolvedMethod(String.class, "equals", Object.class); + } + @Override protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) { // TODO: decide if we want to override this in any way @@ -70,9 +91,13 @@ public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) { StructuredGraph m = super.getMethodSubstitution(original); if (m == null) { - // eventually we want to only defer certain substitutions to the host, but for now we - // will defer everything - return host.getMethodSubstitution(original); + // we check for a few special cases we do NOT want to defer here + // but basically we defer everything else to the host + if (ignoredResolvedMethods.contains(original)) { + return null; + } else { + return host.getMethodSubstitution(original); + } } return m; } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Mon Feb 17 13:48:41 2014 +0100 @@ -137,9 +137,18 @@ long launchKernel = getLaunchKernelAddress(); hostForeignCalls.linkForeignCall(hostProviders, CALL_KERNEL, launchKernel, false, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); } + /* Add a shutdown hook to destroy CUDA context(s) */ + Runtime.getRuntime().addShutdownHook(new Thread("PTXShutdown") { + @Override + public void run() { + destroyContext(); + } + }); super.completeInitialization(); } + private static native void destroyContext(); + /** * Gets the address of {@code Ptx::execute_kernel_from_vm()}. */ @@ -365,7 +374,7 @@ @Override public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) { - return new PTXLIRGenerator(graph, getProviders(), frameMap, cc, lir); + return new PTXHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir); } private static void emitKernelEntry(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014, 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.ptx; + +import com.oracle.graal.api.code.CallingConvention; +import com.oracle.graal.api.code.StackSlot; +import com.oracle.graal.api.meta.DeoptimizationAction; +import com.oracle.graal.api.meta.DeoptimizationReason; +import com.oracle.graal.api.meta.Value; +import com.oracle.graal.compiler.ptx.PTXLIRGenerator; +import com.oracle.graal.graph.GraalInternalError; +import com.oracle.graal.hotspot.HotSpotLIRGenerator; +import com.oracle.graal.hotspot.HotSpotVMConfig; +import com.oracle.graal.hotspot.meta.HotSpotProviders; +import com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode; +import com.oracle.graal.lir.FrameMap; +import com.oracle.graal.lir.LIR; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.ValueNode; + +/** + * LIR generator specialized for PTX HotSpot. + */ +public class PTXHotSpotLIRGenerator extends PTXLIRGenerator implements HotSpotLIRGenerator { + + protected PTXHotSpotLIRGenerator(StructuredGraph graph, HotSpotProviders providers, HotSpotVMConfig config, FrameMap frameMap, CallingConvention cc, LIR lir) { + super(graph, providers, frameMap, cc, lir); + assert config.basicLockSize == 8; + } + + public void emitPrefetchAllocate(ValueNode address, ValueNode distance) { + // nop + } + + public void emitTailcall(Value[] args, Value address) { + throw GraalInternalError.unimplemented(); + } + + public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { + throw GraalInternalError.unimplemented(); + } + + public void emitPatchReturnAddress(ValueNode address) { + throw GraalInternalError.unimplemented(); + } + + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + throw GraalInternalError.unimplemented(); + } + + public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { + throw GraalInternalError.unimplemented(); + } + + public StackSlot getLockSlot(int lockDepth) { + throw GraalInternalError.unimplemented(); + } + + @Override + public HotSpotProviders getProviders() { + throw GraalInternalError.unimplemented(); + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Mon Feb 17 13:48:41 2014 +0100 @@ -22,6 +22,7 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.compiler.GraalCompiler.*; import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*; @@ -222,6 +223,13 @@ } InlinedBytecodes.add(method.getCodeSize()); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); + if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) { + // for OSR, only a pointer is passed to the method. + JavaType[] parameterTypes = new JavaType[]{providers.getMetaAccess().lookupJavaType(long.class)}; + CallingConvention tmp = providers.getCodeCache().getRegisterConfig().getCallingConvention(JavaCallee, providers.getMetaAccess().lookupJavaType(void.class), parameterTypes, + backend.getTarget(), false); + cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0)); + } Suites suites = getSuites(providers); ProfilingInfo profilingInfo = getProfilingInfo(); OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Mon Feb 17 13:48:41 2014 +0100 @@ -56,6 +56,7 @@ ValueNode lock = state.lockAt(lockIndex); Value object = toValue(lock); boolean eliminated = object instanceof VirtualObject && state.monitorIdAt(lockIndex) != null; + assert state.monitorIdAt(lockIndex) == null || state.monitorIdAt(lockIndex).getLockDepth() == lockDepth; return new HotSpotMonitorValue(object, slot, eliminated); } diff -r 8df361535530 -r d68f5d0c97f0 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 Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon Feb 17 13:48:41 2014 +0100 @@ -840,14 +840,35 @@ @HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset; @HotSpotVMField(name = "JavaThread::_graal_counters[0]", type = "jlong", get = HotSpotVMField.Type.OFFSET, optional = true) @Stable public int graalCountersThreadOffset; - // The native side (graalCompilerToVM.cpp) sets the rtldDefault if the - // platform is NOT Windows (Windows is currently not supported). - // AMD64NativeFunctionInterface checks if rtld_default handle is valid. - // Using 0 is not possible as it is a valid value for rtldDefault on some platforms. + /** + * An invalid value for {@link #rtldDefault}. + */ public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE; - @Stable public long libraryLoadAddress; - @Stable public long functionLookupAddress; + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *

+     *     void* (const char *filename, char *ebuf, int ebuflen)
+     * 
+ */ + @Stable public long dllLoad; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
+     *     void* (void* handle, const char* name)
+     * 
+ */ + @Stable public long dllLookup; + + /** + * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will + * return the first occurrence of the desired symbol using the default library search order. If + * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on + * the current platform. + */ @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE; /** @@ -1005,6 +1026,8 @@ @HotSpotVMConstant(name = "JVM_CONSTANT_MethodType") @Stable public int jvmConstantMethodType; @HotSpotVMConstant(name = "JVM_CONSTANT_MethodTypeInError") @Stable public int jvmConstantMethodTypeInError; + @HotSpotVMConstant(name = "HeapWordSize") @Stable public int heapWordSize; + @HotSpotVMField(name = "Symbol::_length", type = "unsigned short", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolLengthOffset; @HotSpotVMField(name = "Symbol::_body[0]", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolBodyOffset; @@ -1261,6 +1284,35 @@ @HotSpotVMField(name = "StubRoutines::_updateBytesCRC32", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long updateBytesCRC32Stub; @HotSpotVMField(name = "StubRoutines::_crc_table_adr", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long crcTableAddress; + @HotSpotVMField(name = "StubRoutines::_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long alignedOopDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopy; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy; + @HotSpotVMField(name = "StubRoutines::_generic_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long genericArraycopy; + @Stable public long newInstanceAddress; @Stable public long newArrayAddress; @Stable public long newMultiArrayAddress; diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Mon Feb 17 13:48:41 2014 +0100 @@ -54,20 +54,30 @@ boolean hasBalancedMonitors(long metaspaceMethod); /** - * Determines if a given metaspace Method object is compilable. A method may not be compilable - * for a number of reasons such as: + * Determines if a given metaspace Method can be inlined. A method may not be inlinable for a + * number of reasons such as: * * - * A non-compilable method should not be inlined. + * @param metaspaceMethod the metaspace Method object to query + * @return true if the method can be inlined + */ + boolean canInlineMethod(long metaspaceMethod); + + /** + * Determines if a given metaspace Method should be inlined at any cost. This could be because: + * * * @param metaspaceMethod the metaspace Method object to query - * @return true if the method is compilable + * @return true if the method should be inlined */ - boolean isMethodCompilable(long metaspaceMethod); + boolean shouldInlineMethod(long metaspaceMethod); /** * Used to implement {@link ResolvedJavaType#findUniqueConcreteMethod(ResolvedJavaMethod)}. diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Mon Feb 17 13:48:41 2014 +0100 @@ -53,9 +53,6 @@ public native boolean hasBalancedMonitors(long metaspaceMethod); @Override - public native boolean isMethodCompilable(long metaspaceMethod); - - @Override public native long findUniqueConcreteMethod(long metaspaceMethod); @Override @@ -174,4 +171,8 @@ public native int allocateCompileId(HotSpotResolvedJavaMethod method, int entryBCI); public native String getGPUs(); + + public native boolean canInlineMethod(long metaspaceMethod); + + public native boolean shouldInlineMethod(long metaspaceMethod); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Mon Feb 17 13:48:41 2014 +0100 @@ -51,6 +51,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.hotspot.stubs.*; /** @@ -66,6 +67,14 @@ stub.getLinkage().setCompiledStub(stub); } + private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) { + LocationIdentity killed = NamedLocationIdentity.getArrayLocation(kind); + registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, false, false), routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, true, false), alignedRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, false, true), disjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + registerForeignCall(ArrayCopySnippets.lookupArraycopyDescriptor(kind, true, true), alignedDisjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + } + public void initialize(HotSpotProviders providers, HotSpotVMConfig c) { TargetDescription target = providers.getCodeCache().getTarget(); @@ -110,5 +119,15 @@ linkForeignCall(providers, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); + + registerArrayCopy(Kind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); + registerArrayCopy(Kind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); + registerArrayCopy(Kind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); + registerArrayCopy(Kind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); + registerArrayCopy(Kind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); + registerArrayCopy(Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); + registerArrayCopy(Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); + registerArrayCopy(Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Mon Feb 17 13:48:41 2014 +0100 @@ -245,27 +245,9 @@ } /** - * Returns true if this method has a ForceInline annotation. - * - * @return true if ForceInline annotation present, false otherwise - */ - public boolean isForceInline() { - return forceInline; - } - - /** - * Returns true if this method has a DontInline annotation. - * - * @return true if DontInline annotation present, false otherwise - */ - public boolean isDontInline() { - return dontInline; - } - - /** * Manually adds a DontInline annotation to this method. */ - public void setDontInline() { + public void setNotInlineable() { dontInline = true; runtime().getCompilerToVM().doNotInlineOrCompile(metaspaceMethod); } @@ -488,7 +470,15 @@ if (dontInline) { return false; } - return runtime().getCompilerToVM().isMethodCompilable(metaspaceMethod); + return runtime().getCompilerToVM().canInlineMethod(metaspaceMethod); + } + + @Override + public boolean shouldBeInlined() { + if (forceInline) { + return true; + } + return runtime().getCompilerToVM().shouldInlineMethod(metaspaceMethod); } @Override diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionHandle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionHandle.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014, 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.nfi; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.*; + +public class HotSpotNativeFunctionHandle implements NativeFunctionHandle { + + private final InstalledCode code; + private final String name; + private final Class[] argumentTypes; + + public HotSpotNativeFunctionHandle(InstalledCode code, String name, Class... argumentTypes) { + this.argumentTypes = argumentTypes; + this.name = name; + this.code = code; + } + + private void traceCall(Object... args) { + try (Scope s = Debug.scope("GNFI")) { + if (Debug.isLogEnabled()) { + Debug.log("[GNFI] %s%s", name, Arrays.toString(args)); + } + } + } + + private void traceResult(Object result) { + try (Scope s = Debug.scope("GNFI")) { + if (Debug.isLogEnabled()) { + Debug.log("[GNFI] %s --> %s", name, result); + } + } + } + + @Override + public Object call(Object... args) { + assert checkArgs(args); + try { + traceCall(args); + Object res = code.execute(args, null, null); + traceResult(res); + return res; + } catch (InvalidInstalledCodeException e) { + throw GraalInternalError.shouldNotReachHere("Execution of GNFI Callstub failed: " + name); + } + } + + private boolean checkArgs(Object... args) { + assert args.length == argumentTypes.length : this + " expected " + argumentTypes.length + " args, got " + args.length; + for (int i = 0; i < argumentTypes.length; i++) { + Object arg = args[i]; + assert arg != null; + Class expectedType = argumentTypes[i]; + if (expectedType.isPrimitive()) { + Kind kind = Kind.fromJavaClass(expectedType); + expectedType = kind.toBoxedJavaClass(); + } + assert expectedType == arg.getClass() : this + " expected arg " + i + " to be " + expectedType.getName() + ", not " + arg.getClass().getName(); + + } + return true; + } + + public InstalledCode getCallStub() { + return code; + } + + @Override + public String toString() { + return name + Arrays.toString(argumentTypes); + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2014, 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.nfi; + +import static com.oracle.graal.api.code.CodeUtil.*; +import static com.oracle.graal.graph.UnsafeAccess.*; +import static com.oracle.graal.hotspot.nfi.NativeCallStubGraphBuilder.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; + +public class HotSpotNativeFunctionInterface implements NativeFunctionInterface { + + private final HotSpotProviders providers; + private final Backend backend; + private final HotSpotNativeLibraryHandle rtldDefault; + private final HotSpotNativeFunctionPointer libraryLoadFunctionPointer; + private final HotSpotNativeFunctionPointer functionLookupFunctionPointer; + private final RawNativeCallNodeFactory factory; + + private HotSpotNativeFunctionHandle libraryLookupFunctionHandle; + private HotSpotNativeFunctionHandle dllLookupFunctionHandle; + + public HotSpotNativeFunctionInterface(HotSpotProviders providers, RawNativeCallNodeFactory factory, Backend backend, long dlopen, long dlsym, long rtldDefault) { + this.rtldDefault = rtldDefault == HotSpotVMConfig.INVALID_RTLD_DEFAULT_HANDLE ? null : new HotSpotNativeLibraryHandle("RTLD_DEFAULT", rtldDefault); + this.providers = providers; + this.backend = backend; + this.factory = factory; + this.libraryLoadFunctionPointer = new HotSpotNativeFunctionPointer(dlopen, "os::dll_load"); + this.functionLookupFunctionPointer = new HotSpotNativeFunctionPointer(dlsym, "os::dll_lookup"); + } + + @Override + public HotSpotNativeLibraryHandle getLibraryHandle(String libPath) { + if (libraryLookupFunctionHandle == null) { + libraryLookupFunctionHandle = createHandle(libraryLoadFunctionPointer, long.class, long.class, long.class, int.class); + } + + int ebufLen = 1024; + // Allocating a single chunk for both the error message buffer and the + // file name simplifies deallocation below. + long buffer = unsafe.allocateMemory(ebufLen + libPath.length() + 1); + long ebuf = buffer; + long libPathCString = writeCString(libPath, buffer + ebufLen); + try { + long handle = (long) libraryLookupFunctionHandle.call(libPathCString, ebuf, ebufLen); + if (handle == 0) { + throw new UnsatisfiedLinkError(libPath); + } + return new HotSpotNativeLibraryHandle(libPath, handle); + } finally { + unsafe.freeMemory(buffer); + } + } + + @Override + public HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle library, String name, Class returnType, Class... argumentTypes) { + HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, library, true); + return createHandle(functionPointer, returnType, argumentTypes); + } + + @Override + public HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraries, String name, Class returnType, Class... argumentTypes) { + HotSpotNativeFunctionPointer functionPointer = null; + for (NativeLibraryHandle libraryHandle : libraries) { + functionPointer = lookupFunctionPointer(name, libraryHandle, false); + if (functionPointer != null) { + return createHandle(functionPointer, returnType, argumentTypes); + } + } + // Fall back to default library path + return getFunctionHandle(name, returnType, argumentTypes); + } + + @Override + public HotSpotNativeFunctionHandle getFunctionHandle(String name, Class returnType, Class... argumentTypes) { + if (rtldDefault == null) { + throw new UnsatisfiedLinkError(name); + } + return getFunctionHandle(rtldDefault, name, returnType, argumentTypes); + } + + private HotSpotNativeFunctionPointer lookupFunctionPointer(String name, NativeLibraryHandle library, boolean linkageErrorIfMissing) { + if (name == null || library == null) { + throw new NullPointerException(); + } + + if (dllLookupFunctionHandle == null) { + dllLookupFunctionHandle = createHandle(functionLookupFunctionPointer, long.class, long.class, long.class); + } + long nameCString = createCString(name); + try { + long functionPointer = (long) dllLookupFunctionHandle.call(((HotSpotNativeLibraryHandle) library).value, nameCString); + if (functionPointer == 0L) { + if (!linkageErrorIfMissing) { + return null; + } + throw new UnsatisfiedLinkError(name); + } + return new HotSpotNativeFunctionPointer(functionPointer, name); + } finally { + unsafe.freeMemory(nameCString); + } + } + + @Override + public HotSpotNativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class returnType, Class... argumentTypes) { + if (!(functionPointer instanceof HotSpotNativeFunctionPointer)) { + throw new UnsatisfiedLinkError(functionPointer.getName()); + } + return createHandle(functionPointer, returnType, argumentTypes); + } + + private HotSpotNativeFunctionHandle createHandle(NativeFunctionPointer functionPointer, Class returnType, Class... argumentTypes) { + HotSpotNativeFunctionPointer hs = (HotSpotNativeFunctionPointer) functionPointer; + InstalledCode code = installNativeFunctionStub(hs.value, returnType, argumentTypes); + return new HotSpotNativeFunctionHandle(code, hs.name, argumentTypes); + } + + /** + * Creates and installs a stub for calling a native function. + */ + private InstalledCode installNativeFunctionStub(long functionPointer, Class returnType, Class... argumentTypes) { + StructuredGraph g = getGraph(providers, factory, functionPointer, returnType, argumentTypes); + Suites suites = providers.getSuites().createSuites(); + PhaseSuite phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); + CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, g.method(), false); + CompilationResult compResult = GraalCompiler.compileGraph(g, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL, + DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, true, new CompilationResult(), CompilationResultBuilderFactory.Default); + InstalledCode installedCode; + try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) { + installedCode = providers.getCodeCache().addMethod(g.method(), compResult, null); + } + return installedCode; + } + + @Override + public HotSpotNativeFunctionPointer getFunctionPointer(NativeLibraryHandle[] libraries, String name) { + for (NativeLibraryHandle libraryHandle : libraries) { + HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, libraryHandle, false); + if (functionPointer != null) { + return functionPointer; + } + } + // Fall back to default library path + if (rtldDefault == null) { + throw new UnsatisfiedLinkError(name); + } + return lookupFunctionPointer(name, rtldDefault, true); + } + + public boolean isDefaultLibrarySearchSupported() { + return rtldDefault != null; + } + + @Override + public NativeFunctionPointer getNativeFunctionPointerFromRawValue(long rawValue) { + return new HotSpotNativeFunctionPointer(rawValue, null); + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionPointer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionPointer.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, 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.nfi; + +import com.oracle.graal.api.code.*; + +public class HotSpotNativeFunctionPointer implements NativeFunctionPointer { + + final long value; + final String name; + + public HotSpotNativeFunctionPointer(long value, String name) { + if (value == 0) { + throw new UnsatisfiedLinkError(name); + } + this.value = value; + this.name = name; + } + + public String getName() { + return name; + } + + public long getValue() { + return value; + } + + @Override + public String toString() { + return name + "@0x" + Long.toHexString(value); + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeLibraryHandle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeLibraryHandle.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 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.nfi; + +import com.oracle.graal.api.code.*; + +public class HotSpotNativeLibraryHandle implements NativeLibraryHandle { + + final long value; + final String name; + + public HotSpotNativeLibraryHandle(String name, long handle) { + this.name = name; + this.value = handle; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotNativeLibraryHandle) { + HotSpotNativeLibraryHandle that = (HotSpotNativeLibraryHandle) obj; + return that.value == value; + } + return false; + } + + @Override + public int hashCode() { + return (int) value; + } + + @Override + public String toString() { + return name + "@" + value; + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2014, 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.nfi; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.word.phases.*; + +/** + * Utility creating a graph for a stub used to call a native function. + */ +public class NativeCallStubGraphBuilder { + + /** + * Creates a graph for a stub used to call a native function. + * + * @param functionPointer a native function pointer + * @param returnType the type of the return value + * @param argumentTypes the types of the arguments + * @return the graph that represents the call stub + */ + public static StructuredGraph getGraph(HotSpotProviders providers, RawNativeCallNodeFactory factory, long functionPointer, Class returnType, Class... argumentTypes) { + try { + ResolvedJavaMethod method = providers.getMetaAccess().lookupJavaMethod(NativeCallStubGraphBuilder.class.getMethod("libCall", Object.class, Object.class, Object.class)); + StructuredGraph g = new StructuredGraph(method); + ParameterNode arg0 = g.unique(new ParameterNode(0, StampFactory.forKind(Kind.Object))); + ParameterNode arg1 = g.unique(new ParameterNode(1, StampFactory.forKind(Kind.Object))); + ParameterNode arg2 = g.unique(new ParameterNode(2, StampFactory.forKind(Kind.Object))); + FrameState frameState = g.add(new FrameState(method, 0, Arrays.asList(new ValueNode[]{arg0, arg1, arg2}), 3, 0, false, false, new ArrayList(), + new ArrayList())); + g.start().setStateAfter(frameState); + List parameters = new ArrayList<>(); + FixedWithNextNode fixedWithNext = getParameters(g, arg0, argumentTypes.length, argumentTypes, parameters, providers); + Constant functionPointerNode = Constant.forLong(functionPointer); + + ValueNode[] arguments = new ValueNode[parameters.size()]; + + for (int i = 0; i < arguments.length; i++) { + arguments[i] = parameters.get(i); + } + + FixedWithNextNode callNode = g.add(factory.createRawCallNode(getKind(returnType), functionPointerNode, arguments)); + + if (fixedWithNext == null) { + g.start().setNext(callNode); + } else { + fixedWithNext.setNext(callNode); + } + + // box result + BoxNode boxedResult; + if (callNode.kind() != Kind.Void) { + if (callNode.kind() == Kind.Object) { + throw new IllegalArgumentException("Return type not supported: " + returnType.getName()); + } + ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(callNode.kind().toBoxedJavaClass()); + boxedResult = g.unique(new BoxNode(callNode, type, callNode.kind())); + } else { + boxedResult = g.unique(new BoxNode(ConstantNode.forLong(0, g), providers.getMetaAccess().lookupJavaType(Long.class), Kind.Long)); + } + + ReturnNode returnNode = g.add(new ReturnNode(boxedResult)); + callNode.setNext(returnNode); + (new WordTypeRewriterPhase(providers.getMetaAccess(), Kind.Long)).apply(g); + return g; + } catch (NoSuchMethodException e) { + throw GraalInternalError.shouldNotReachHere("Call Stub method not found"); + } + } + + private static FixedWithNextNode getParameters(StructuredGraph g, ParameterNode argumentsArray, int numArgs, Class[] argumentTypes, List args, HotSpotProviders providers) { + assert numArgs == argumentTypes.length; + FixedWithNextNode last = null; + for (int i = 0; i < numArgs; i++) { + // load boxed array element: + LoadIndexedNode boxedElement = g.add(new LoadIndexedNode(argumentsArray, ConstantNode.forInt(i, g), Kind.Object)); + if (i == 0) { + g.start().setNext(boxedElement); + last = boxedElement; + } else { + last.setNext(boxedElement); + last = boxedElement; + } + Class type = argumentTypes[i]; + Kind kind = getKind(type); + if (kind == Kind.Object) { + // array value + Kind arrayElementKind = getElementKind(type); + LocationIdentity locationIdentity = NamedLocationIdentity.getArrayLocation(arrayElementKind); + int displacement = getArrayBaseOffset(arrayElementKind); + ConstantNode index = ConstantNode.forInt(0, g); + int indexScaling = getArrayIndexScale(arrayElementKind); + IndexedLocationNode locationNode = IndexedLocationNode.create(locationIdentity, arrayElementKind, displacement, index, g, indexScaling); + Stamp wordStamp = StampFactory.forKind(providers.getCodeCache().getTarget().wordKind); + ComputeAddressNode arrayAddress = g.unique(new ComputeAddressNode(boxedElement, locationNode, wordStamp)); + args.add(arrayAddress); + } else { + // boxed primitive value + try { + ResolvedJavaField field = providers.getMetaAccess().lookupJavaField(kind.toBoxedJavaClass().getDeclaredField("value")); + LoadFieldNode loadFieldNode = g.add(new LoadFieldNode(boxedElement, field)); + last.setNext(loadFieldNode); + last = loadFieldNode; + args.add(loadFieldNode); + } catch (NoSuchFieldException e) { + throw new GraalInternalError(e); + } + } + } + return last; + } + + public static Kind getElementKind(Class clazz) { + Class componentType = clazz.getComponentType(); + if (componentType == null) { + throw new IllegalArgumentException("Parameter type not supported: " + clazz); + } + if (componentType.isPrimitive()) { + return Kind.fromJavaClass(componentType); + } + throw new IllegalArgumentException("Parameter type not supported: " + clazz); + } + + private static Kind getKind(Class clazz) { + if (clazz == int.class || clazz == Integer.class) { + return Kind.Int; + } else if (clazz == long.class || clazz == Long.class) { + return Kind.Long; + } else if (clazz == char.class || clazz == Character.class) { + return Kind.Char; + } else if (clazz == byte.class || clazz == Byte.class) { + return Kind.Byte; + } else if (clazz == float.class || clazz == Float.class) { + return Kind.Float; + } else if (clazz == double.class || clazz == Double.class) { + return Kind.Double; + } else if (clazz == int[].class || clazz == long[].class || clazz == char[].class || clazz == byte[].class || clazz == float[].class || clazz == double[].class) { + return Kind.Object; + } else if (clazz == void.class) { + return Kind.Void; + } else { + throw new IllegalArgumentException("Type not supported: " + clazz); + } + } + + @SuppressWarnings("unused") + public static Object libCall(Object argLoc, Object unused1, Object unused2) { + throw GraalInternalError.shouldNotReachHere("GNFI libCall method must not be called"); + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/RawNativeCallNodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/RawNativeCallNodeFactory.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 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.nfi; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; + +/** + * Factory for creating a node that makes a direct call to a native function pointer. + */ +public interface RawNativeCallNodeFactory { + FixedWithNextNode createRawCallNode(Kind returnType, Constant functionPointer, ValueNode... args); +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java Mon Feb 17 13:48:41 2014 +0100 @@ -63,7 +63,7 @@ ConstantNode klassNode = ConstantNode.forConstant(klass, metaAccess, graph); Stamp stamp = StampFactory.exactNonNull(metaAccess.lookupJavaType(Class.class)); - LocationNode location = graph.unique(ConstantLocationNode.create(FINAL_LOCATION, stamp.kind(), classMirrorOffset, graph)); + LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, stamp.kind(), classMirrorOffset, graph); FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp)); return freadNode; } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.replacements; import static com.oracle.graal.compiler.GraalCompiler.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; @@ -63,6 +64,10 @@ return arguments.get(4); } + private static boolean isHeapWordAligned(Constant value, Kind kind) { + return (arrayBaseOffset(kind) + value.asInt() * arrayIndexScale(kind)) % heapWordSize() == 0; + } + private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) { ResolvedJavaType srcType = ObjectStamp.typeOrNull(getSource().stamp()); ResolvedJavaType destType = ObjectStamp.typeOrNull(getDestination().stamp()); @@ -74,7 +79,23 @@ return null; } Kind componentKind = srcType.getComponentType().getKind(); - final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); + boolean disjoint = false; + boolean aligned = false; + if (getSourcePosition() == getDestinationPosition()) { + // Can treat as disjoint + disjoint = true; + } + Constant constantSrc = getSourcePosition().stamp().asConstant(); + Constant constantDst = getDestinationPosition().stamp().asConstant(); + if (constantSrc != null && constantDst != null) { + aligned = isHeapWordAligned(constantSrc, componentKind) && isHeapWordAligned(constantDst, componentKind); + if (constantSrc.asInt() >= constantDst.asInt()) { + // low to high copy so treat as disjoint + disjoint = true; + } + } + + final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind, aligned, disjoint)); try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) { return replacements.getSnippet(snippetMethod); } catch (Throwable e) { @@ -188,4 +209,5 @@ } } } + } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Mon Feb 17 13:48:41 2014 +0100 @@ -35,6 +35,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -51,13 +52,47 @@ public class ArrayCopySnippets implements Snippets { private static final EnumMap arraycopyMethods = new EnumMap<>(Kind.class); + private static final EnumMap[][] arraycopyCalls = new EnumMap[2][2]; + private static final EnumMap[][] arraycopyDescriptors = new EnumMap[2][2]; + public static final Method genericArraycopySnippet; + @SuppressWarnings("unchecked") + private static void findArraycopyCall(Kind kind, Class arrayClass, boolean aligned, boolean disjoint) throws NoSuchMethodException { + String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + "Arraycopy"; + arraycopyCalls[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, ArrayCopySnippets.class.getDeclaredMethod(name, arrayClass, int.class, arrayClass, int.class, int.class)); + arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class)); + } + + private static Method lookupArraycopyCall(Kind kind, boolean aligned, boolean disjoint) { + return (Method) arraycopyCalls[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind); + } + + @Fold + public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint) { + return (ForeignCallDescriptor) arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind); + } + private static void addArraycopySnippetMethod(Kind kind, Class arrayClass) throws NoSuchMethodException { arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); + if (CallArrayCopy.getValue()) { + if (kind != Kind.Object) { + // Only primitive types are currently supported + findArraycopyCall(kind, arrayClass, false, false); + findArraycopyCall(kind, arrayClass, false, true); + findArraycopyCall(kind, arrayClass, true, false); + findArraycopyCall(kind, arrayClass, true, true); + } + } } static { + for (int i = 0; i < arraycopyCalls.length; i++) { + for (int j = 0; j < arraycopyCalls[i].length; j++) { + arraycopyCalls[i][j] = new EnumMap(Kind.class); + arraycopyDescriptors[i][j] = new EnumMap(Kind.class); + } + } try { addArraycopySnippetMethod(Kind.Byte, byte[].class); addArraycopySnippetMethod(Kind.Boolean, boolean[].class); @@ -74,7 +109,11 @@ } } - public static Method getSnippetForKind(Kind kind) { + public static Method getSnippetForKind(Kind kind, boolean aligned, boolean disjoint) { + Method m = lookupArraycopyCall(kind, aligned, disjoint); + if (m != null) { + return m; + } return arraycopyMethods.get(kind); } @@ -195,6 +234,186 @@ } } + @NodeIntrinsic(ForeignCallNode.class) + public static native void callArraycopy(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word src, Word dst, Word len); + + private static Word computeBase(Object object, Kind kind, int pos) { + // In this code pos must be cast to long before being multiplied since shifting the value + // could be outside the range of int. arrayIndexScale should probably either return long or + // Word to force the right thing to happen. + return Word.unsigned(GetObjectAddressNode.get(object) + arrayBaseOffset(kind) + (long) pos * arrayIndexScale(kind)); + } + + private static void callArraycopyTemplate(SnippetCounter counter, Kind kind, boolean aligned, boolean disjoint, Object src, int srcPos, Object dest, int destPos, int length) { + counter.inc(); + Object nonNullSrc = guardingNonNull(src); + Object nonNullDest = guardingNonNull(dest); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + Word srcAddr = computeBase(src, kind, srcPos); + Word destAddr = computeBase(dest, kind, destPos); + callArraycopy(lookupArraycopyDescriptor(kind, aligned, disjoint), srcAddr, destAddr, Word.signed(length)); + } + + @Snippet + public static void byteArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + callArraycopyTemplate(byteCallCounter, Kind.Byte, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void byteDisjointArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + callArraycopyTemplate(byteDisjointCallCounter, Kind.Byte, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void byteAlignedArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + callArraycopyTemplate(byteAlignedCallCounter, Kind.Byte, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void byteAlignedDisjointArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + callArraycopyTemplate(byteAlignedDisjointCallCounter, Kind.Byte, true, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void booleanArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + callArraycopyTemplate(booleanCallCounter, Kind.Boolean, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void booleanDisjointArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + callArraycopyTemplate(booleanDisjointCallCounter, Kind.Boolean, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void booleanAlignedArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + callArraycopyTemplate(booleanAlignedCallCounter, Kind.Boolean, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void booleanAlignedDisjointArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + callArraycopyTemplate(booleanAlignedDisjointCallCounter, Kind.Boolean, true, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void charArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { + callArraycopyTemplate(charCallCounter, Kind.Char, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void charDisjointArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { + callArraycopyTemplate(charDisjointCallCounter, Kind.Char, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void charAlignedArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { + callArraycopyTemplate(charAlignedCallCounter, Kind.Char, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void charAlignedDisjointArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { + callArraycopyTemplate(charAlignedDisjointCallCounter, Kind.Char, true, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void shortArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { + callArraycopyTemplate(shortCallCounter, Kind.Short, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void shortDisjointArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { + callArraycopyTemplate(shortDisjointCallCounter, Kind.Short, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void shortAlignedArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { + callArraycopyTemplate(shortAlignedCallCounter, Kind.Short, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void shortAlignedDisjointArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { + callArraycopyTemplate(shortAlignedDisjointCallCounter, Kind.Short, true, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void intArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { + callArraycopyTemplate(intCallCounter, Kind.Int, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void intDisjointArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { + callArraycopyTemplate(intDisjointCallCounter, Kind.Int, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void intAlignedArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { + callArraycopyTemplate(intAlignedCallCounter, Kind.Int, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void intAlignedDisjointArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { + callArraycopyTemplate(intAlignedDisjointCallCounter, Kind.Int, true, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void floatArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { + callArraycopyTemplate(floatCallCounter, Kind.Float, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void floatDisjointArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { + callArraycopyTemplate(floatDisjointCallCounter, Kind.Float, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void floatAlignedArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { + callArraycopyTemplate(floatAlignedCallCounter, Kind.Float, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void floatAlignedDisjointArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { + callArraycopyTemplate(floatAlignedDisjointCallCounter, Kind.Float, true, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void longArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { + callArraycopyTemplate(longCallCounter, Kind.Long, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void longDisjointArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { + callArraycopyTemplate(longDisjointCallCounter, Kind.Long, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void longAlignedArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { + callArraycopyTemplate(longAlignedCallCounter, Kind.Long, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void longAlignedDisjointArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { + callArraycopyTemplate(longAlignedDisjointCallCounter, Kind.Long, true, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void doubleArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { + callArraycopyTemplate(doubleCallCounter, Kind.Double, false, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void doubleDisjointArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { + callArraycopyTemplate(doubleDisjointCallCounter, Kind.Double, false, true, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void doubleAlignedArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { + callArraycopyTemplate(doubleAlignedCallCounter, Kind.Double, true, false, src, srcPos, dest, destPos, length); + } + + @Snippet + public static void doubleAlignedDisjointArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { + callArraycopyTemplate(doubleAlignedDisjointCallCounter, Kind.Double, true, true, src, srcPos, dest, destPos, length); + } + private static final SnippetCounter.Group checkCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess"); private static final SnippetCounter checkNPECounter = new SnippetCounter(checkCounters, "checkNPE", "checkNPE"); @@ -210,6 +429,40 @@ private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays"); private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays"); private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays"); + + private static final SnippetCounter booleanAlignedCallCounter = new SnippetCounter(counters, "boolean[]", "aligned arraycopy call for boolean[] arrays"); + private static final SnippetCounter booleanAlignedDisjointCallCounter = new SnippetCounter(counters, "boolean[]", "aligned disjoint arraycopy call for boolean[] arrays"); + private static final SnippetCounter booleanCallCounter = new SnippetCounter(counters, "boolean[]", "arraycopy call for boolean[] arrays"); + private static final SnippetCounter booleanDisjointCallCounter = new SnippetCounter(counters, "boolean[]", "disjoint arraycopy call for boolean[] arrays"); + private static final SnippetCounter byteAlignedCallCounter = new SnippetCounter(counters, "byte[]", "aligned arraycopy call for byte[] arrays"); + private static final SnippetCounter byteAlignedDisjointCallCounter = new SnippetCounter(counters, "byte[]", "aligned disjoint arraycopy call for byte[] arrays"); + private static final SnippetCounter byteCallCounter = new SnippetCounter(counters, "byte[]", "arraycopy call for byte[] arrays"); + private static final SnippetCounter byteDisjointCallCounter = new SnippetCounter(counters, "byte[]", "disjoint arraycopy call for byte[] arrays"); + private static final SnippetCounter charAlignedCallCounter = new SnippetCounter(counters, "char[]", "aligned arraycopy call for char[] arrays"); + private static final SnippetCounter charAlignedDisjointCallCounter = new SnippetCounter(counters, "char[]", "aligned disjoint arraycopy call for char[] arrays"); + private static final SnippetCounter charCallCounter = new SnippetCounter(counters, "char[]", "arraycopy call for char[] arrays"); + private static final SnippetCounter charDisjointCallCounter = new SnippetCounter(counters, "char[]", "disjoint arraycopy call for char[] arrays"); + private static final SnippetCounter doubleAlignedCallCounter = new SnippetCounter(counters, "double[]", "aligned arraycopy call for double[] arrays"); + private static final SnippetCounter doubleAlignedDisjointCallCounter = new SnippetCounter(counters, "double[]", "aligned disjoint arraycopy call for double[] arrays"); + private static final SnippetCounter doubleCallCounter = new SnippetCounter(counters, "double[]", "arraycopy call for double[] arrays"); + private static final SnippetCounter doubleDisjointCallCounter = new SnippetCounter(counters, "double[]", "disjoint arraycopy call for double[] arrays"); + private static final SnippetCounter floatAlignedCallCounter = new SnippetCounter(counters, "float[]", "aligned arraycopy call for float[] arrays"); + private static final SnippetCounter floatAlignedDisjointCallCounter = new SnippetCounter(counters, "float[]", "aligned disjoint arraycopy call for float[] arrays"); + private static final SnippetCounter floatCallCounter = new SnippetCounter(counters, "float[]", "arraycopy call for float[] arrays"); + private static final SnippetCounter floatDisjointCallCounter = new SnippetCounter(counters, "float[]", "disjoint arraycopy call for float[] arrays"); + private static final SnippetCounter intAlignedCallCounter = new SnippetCounter(counters, "int[]", "aligned arraycopy call for int[] arrays"); + private static final SnippetCounter intAlignedDisjointCallCounter = new SnippetCounter(counters, "int[]", "aligned disjoint arraycopy call for int[] arrays"); + private static final SnippetCounter intCallCounter = new SnippetCounter(counters, "int[]", "arraycopy call for int[] arrays"); + private static final SnippetCounter intDisjointCallCounter = new SnippetCounter(counters, "int[]", "disjoint arraycopy call for int[] arrays"); + private static final SnippetCounter longAlignedCallCounter = new SnippetCounter(counters, "long[]", "aligned arraycopy call for long[] arrays"); + private static final SnippetCounter longAlignedDisjointCallCounter = new SnippetCounter(counters, "long[]", "aligned disjoint arraycopy call for long[] arrays"); + private static final SnippetCounter longCallCounter = new SnippetCounter(counters, "long[]", "arraycopy call for long[] arrays"); + private static final SnippetCounter longDisjointCallCounter = new SnippetCounter(counters, "long[]", "disjoint arraycopy call for long[] arrays"); + private static final SnippetCounter shortAlignedCallCounter = new SnippetCounter(counters, "short[]", "aligned arraycopy call for short[] arrays"); + private static final SnippetCounter shortAlignedDisjointCallCounter = new SnippetCounter(counters, "short[]", "aligned disjoint arraycopy call for short[] arrays"); + private static final SnippetCounter shortCallCounter = new SnippetCounter(counters, "short[]", "arraycopy call for short[] arrays"); + private static final SnippetCounter shortDisjointCallCounter = new SnippetCounter(counters, "short[]", "disjoint arraycopy call for short[] arrays"); + private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method"); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Mon Feb 17 13:48:41 2014 +0100 @@ -211,6 +211,11 @@ return Unsafe.getUnsafe().pageSize(); } + @Fold + public static int heapWordSize() { + return config().heapWordSize; + } + public static final LocationIdentity PROTOTYPE_MARK_WORD_LOCATION = new NamedLocationIdentity("PrototypeMarkWord"); @Fold @@ -718,14 +723,4 @@ throw new GraalInternalError(e); } } - - @Fold - public static long dllLoad() { - return config().libraryLoadAddress; - } - - @Fold - public static long dllLookup() { - return config().functionLookupAddress; - } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon Feb 17 13:48:41 2014 +0100 @@ -950,12 +950,16 @@ dims[i] = frameState.ipop(); } if (type instanceof ResolvedJavaType) { - frameState.apush(append(new NewMultiArrayNode((ResolvedJavaType) type, dims))); + frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims))); } else { handleUnresolvedNewMultiArray(type, dims); } } + protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, ValueNode[] dimensions) { + return new NewMultiArrayNode(type, dimensions); + } + private void genGetField(JavaField field) { emitExplicitExceptions(frameState.peek(0), null); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2b.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2b.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2b.java Mon Feb 17 13:48:41 2014 +0100 @@ -53,4 +53,27 @@ runTest("test", 128); } + public static int testInt(int a) { + return (byte) a; + } + + @Test + public void runI0() throws Throwable { + runTest("testInt", -1); + } + + @Test + public void runI1() throws Throwable { + runTest("testInt", 2); + } + + @Test + public void runI2() throws Throwable { + runTest("testInt", 255); + } + + @Test + public void runI3() throws Throwable { + runTest("testInt", 128); + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2c.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2c.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2c.java Mon Feb 17 13:48:41 2014 +0100 @@ -48,4 +48,22 @@ runTest("test", 65535); } + public static int testInt(int a) { + return (char) a; + } + + @Test + public void runI0() throws Throwable { + runTest("testInt", -1); + } + + @Test + public void runI1() throws Throwable { + runTest("testInt", 645); + } + + @Test + public void runI2() throws Throwable { + runTest("testInt", 65535); + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2s.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2s.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2s.java Mon Feb 17 13:48:41 2014 +0100 @@ -53,4 +53,27 @@ runTest("test", 32768); } + public static int testInt(int a) { + return (short) a; + } + + @Test + public void runI0() throws Throwable { + runTest("testInt", -1); + } + + @Test + public void runI1() throws Throwable { + runTest("testInt", 34); + } + + @Test + public void runI2() throws Throwable { + runTest("testInt", 65535); + } + + @Test + public void runI3() throws Throwable { + runTest("testInt", 32768); + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Mon Feb 17 13:48:41 2014 +0100 @@ -73,12 +73,23 @@ default: throw GraalInternalError.shouldNotReachHere(); } } else if (isConstant(y)) { + boolean isZero = ((Constant) y).isDefaultForKind(); switch (opcode) { - case ICMP: masm.cmpl(asIntReg(x), crb.asIntConst(y)); break; - case LCMP: masm.cmpq(asLongReg(x), crb.asIntConst(y)); break; + case ICMP: if (isZero) { + masm.testl(asIntReg(x), asIntReg(x)); + } else { + masm.cmpl(asIntReg(x), crb.asIntConst(y)); + } + break; + case LCMP: if (isZero) { + masm.testq(asLongReg(x), asLongReg(x)); + } else { + masm.cmpq(asLongReg(x), crb.asIntConst(y)); + } + break; case ACMP: - if (((Constant) y).isNull()) { - masm.cmpq(asObjectReg(x), 0); break; + if (isZero) { + masm.testq(asObjectReg(x), asObjectReg(x)); break; } else { throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons"); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Mon Feb 17 13:48:41 2014 +0100 @@ -61,28 +61,39 @@ protected final LabelRef trueDestination; protected final LabelRef falseDestination; - public BranchOp(Condition condition, LabelRef trueDestination, LabelRef falseDestination) { - this(intCond(condition), trueDestination, falseDestination); + private final double trueDestinationProbability; + + public BranchOp(Condition condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + this(intCond(condition), trueDestination, falseDestination, trueDestinationProbability); } - public BranchOp(ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination) { + public BranchOp(ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { this.condition = condition; this.trueDestination = trueDestination; this.falseDestination = falseDestination; + this.trueDestinationProbability = trueDestinationProbability; } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + /* + * The strategy for emitting jumps is: If either trueDestination or falseDestination is + * the successor block, assume the block scheduler did the correct thing and jcc to the + * other. Otherwise, we need a jcc followed by a jmp. Use the branch probability to make + * sure it is more likely to branch on the jcc (= less likely to execute both the jcc + * and the jmp instead of just the jcc). In the case of loops, that means the jcc is the + * back-edge. + */ if (crb.isSuccessorEdge(trueDestination)) { jcc(masm, true, falseDestination); - } else if (falseDestination.getSourceBlock() == falseDestination.getTargetBlock()) { + } else if (crb.isSuccessorEdge(falseDestination)) { + jcc(masm, false, trueDestination); + } else if (trueDestinationProbability < 0.5) { jcc(masm, true, falseDestination); masm.jmp(trueDestination.label()); } else { jcc(masm, false, trueDestination); - if (!crb.isSuccessorEdge(falseDestination)) { - masm.jmp(falseDestination.label()); - } + masm.jmp(falseDestination.label()); } } @@ -94,8 +105,8 @@ public static class FloatBranchOp extends BranchOp { protected boolean unorderedIsTrue; - public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination) { - super(floatCond(condition), trueDestination, falseDestination); + public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { + super(floatCond(condition), trueDestination, falseDestination, trueDestinationProbability); this.unorderedIsTrue = unorderedIsTrue; } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Mon Feb 17 13:48:41 2014 +0100 @@ -139,6 +139,8 @@ public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { switch (kind) { case Boolean: + masm.movzbl(asRegister(result), address.toAddress()); + break; case Byte: masm.movsbl(asRegister(result), address.toAddress()); break; diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Mon Feb 17 13:48:41 2014 +0100 @@ -122,6 +122,10 @@ return frameSize; } + public int outgoingSize() { + return outgoingSize; + } + /** * Determines if any space is used in the frame apart from the * {@link Architecture#getReturnAddressSize() return address slot}. diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Mon Feb 17 13:48:41 2014 +0100 @@ -160,7 +160,7 @@ public void recordInlineDataInCode(Constant data) { assert data != null; int pos = asm.codeBuffer.position(); - Debug.log("Inline data in code: pos = %d, data = %s", pos, data.toString()); + Debug.log("Inline data in code: pos = %d, data = %s", pos, data); compilationResult.recordInlineData(pos, data); } @@ -172,7 +172,7 @@ public AbstractAddress recordDataReferenceInCode(Data data) { assert data != null; int pos = asm.codeBuffer.position(); - Debug.log("Data reference in code: pos = %d, data = %s", pos, data.toString()); + Debug.log("Data reference in code: pos = %d, data = %s", pos, data); compilationResult.recordDataReference(pos, data); return asm.getPlaceholder(); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeFunctionHandle.java --- a/graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeFunctionHandle.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2014, 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.nfi.hotspot.amd64; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nfi.hotspot.amd64.util.*; -import com.oracle.graal.nodes.*; - -public class AMD64HotSpotNativeFunctionHandle implements NativeFunctionHandle { - - private final InstalledCode code; - private final String functionName; - - protected final HotSpotProviders providers; - protected final Backend backend; - - public AMD64HotSpotNativeFunctionHandle(HotSpotProviders providers, Backend backend, AMD64HotSpotNativeFunctionPointer functionPointer, Class returnType, Class[] argumentTypes) { - this.providers = providers; - this.backend = backend; - this.functionName = functionPointer.getFunctionName(); - StructuredGraph graph = NativeCallStubGraphBuilder.getGraph(providers, functionPointer, returnType, argumentTypes); - InstallUtil installer = new InstallUtil(providers, backend); - this.code = installer.install(graph); - } - - @Override - public Object call(Object[] args) { - try { - return code.execute(args, null, null); - } catch (InvalidInstalledCodeException e) { - throw GraalInternalError.shouldNotReachHere("Execution of GNFI Callstub failed: " + functionName); - } - } - - public InstalledCode getCallStub() { - return code; - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeFunctionInterface.java --- a/graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeFunctionInterface.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2014, 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.nfi.hotspot.amd64; - -import java.lang.reflect.*; - -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; - -public class AMD64HotSpotNativeFunctionInterface implements NativeFunctionInterface { - - private static final Class LOOKUP_FUNCTION_RETURNTYPE = long.class; - private static final Class[] LOOKUP_FUNCTION_SIGNATURE = new Class[]{long.class, long.class}; - - private static final Unsafe unsafe = getUnsafe(); - - private static final int STD_BUFFER_SIZE = 1024; - - protected final HotSpotProviders providers; - protected final Backend backend; - protected final AMD64HotSpotNativeLibraryHandle rtldDefault; - protected final AMD64HotSpotNativeFunctionPointer libraryLoadFunctionPointer; - protected final AMD64HotSpotNativeFunctionPointer functionLookupFunctionPointer; - - private AMD64HotSpotNativeFunctionHandle libraryLookupFunctionHandle; - private AMD64HotSpotNativeFunctionHandle dllLookupFunctionHandle; - - public AMD64HotSpotNativeFunctionInterface(HotSpotProviders providers, Backend backend, AMD64HotSpotNativeFunctionPointer libraryLoadFunctionPointer, - AMD64HotSpotNativeFunctionPointer functionLookUpFunctionPointer, AMD64HotSpotNativeLibraryHandle rtldDefault) { - this.rtldDefault = rtldDefault; - this.providers = providers; - this.backend = backend; - this.libraryLoadFunctionPointer = libraryLoadFunctionPointer; - this.functionLookupFunctionPointer = functionLookUpFunctionPointer; - } - - @Override - public AMD64HotSpotNativeLibraryHandle getLibraryHandle(String libPath) { - if (libraryLookupFunctionHandle == null) { - libraryLookupFunctionHandle = new AMD64HotSpotNativeFunctionHandle(providers, backend, libraryLoadFunctionPointer, long.class, new Class[]{long.class, long.class, int.class}); - } - - long allocatedMemory = -1; - try { - allocatedMemory = unsafe.allocateMemory(STD_BUFFER_SIZE); - } catch (OutOfMemoryError e) { - throw new AssertionError(); - } - - Object[] args = new Object[]{copyStringToMemory(libPath), allocatedMemory, STD_BUFFER_SIZE}; - long libraryHandle = (long) libraryLookupFunctionHandle.call(args); - unsafe.freeMemory(allocatedMemory); - return new AMD64HotSpotNativeLibraryHandle(libraryHandle); - } - - @Override - public AMD64HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle libraryHandle, String functionName, Class returnType, Class[] argumentTypes) { - AMD64HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(functionName, libraryHandle); - if (!functionPointer.isValid()) { - throw new IllegalStateException(functionName + " not found!"); - } - return getFunctionHandle(functionPointer, returnType, argumentTypes); - } - - @Override - public AMD64HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraryHandles, String functionName, Class returnType, Class[] argumentTypes) { - AMD64HotSpotNativeFunctionPointer functionPointer = null; - for (NativeLibraryHandle libraryHandle : libraryHandles) { - functionPointer = lookupFunctionPointer(functionName, libraryHandle); - if (functionPointer.isValid()) { - return new AMD64HotSpotNativeFunctionHandle(providers, backend, functionPointer, returnType, argumentTypes); - } - } - return getFunctionHandle(functionName, returnType, argumentTypes); - } - - @Override - public AMD64HotSpotNativeFunctionHandle getFunctionHandle(String functionName, Class returnType, Class[] argumentTypes) { - if (rtldDefault.asRawValue() == HotSpotVMConfig.INVALID_RTLD_DEFAULT_HANDLE) { - throw new AssertionError("No library provided or RTLD_DEFAULT not supported!"); - } - return getFunctionHandle(rtldDefault, functionName, returnType, argumentTypes); - } - - private AMD64HotSpotNativeFunctionPointer lookupFunctionPointer(String functionName, NativeLibraryHandle handle) { - - if (!functionLookupFunctionPointer.isValid()) { - throw new IllegalStateException("no dlsym function pointer"); - } - if (dllLookupFunctionHandle == null) { - dllLookupFunctionHandle = new AMD64HotSpotNativeFunctionHandle(providers, backend, functionLookupFunctionPointer, LOOKUP_FUNCTION_RETURNTYPE, LOOKUP_FUNCTION_SIGNATURE); - } - long allocatedMemory = copyStringToMemory(functionName); - Object[] args = new Object[]{handle, allocatedMemory}; - long functionPointer = (long) dllLookupFunctionHandle.call(args); - unsafe.freeMemory(allocatedMemory); - return new AMD64HotSpotNativeFunctionPointer(functionPointer, functionName); - } - - private static long copyStringToMemory(String str) { - int size = str.length(); - long ptr = unsafe.allocateMemory(size + 1); - for (int i = 0; i < size; i++) { - unsafe.putByte(ptr + i, (byte) str.charAt(i)); - } - unsafe.putByte(ptr + size, (byte) '\0'); - return ptr; - } - - private static Unsafe getUnsafe() { - try { - return Unsafe.getUnsafe(); - } catch (SecurityException e) { - } - try { - Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafeInstance.setAccessible(true); - return (Unsafe) theUnsafeInstance.get(Unsafe.class); - } catch (IllegalArgumentException | SecurityException | NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); - } - } - - @Override - public AMD64HotSpotNativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class returnType, Class[] argumentTypes) { - if (functionPointer instanceof AMD64HotSpotNativeFunctionPointer) { - if (!((AMD64HotSpotNativeFunctionPointer) functionPointer).isValid()) { - throw new IllegalStateException("Function Symbol not found"); - } - } else { - throw new IllegalStateException("AMD64 function pointer required!"); - } - return new AMD64HotSpotNativeFunctionHandle(providers, backend, (AMD64HotSpotNativeFunctionPointer) functionPointer, returnType, argumentTypes); - } - - @Override - public AMD64HotSpotNativeFunctionPointer getFunctionPointer(NativeLibraryHandle[] libraryHandles, String functionName) { - for (NativeLibraryHandle libraryHandle : libraryHandles) { - AMD64HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(functionName, libraryHandle); - if (functionPointer.isValid()) { - return functionPointer; - } - } - throw new LinkageError("Function not found: " + functionName); - } - - @Override - public NativeFunctionPointer getNativeFunctionPointerFromRawValue(long rawValue) { - return new AMD64HotSpotNativeFunctionPointer(rawValue, null); - } - -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeFunctionPointer.java --- a/graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeFunctionPointer.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2014, 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.nfi.hotspot.amd64; - -import com.oracle.graal.api.code.*; - -public class AMD64HotSpotNativeFunctionPointer implements NativeFunctionPointer { - - private final long functionPointer; - private final String functionName; - - public AMD64HotSpotNativeFunctionPointer(long functionPointer, String functionName) { - this.functionPointer = functionPointer; - this.functionName = functionName; - } - - public boolean isValid() { - return functionPointer != 0; - } - - @Override - public long asRawValue() { - return functionPointer; - } - - public String getFunctionName() { - return functionName; - } - -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeLibraryHandle.java --- a/graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/AMD64HotSpotNativeLibraryHandle.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2014, 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.nfi.hotspot.amd64; - -import com.oracle.graal.api.code.*; - -public class AMD64HotSpotNativeLibraryHandle implements NativeLibraryHandle { - - private final long handle; - - public AMD64HotSpotNativeLibraryHandle(long handle) { - this.handle = handle; - } - - public long asRawValue() { - return handle; - } - - public boolean isValid() { - return handle != 0; - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/node/AMD64RawNativeCallNode.java --- a/graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/node/AMD64RawNativeCallNode.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2014, 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.nfi.hotspot.amd64.node; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CallingConvention.Type; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.amd64.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -public class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRGenLowerable { - - private final Constant functionPointer; - @Input private final NodeInputList args; - - public AMD64RawNativeCallNode(Kind returnType, Constant functionPointer, ValueNode[] args) { - super(StampFactory.forKind(returnType)); - this.functionPointer = functionPointer; - this.args = new NodeInputList<>(this, args); - } - - @Override - public void generate(LIRGenerator generator) { - if (generator instanceof AMD64LIRGenerator) { - AMD64LIRGenerator amd64gen = (AMD64LIRGenerator) generator; - Value[] parameter = new Value[args.count()]; - JavaType[] parameterTypes = new JavaType[args.count()]; - for (int i = 0; i < args.count(); i++) { - parameter[i] = generator.operand(args.get(i)); - parameterTypes[i] = args.get(i).stamp().javaType(amd64gen.getMetaAccess()); - } - ResolvedJavaType returnType = stamp().javaType(amd64gen.getMetaAccess()); - CallingConvention cc = generator.getCodeCache().getRegisterConfig().getCallingConvention(Type.NativeCall, returnType, parameterTypes, generator.target(), false); - amd64gen.emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args)); - if (this.kind() != Kind.Void) { - generator.setResult(this, amd64gen.emitMove(cc.getReturn())); - } - } else { - throw GraalInternalError.shouldNotReachHere("GNFI Native call only supported with AMD64LIR Generator"); - } - } - - private static int countFloatingTypeArguments(NodeInputList args) { - int count = 0; - for (ValueNode n : args) { - if (n.kind() == Kind.Double || n.kind() == Kind.Float) { - count++; - } - } - if (count > 8) { - return 8; - } - return count; - } - -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/util/InstallUtil.java --- a/graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/util/InstallUtil.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2014, 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.nfi.hotspot.amd64.util; - -import static com.oracle.graal.api.code.CodeUtil.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CallingConvention.Type; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.ProfilingInfo.TriState; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.printer.*; - -/** - * Utility to install the code of the native call stub. - * - */ -public class InstallUtil { - - protected final HotSpotProviders providers; - protected final Backend backend; - - public InstallUtil(HotSpotProviders providers, Backend backend) { - DebugEnvironment.initialize(System.out); - this.providers = providers; - this.backend = backend; - } - - /** - * Attaches a graph to a method libCall. Compiles the graph and installs it. - * - * @param g the graph to be attached to a method and compiled - * @return returns the installed code that also holds a copy of graph g - */ - public InstalledCode install(final StructuredGraph g) { - try { - Suites suites = providers.getSuites().createSuites(); - PhaseSuite phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); - CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, g.method(), false); - CompilationResult compResult = GraalCompiler.compileGraph(g, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL, - DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, true, new CompilationResult(), CompilationResultBuilderFactory.Default); - InstalledCode installedCode; - try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) { - installedCode = providers.getCodeCache().addMethod(g.method(), compResult, null); - } - - return installedCode; - } catch (SecurityException e) { - throw GraalInternalError.shouldNotReachHere("Installation of GNFI Callstub failed."); - } - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/util/NativeCallStubGraphBuilder.java --- a/graal/com.oracle.graal.nfi.hotspot.amd64/src/com/oracle/graal/nfi/hotspot/amd64/util/NativeCallStubGraphBuilder.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2014, 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.nfi.hotspot.amd64.util; - -import java.util.*; - -import sun.misc.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nfi.hotspot.amd64.*; -import com.oracle.graal.nfi.hotspot.amd64.node.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.word.phases.*; - -/** - * Utility that creates a Graal graph. The graph represents the native call stub for a foreign - * target function. - * - */ -public class NativeCallStubGraphBuilder { - - private static final ResolvedJavaType integerJavaType = HotSpotResolvedObjectType.fromClass(Integer.class); - private static final ResolvedJavaField[] integerInstanceFields = integerJavaType.getInstanceFields(false); - private static final ResolvedJavaField integerValueField = getValueField(integerInstanceFields); - - private static final ResolvedJavaType longJavaType = HotSpotResolvedObjectType.fromClass(Long.class); - private static final ResolvedJavaField[] longInstanceFields = longJavaType.getInstanceFields(false); - private static final ResolvedJavaField longValueField = getValueField(longInstanceFields); - - private static final ResolvedJavaType charJavaType = HotSpotResolvedObjectType.fromClass(Character.class); - private static final ResolvedJavaField[] charInstanceFields = charJavaType.getInstanceFields(false); - private static final ResolvedJavaField charValueField = getValueField(charInstanceFields); - - private static final ResolvedJavaType byteJavaType = HotSpotResolvedObjectType.fromClass(Byte.class); - private static final ResolvedJavaField[] byteInstanceFields = byteJavaType.getInstanceFields(false); - private static final ResolvedJavaField byteValueField = getValueField(byteInstanceFields); - - private static final ResolvedJavaType floatJavaType = HotSpotResolvedObjectType.fromClass(Float.class); - private static final ResolvedJavaField[] floatInstanceFields = floatJavaType.getInstanceFields(false); - private static final ResolvedJavaField floatValueField = getValueField(floatInstanceFields); - - private static final ResolvedJavaType doubleJavaType = HotSpotResolvedObjectType.fromClass(Double.class); - private static final ResolvedJavaField[] doubleInstanceFields = doubleJavaType.getInstanceFields(false); - private static final ResolvedJavaField doubleValueField = getValueField(doubleInstanceFields); - - private static ResolvedJavaField getValueField(ResolvedJavaField[] fields) { - for (ResolvedJavaField field : fields) { - if (field.getName().equals("value")) { - return field; - } - } - throw new AssertionError("value field not found!"); - } - - /** - * Creates a Graal graph that represents the call stub for a foreign target function. - * - * @param providers the HotSpot providers - * @param functionPointer a function pointer that points to the foreign target function - * @param returnType the type of the return value - * @param argumentTypes the types of the arguments - * @return the graph that represents the call stub - */ - public static StructuredGraph getGraph(HotSpotProviders providers, AMD64HotSpotNativeFunctionPointer functionPointer, Class returnType, Class[] argumentTypes) { - ResolvedJavaMethod method; - try { - method = providers.getMetaAccess().lookupJavaMethod(NativeCallStubGraphBuilder.class.getMethod("libCall", Object.class, Object.class, Object.class)); - StructuredGraph g = new StructuredGraph(method); - ParameterNode arg0 = g.unique(new ParameterNode(0, StampFactory.forKind(Kind.Object))); - ParameterNode arg1 = g.unique(new ParameterNode(1, StampFactory.forKind(Kind.Object))); - ParameterNode arg2 = g.unique(new ParameterNode(2, StampFactory.forKind(Kind.Object))); - FrameState frameState = g.add(new FrameState(method, 0, Arrays.asList(new ValueNode[]{arg0, arg1, arg2}), 3, 0, false, false, new ArrayList(), - new ArrayList())); - g.start().setStateAfter(frameState); - List parameters = new ArrayList<>(); - FixedWithNextNode fixedWithNext = getParameters(g, arg0, argumentTypes.length, argumentTypes, parameters, providers); - Constant functionPointerNode = Constant.forLong(functionPointer.asRawValue()); - - ValueNode[] arguments = new ValueNode[parameters.size()]; - - for (int i = 0; i < arguments.length; i++) { - arguments[i] = parameters.get(i); - } - - AMD64RawNativeCallNode callNode = g.add(new AMD64RawNativeCallNode(getKind(returnType), functionPointerNode, arguments)); - - if (fixedWithNext == null) { - g.start().setNext(callNode); - } else { - fixedWithNext.setNext(callNode); - } - - // box result - BoxNode boxedResult; - if (callNode.kind() != Kind.Void) { - ResolvedJavaType type = getResolvedJavaType(callNode.kind()); - boxedResult = new BoxNode(callNode, type, callNode.kind()); - } else { - boxedResult = new BoxNode(ConstantNode.forLong(0, g), longJavaType, Kind.Long); - } - - // box result: - BoxNode boxNode = g.unique(boxedResult); - - ReturnNode returnNode = g.add(new ReturnNode(boxNode)); - callNode.setNext(returnNode); - (new WordTypeRewriterPhase(providers.getMetaAccess(), Kind.Long)).apply(g); - return g; - } catch (NoSuchMethodException | SecurityException e) { - throw GraalInternalError.shouldNotReachHere("Call Stub method not found"); - } - } - - private static FixedWithNextNode getParameters(StructuredGraph g, ParameterNode argumentsArray, int numArgs, Class[] argumentClass, List args, HotSpotProviders providers) { - assert numArgs == argumentClass.length; - FixedWithNextNode fixedWithNext = null; - for (int i = 0; i < numArgs; i++) { - // load boxed array element: - LoadIndexedNode boxedElement = g.add(new LoadIndexedNode(argumentsArray, ConstantNode.forInt(i, g), Kind.Object)); - if (i == 0) { - g.start().setNext(boxedElement); - fixedWithNext = boxedElement; - } else { - fixedWithNext.setNext(boxedElement); - fixedWithNext = boxedElement; - } - if (getKind(argumentClass[i]) == Kind.Object) { - // array value - Kind arrayElementKind = getArrayValuesKind(argumentClass[i]); - LocationIdentity locationIdentity = NamedLocationIdentity.getArrayLocation(arrayElementKind); - IndexedLocationNode locationNode = IndexedLocationNode.create(locationIdentity, arrayElementKind, HotSpotGraalRuntime.getArrayBaseOffset(arrayElementKind), ConstantNode.forInt(0, g), - g, HotSpotGraalRuntime.getArrayIndexScale(arrayElementKind)); - ComputeAddressNode arrayAddress = g.unique(new ComputeAddressNode(boxedElement, locationNode, StampFactory.forKind(providers.getCodeCache().getTarget().wordKind))); - args.add(arrayAddress); - } else { - // boxed primitive value - LoadFieldNode loadFieldNode = g.add(new LoadFieldNode(boxedElement, getResolvedJavaField(argumentClass[i]))); - fixedWithNext.setNext(loadFieldNode); - fixedWithNext = loadFieldNode; - args.add(loadFieldNode); - } - } - return fixedWithNext; - } - - public static int getArrayValuesObjectOffset(Class clazz) { - if (clazz == int[].class) { - return Unsafe.ARRAY_INT_BASE_OFFSET; - } else if (clazz == long[].class) { - return Unsafe.ARRAY_LONG_BASE_OFFSET; - } else if (clazz == char[].class) { - return Unsafe.ARRAY_CHAR_BASE_OFFSET; - } else if (clazz == byte[].class) { - return Unsafe.ARRAY_BYTE_BASE_OFFSET; - } else if (clazz == float[].class) { - return Unsafe.ARRAY_FLOAT_BASE_OFFSET; - } else if (clazz == double[].class) { - return Unsafe.ARRAY_DOUBLE_BASE_OFFSET; - } else { - throw new IllegalArgumentException("Array Type not supported: " + clazz); - } - } - - public static Kind getArrayValuesKind(Class clazz) { - if (clazz == int[].class) { - return Kind.Int; - } else if (clazz == long[].class) { - return Kind.Long; - } else if (clazz == char[].class) { - return Kind.Char; - } else if (clazz == byte[].class) { - return Kind.Byte; - } else if (clazz == float[].class) { - return Kind.Float; - } else if (clazz == double[].class) { - return Kind.Double; - } else { - throw new IllegalArgumentException("Array Type not supported: " + clazz); - } - } - - private static Kind getKind(Class clazz) { - if (clazz == int.class || clazz == Integer.class) { - return Kind.Int; - } else if (clazz == long.class || clazz == Long.class) { - return Kind.Long; - } else if (clazz == char.class || clazz == Character.class) { - return Kind.Char; - } else if (clazz == byte.class || clazz == Byte.class) { - return Kind.Byte; - } else if (clazz == float.class || clazz == Float.class) { - return Kind.Float; - } else if (clazz == double.class || clazz == Double.class) { - return Kind.Double; - } else if (clazz == int[].class || clazz == long[].class || clazz == char[].class || clazz == byte[].class || clazz == float[].class || clazz == double[].class) { - return Kind.Object; - } else if (clazz == void.class) { - return Kind.Void; - } else { - throw new IllegalArgumentException("Type not supported: " + clazz); - } - } - - private static ResolvedJavaField getResolvedJavaField(Class containerClass) { - if (containerClass == int.class || containerClass == Integer.class) { - return integerValueField; - } else if (containerClass == long.class || containerClass == Long.class) { - return longValueField; - } else if (containerClass == char.class || containerClass == Character.class) { - return charValueField; - } else if (containerClass == byte.class || containerClass == Byte.class) { - return byteValueField; - } else if (containerClass == float.class || containerClass == Float.class) { - return floatValueField; - } else if (containerClass == double.class || containerClass == Double.class) { - return doubleValueField; - } else { - throw new IllegalArgumentException("Type not supported: " + containerClass); - } - } - - private static ResolvedJavaType getResolvedJavaType(Kind kind) { - if (kind == Kind.Int) { - return integerJavaType; - } else if (kind == Kind.Long) { - return longJavaType; - } else if (kind == Kind.Char) { - return charJavaType; - } else if (kind == Kind.Byte) { - return byteJavaType; - } else if (kind == Kind.Float) { - return floatJavaType; - } else if (kind == Kind.Double) { - return doubleJavaType; - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - - @SuppressWarnings("unused") - public static Object libCall(Object argLoc, Object unused1, Object unused2) { - throw GraalInternalError.shouldNotReachHere("GNFI Callstub method must not be called!"); - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.test/test/com/oracle/graal/nfi/test/LibCallTest.java --- a/graal/com.oracle.graal.nfi.test/test/com/oracle/graal/nfi/test/LibCallTest.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.nfi.test; - -import java.lang.reflect.*; - -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.runtime.*; - -public class LibCallTest { - - protected static final Unsafe unsafe = getUnsafe(); - public final RuntimeProvider runtimeProvider; - public final NativeFunctionInterface ffi; - - public LibCallTest() { - this.runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class); - if (runtimeProvider.getHostBackend() instanceof HostBackend) { - ffi = ((HostBackend) runtimeProvider.getHostBackend()).getNativeFunctionInterface(); - } else { - throw GraalInternalError.shouldNotReachHere("Cannot initialize GNFI - backend is not a HostBackend"); - } - } - - protected long getDouble(double val) { - Long d = unsafe.allocateMemory(8); - unsafe.putDouble(d, val); - return d; - } - - protected long getLong(long val) { - Long d = unsafe.allocateMemory(8); - unsafe.putLong(d, val); - return d; - } - - protected long getInt(int val) { - Long d = unsafe.allocateMemory(4); - unsafe.putInt(d, val); - return d; - } - - protected void free(long p) { - unsafe.freeMemory(p); - } - - private static Unsafe getUnsafe() { - 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 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.test/test/com/oracle/graal/nfi/test/MathLibCallTest.java --- a/graal/com.oracle.graal.nfi.test/test/com/oracle/graal/nfi/test/MathLibCallTest.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.nfi.test; - -import org.junit.*; - -import com.oracle.graal.api.code.*; - -public class MathLibCallTest extends LibCallTest { - - private final Object[] args = new Object[]{Double.doubleToLongBits(3), Double.doubleToLongBits(5.5)}; - private final NativeFunctionHandle handle = ffi.getFunctionHandle("pow", double.class, new Class[]{double.class, double.class}); - - @Test - public void powTest() { - double result = (double) handle.call(args); - Assert.assertEquals(Math.pow(3, 5.5), result, 0); - } - - @Test - public void compilePowTest() { - double result = 0; - for (int i = 0; i < 100000; i++) { - result = callPow(); - } - Assert.assertEquals(Math.pow(3, 5.5), result, 0); - - } - - private double callPow() { - return (double) handle.call(args); - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nfi.test/test/com/oracle/graal/nfi/test/StdLibCallTest.java --- a/graal/com.oracle.graal.nfi.test/test/com/oracle/graal/nfi/test/StdLibCallTest.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.nfi.test; - -import org.junit.*; - -import com.oracle.graal.api.code.*; - -public class StdLibCallTest extends LibCallTest { - - private static void copyString(long pointer, String s) { - for (int i = 0; i < s.length(); i++) { - unsafe.putByte(pointer + i, (byte) s.charAt(i)); - } - unsafe.putByte(pointer + s.length(), (byte) '\0'); - } - - private static void checkString(long pointer, String s) { - for (int i = 0; i < s.length(); i++) { - Assert.assertEquals(unsafe.getByte(pointer + i) & 0xFF, (byte) s.charAt(i)); - } - Assert.assertEquals(unsafe.getByte(pointer + s.length()) & 0xFF, (byte) '\0'); - } - - private static long getBuffer(int length) { - return unsafe.allocateMemory(length); - } - - @Test - public void mallocTest() { - String string = "GRAAL"; - int stringLength = string.length() + 1; - - Object[] args = new Object[]{1}; - args[0] = stringLength; - NativeFunctionHandle mallocHandle = ffi.getFunctionHandle("malloc", long.class, new Class[]{int.class}); - - long p = (long) mallocHandle.call(args); - copyString(p, string); - - long buffer = getBuffer(stringLength); - NativeFunctionHandle putsHandle = ffi.getFunctionHandle("snprintf", int.class, new Class[]{long.class, int.class, long.class}); - Object[] args2 = new Object[]{buffer, stringLength, p}; - int result = (int) putsHandle.call(args2); - Assert.assertTrue(0 < result); - checkString(p, string); - checkString(buffer, string); - - NativeFunctionHandle freeHandle = ffi.getFunctionHandle("free", void.class, new Class[]{long.class}); - freeHandle.call(args2); - } - - @Test - public void printfSimpleTest() { - long str = unsafe.allocateMemory(8); - copyString(str, "AB %f%f"); - - String referenceString = "AB 1.0000001.000000"; - int referenceStringLenght = referenceString.length() + 1; - - long buffer = getBuffer(referenceStringLenght); - - Object[] args = new Object[]{buffer, referenceStringLenght, str, Double.doubleToRawLongBits(1.0), Double.doubleToRawLongBits(1.0)}; - NativeFunctionHandle printfHandle = ffi.getFunctionHandle("snprintf", int.class, new Class[]{long.class, int.class, long.class, double.class, double.class}); - - int result = (int) printfHandle.call(args); - - checkString(buffer, referenceString); - Assert.assertTrue(0 < result); - } - - @Test - public void printfTest() { - long str = unsafe.allocateMemory(25); - int[] val = new int[12]; - for (int i = 0; i < 12; i++) { - unsafe.putByte(str + 2 * i, (byte) '%'); - unsafe.putByte(str + 2 * i + 1, (byte) 'i'); - val[i] = i; - } - unsafe.putByte(str + 24, (byte) '\0'); - - String referenceString = "01234567891011"; - int referenceStringLenght = referenceString.length() + 1; - - long buffer = getBuffer(referenceStringLenght); - - Object[] args = new Object[]{buffer, referenceStringLenght, str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11]}; - NativeFunctionHandle printfHandle = ffi.getFunctionHandle("snprintf", int.class, new Class[]{long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, - int.class, int.class, int.class, int.class, int.class, int.class, int.class}); - - int result = (int) printfHandle.call(args); - checkString(buffer, referenceString); - Assert.assertTrue(0 < result); - } - - @Test - public void printfTest2() { - long str = unsafe.allocateMemory(49); - int[] val = new int[12]; - for (int i = 0; i < 12; i++) { - unsafe.putByte(str + 2 * i, (byte) '%'); - unsafe.putByte(str + 2 * i + 1, (byte) 'i'); - val[i] = i; - } - double[] dval = new double[12]; - for (int i = 12; i < 24; i++) { - unsafe.putByte(str + 2 * i, (byte) '%'); - unsafe.putByte(str + 2 * i + 1, (byte) 'f'); - dval[i - 12] = i + 0.5; - } - unsafe.putByte(str + 48, (byte) '\0'); - - String referenceString = "0123456789101112.50000013.50000014.50000015.50000016.50000017.50000018.50000019.50000020.500000" + "21.50000022.50000023.500000"; - int referenceStringLenght = referenceString.length() + 1; - - long buffer = getBuffer(referenceStringLenght); - - Object[] args = new Object[]{buffer, referenceStringLenght, str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], dval[0], dval[1], dval[2], - dval[3], dval[4], dval[5], dval[6], dval[7], dval[8], dval[9], dval[10], dval[11]}; - - NativeFunctionHandle printfHandle = ffi.getFunctionHandle("snprintf", int.class, new Class[]{long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, - int.class, int.class, int.class, int.class, int.class, int.class, int.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, - double.class, double.class, double.class, double.class, double.class}); - - int result = (int) printfHandle.call(args); - checkString(buffer, referenceString); - Assert.assertTrue(0 < result); - } - - @Test - public void printfTest3() { - long str = unsafe.allocateMemory(73); - int[] val = new int[12]; - for (int i = 0; i < 12; i++) { - unsafe.putByte(str + 2 * i, (byte) '%'); - unsafe.putByte(str + 2 * i + 1, (byte) 'i'); - val[i] = i; - } - double[] dval = new double[12]; - for (int i = 12; i < 24; i++) { - unsafe.putByte(str + 2 * i, (byte) '%'); - unsafe.putByte(str + 2 * i + 1, (byte) 'f'); - dval[i - 12] = i + 0.5; - } - char[] cval = new char[12]; - for (int i = 24; i < 36; i++) { - unsafe.putByte(str + 2 * i, (byte) '%'); - unsafe.putByte(str + 2 * i + 1, (byte) 'c'); - cval[i - 24] = (char) ('a' + (i - 24)); - } - unsafe.putByte(str + 72, (byte) '\0'); - - String referenceString = "0123456789101112.50000013.50000014.50000015.50000016.50000017.50000018.50000019.50000020.50000021.50000022.50000023.500000abcdefghijkl"; - int referenceStringLenght = referenceString.length() + 1; - - long buffer = getBuffer(referenceStringLenght); - - Object[] args = new Object[]{buffer, referenceStringLenght, str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], dval[0], dval[1], dval[2], - dval[3], dval[4], dval[5], dval[6], dval[7], dval[8], dval[9], dval[10], dval[11], cval[0], cval[1], cval[2], cval[3], cval[4], cval[5], cval[6], cval[7], cval[8], cval[9], - cval[10], cval[11]}; - - NativeFunctionHandle printfHandle = ffi.getFunctionHandle("snprintf", int.class, new Class[]{long.class, int.class, long.class, int.class, int.class, int.class, int.class, int.class, - int.class, int.class, int.class, int.class, int.class, int.class, int.class, double.class, double.class, double.class, double.class, double.class, double.class, double.class, - double.class, double.class, double.class, double.class, double.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, char.class, - char.class, char.class, char.class, char.class}); - - int result = (int) printfHandle.call(args); - checkString(buffer, referenceString); - Assert.assertTrue(0 < result); - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -36,7 +36,7 @@ * loop. */ @NodeInfo(nameTemplate = "{p#type/s}Proxy") -public class ProxyNode extends FloatingNode implements IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, ValueProxy, GuardingNode { +public class ProxyNode extends FloatingNode implements IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, ValueAndStampProxy, GuardingNode { @Input(notDataflow = true) private AbstractBeginNode proxyPoint; @Input private ValueNode value; diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -35,37 +35,16 @@ public static IntegerAddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) { assert v1.kind() == v2.kind(); - switch (v1.kind()) { - case Int: - return graph.unique(new IntegerAddNode(Kind.Int, v1, v2)); - case Long: - return graph.unique(new IntegerAddNode(Kind.Long, v1, v2)); - default: - throw ValueNodeUtil.shouldNotReachHere(); - } + return graph.unique(new IntegerAddNode(v1.kind(), v1, v2)); } public static IntegerMulNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) { assert v1.kind() == v2.kind(); - switch (v1.kind()) { - case Int: - return graph.unique(new IntegerMulNode(Kind.Int, v1, v2)); - case Long: - return graph.unique(new IntegerMulNode(Kind.Long, v1, v2)); - default: - throw ValueNodeUtil.shouldNotReachHere(); - } + return graph.unique(new IntegerMulNode(v1.kind(), v1, v2)); } public static IntegerSubNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) { assert v1.kind() == v2.kind(); - switch (v1.kind()) { - case Int: - return graph.unique(new IntegerSubNode(Kind.Int, v1, v2)); - case Long: - return graph.unique(new IntegerSubNode(Kind.Long, v1, v2)); - default: - throw ValueNodeUtil.shouldNotReachHere(); - } + return graph.unique(new IntegerSubNode(v1.kind(), v1, v2)); } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -71,7 +71,7 @@ public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool, boolean compressible) { MetaAccessProvider metaAccess = tool.getMetaAccess(); if (read.usages().isEmpty()) { - // Read without usages can be savely removed. + // Read without usages can be safely removed. return null; } if (tool.canonicalizeReads() && metaAccess != null && object != null && object.isConstant()) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -31,7 +31,7 @@ /** * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array. */ -public final class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable { +public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider { @Input private final NodeInputList dimensions; private final ResolvedJavaType type; @@ -74,4 +74,8 @@ public boolean canDeoptimize() { return true; } + + public ValueNode length() { + return dimension(0); + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ValueAndStampProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ValueAndStampProxy.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, 2014, 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.nodes.spi; + +/** + * This interface marks nodes whose result is the same as one of their inputs, and whose stamp is + * the same as one of their inputs. + * + * For some algorithms it is necessary or advantageous to see through these proxies. + */ +public interface ValueAndStampProxy extends ValueProxy { +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Mon Feb 17 13:48:41 2014 +0100 @@ -157,6 +157,7 @@ boolean needPrivateFieldAccessor = false; int i = 0; + Collections.sort(info.options); for (OptionInfo option : info.options) { String optionValue; if (option.field.getModifiers().contains(Modifier.PRIVATE)) { @@ -223,7 +224,7 @@ } } - static class OptionInfo { + static class OptionInfo implements Comparable { final String name; final String help; @@ -240,6 +241,11 @@ } @Override + public int compareTo(OptionInfo other) { + return name.compareTo(other.name); + } + + @Override public String toString() { return declaringClass + "." + field; } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon Feb 17 13:48:41 2014 +0100 @@ -428,6 +428,10 @@ return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); } + if (info.shouldInline()) { + return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); + } + double inliningBonus = getInliningBonus(info); int nodes = determineNodeCount(info); int lowLevelGraphSize = previousLowLevelGraphSize(info); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon Feb 17 13:48:41 2014 +0100 @@ -295,6 +295,8 @@ * Try to make the call static bindable to avoid interface and virtual method calls. */ void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions); + + boolean shouldInline(); } public abstract static class AbstractInlineInfo implements InlineInfo { @@ -411,6 +413,10 @@ assert index == 0; this.inlineableElement = inlineableElement; } + + public boolean shouldInline() { + return concrete.shouldBeInlined(); + } } /** @@ -497,6 +503,10 @@ public String toString() { return "type-checked with type " + type.getName() + " and method " + MetaUtil.format("%H.%n(%p):%r", concrete); } + + public boolean shouldInline() { + return concrete.shouldBeInlined(); + } } /** @@ -592,6 +602,15 @@ } } + public boolean shouldInline() { + for (ResolvedJavaMethod method : concretes) { + if (method.shouldBeInlined()) { + return true; + } + } + return false; + } + private boolean hasSingleMethod() { return concretes.size() == 1 && !shouldFallbackToInvoke(); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon Feb 17 13:48:41 2014 +0100 @@ -232,6 +232,9 @@ @Option(help = "Try to avoid emitting code where patching is required") public static final OptionValue ImmutableCode = new OptionValue<>(false); + @Option(help = "") + public static final OptionValue CallArrayCopy = new OptionValue<>(true); + // Runtime settings @Option(help = "") public static final OptionValue SupportJsrBytecodes = new OptionValue<>(true); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.phases.graph; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class InferStamps { + + /** + * Infer the stamps for all Object nodes in the graph, to make the stamps as precise as + * possible. For example, this propagates the word-type through phi functions. To handle phi + * functions at loop headers, the stamp inference is called until a fix point is reached. + *

+ * This method can be used when it is needed that stamps are inferred before the first run of + * the canonicalizer. For example, word type rewriting must run before the first run of the + * canonicalizer because many nodes are not prepared to see the word type during + * canonicalization. + */ + public static void inferStamps(StructuredGraph graph) { + /* + * We want to make the stamps more precise. For cyclic phi functions, this means we have to + * ignore the initial stamp because the imprecise stamp would always propagate around the + * cycle. We therefore set the stamp to an illegal stamp, which is automatically ignored + * when the phi function performs the "meet" operator on its input stamps. + */ + for (Node n : graph.getNodes()) { + if (n instanceof PhiNode || n instanceof ValueAndStampProxy) { + ValueNode node = (ValueNode) n; + if (node.kind() == Kind.Object) { + assert !(node.stamp() instanceof IllegalStamp) : "We assume all Phi and Proxy stamps are legal before the analysis"; + node.setStamp(StampFactory.illegal(node.kind())); + } + } + } + + boolean stampChanged; + do { + stampChanged = false; + /* + * We could use GraphOrder.forwardGraph() to process the nodes in a defined order and + * propagate long def-use chains in fewer iterations. However, measurements showed that + * we have few iterations anyway, and the overhead of computing the order is much higher + * than the benefit. + */ + for (Node n : graph.getNodes()) { + if (n instanceof ValueNode) { + ValueNode node = (ValueNode) n; + if (node.kind() == Kind.Object) { + stampChanged |= node.inferStamp(); + } + } + } + } while (stampChanged); + + /* + * Check that all the illegal stamps we introduced above are correctly replaced with real + * stamps again. + */ + assert checkNoIllegalStamp(graph); + } + + private static boolean checkNoIllegalStamp(StructuredGraph graph) { + for (Node n : graph.getNodes()) { + if (n instanceof PhiNode || n instanceof ValueAndStampProxy) { + ValueNode node = (ValueNode) n; + assert !(node.stamp() instanceof IllegalStamp) : "Stamp is illegal after analysis. This is not necessarily an error, but a condition that we want to investigate (and then maybe relax or remove the assertion)."; + } + } + return true; + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon Feb 17 13:48:41 2014 +0100 @@ -526,8 +526,10 @@ ParameterNode[] params = new ParameterNode[length]; Stamp stamp = varargs.stamp; for (int j = 0; j < length; j++) { - assert (parameterCount & 0xFFFF) == parameterCount; - int idx = i << 16 | j; + // Use a decimal friendly numbering make it more obvious how values map + assert parameterCount < 10000; + int idx = (i + 1) * 10000 + j; + assert idx >= parameterCount : "collision in parameter numbering"; ParameterNode local = snippetCopy.unique(new ParameterNode(idx, stamp)); params[j] = local; } @@ -542,6 +544,11 @@ LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(params, loadIndexed.index(), loadIndexed.stamp())); snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); Debug.dump(snippetCopy, "After replacing %s", loadIndexed); + } else if (usage instanceof StoreIndexedNode) { + // The template lowering doesn't really treat this as an array so you can't + // store back into the varargs. Allocate your own array if you really need + // this and EA should eliminate it. + throw new GraalInternalError("Can't store into VarargsParameter array"); } } } else { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -66,6 +66,11 @@ return index; } + @NodeIntrinsic + public static int scan(int v) { + return scan(v & 0xFFFFFFFFL); + } + @Override public void generate(LIRGenerator gen) { Variable result = gen.newVariable(Kind.Int); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java --- a/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java Mon Feb 17 13:48:41 2014 +0100 @@ -81,7 +81,7 @@ public void setInstrumentedMethod(ResolvedJavaMethod method) { HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; - hsMethod.setDontInline(); + hsMethod.setNotInlineable(); } public String getArchitecture() { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Feb 17 13:48:41 2014 +0100 @@ -73,13 +73,10 @@ } public RootCallTarget createCallTarget(RootNode rootNode) { - if (!acceptForCompilation(rootNode)) { - return new UnoptimizedCallTarget(rootNode); - } if (truffleCompiler == null) { truffleCompiler = new TruffleCompilerImpl(); } - return new OptimizedCallTarget(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue()); + return new OptimizedCallTarget(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode)); } @Override diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Feb 17 13:48:41 2014 +0100 @@ -38,7 +38,7 @@ /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. */ -public final class OptimizedCallTarget extends DefaultCallTarget implements FrameFactory, LoopCountReceiver, ReplaceObserver { +public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, ReplaceObserver { private static final PrintStream OUT = TTY.out().out(); @@ -52,7 +52,7 @@ private int callCount; private SpeculationLog speculationLog = new SpeculationLog(); - protected OptimizedCallTarget(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold) { + OptimizedCallTarget(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) { super(rootNode); this.compiler = compiler; this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); @@ -62,7 +62,7 @@ } else { compilationPolicy = new DefaultCompilationPolicy(); } - this.compilationEnabled = true; + this.compilationEnabled = compilationEnabled; if (TruffleCallTargetProfiling.getValue()) { registerCallTarget(this); @@ -79,13 +79,7 @@ private Object callHelper(PackedFrame caller, Arguments args) { if (installedCode != null && installedCode.isValid()) { - TruffleRuntime runtime = Truffle.getRuntime(); - if (runtime instanceof GraalTruffleRuntime) { - if (TraceTruffleCompilation.getValue()) { - OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut."); - } - GraalTruffleRuntime.installOptimizedCallTargetCallMethod(); - } + reinstallCallMethodShortcut(); } if (TruffleCallTargetProfiling.getValue()) { callCount++; @@ -101,6 +95,13 @@ } } + private static void reinstallCallMethodShortcut() { + if (TraceTruffleCompilation.getValue()) { + OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut."); + } + GraalTruffleRuntime.installOptimizedCallTargetCallMethod(); + } + public CompilationProfile getCompilationProfile() { return compilationProfile; } @@ -117,7 +118,7 @@ installedCode = null; compilationProfile.reportInvalidated(); if (TraceTruffleCompilation.getValue()) { - OUT.printf("[truffle] invalidated %-48s |Inv# %d |Replace# %d\n", getRootNode(), compilationProfile.getInvalidationCount(), + OUT.printf("[truffle] invalidated %-48s %08x |InvalidationCount %2d |ReplaceCount %3d\n", getRootNode(), getRootNode().hashCode(), compilationProfile.getInvalidationCount(), compilationProfile.getNodeReplaceCount()); } } @@ -221,11 +222,6 @@ } @Override - public VirtualFrame create(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { - return createFrame(descriptor, caller, args); - } - - @Override public void reportLoopCount(int count) { compilationProfile.reportLoopCount(count); } @@ -236,6 +232,10 @@ invalidate(); } + public SpeculationLog getSpeculationLog() { + return speculationLog; + } + private static void printProfiling() { List sortedCallTargets = new ArrayList<>(OptimizedCallTarget.callTargets.keySet()); Collections.sort(sortedCallTargets, new Comparator() { @@ -306,8 +306,4 @@ }); } } - - public SpeculationLog getSpeculationLog() { - return speculationLog; - } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon Feb 17 13:48:41 2014 +0100 @@ -208,6 +208,7 @@ if (TraceTruffleExpansion.getValue()) { expansionLogger.preExpand(methodCallTargetNode, inlineGraph); } + List invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot(); Map inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false); if (TraceTruffleExpansion.getValue()) { expansionLogger.postExpand(inlined); @@ -216,7 +217,7 @@ int nodeCountAfter = graph.getNodeCount(); Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter); } - canonicalizer.applyIncremental(graph, phaseContext, mark); + canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark); changed = true; } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Feb 17 13:48:41 2014 +0100 @@ -169,13 +169,18 @@ if (TraceTruffleCompilation.getValue()) { int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode(), null, true); byte[] code = compiledMethod.getCode(); - OUT.printf("[truffle] optimized %-50s %x |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", compilable.getRootNode(), compilable.hashCode(), nodeCountTruffle, + OUT.printf("[truffle] optimized %-50s %08x |Tree %8d |Time %5.0f(%4.0f+%-4.0f)ms |Graph %5d/%5d |CodeSize %6d @ %s\n", compilable.getRootNode(), compilable.hashCode(), nodeCountTruffle, (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, - (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, code != null ? code.length : 0); + (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, code != null ? code.length : 0, + formatSourceSection(compilable.getRootNode().getSourceSection())); } return compiledMethod; } + private static String formatSourceSection(SourceSection sourceSection) { + return sourceSection != null ? sourceSection.toString() : "n/a"; + } + private void printInlineTree(RootNode rootNode) { OUT.println(); OUT.println("Inlining tree for: " + rootNode); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Feb 17 13:48:41 2014 +0100 @@ -56,7 +56,7 @@ @Option(help = "") public static final OptionValue TruffleFunctionInlining = new OptionValue<>(true); @Option(help = "") - public static final OptionValue TruffleGraphMaxNodes = new OptionValue<>(25000); + public static final OptionValue TruffleGraphMaxNodes = new OptionValue<>(30000); @Option(help = "") public static final OptionValue TruffleInliningMaxRecursiveDepth = new OptionValue<>(2); @Option(help = "") diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Mon Feb 17 13:48:41 2014 +0100 @@ -115,7 +115,8 @@ private static void printCallSiteInfo(InliningPolicy policy, InlinableCallSiteInfo callSite, String msg) { String calls = String.format("%4s/%4s", callSite.getCallCount(), policy.callerInvocationCount); String nodes = String.format("%3s/%3s", callSite.getInlineNodeCount(), policy.callerNodeCount); - OUT.printf("[truffle] %-9s %-50s |Nodes %6s |Calls %6s %7.3f |%s\n", msg, callSite.getCallNode(), nodes, calls, policy.metric(callSite), callSite.getCallNode().getCallTarget()); + CallTarget inlined = callSite.getCallNode().getCallTarget(); + OUT.printf("[truffle] %-9s %-50s %08x |Tree %8s |Calls %6s %7.3f @ %s\n", msg, inlined, inlined.hashCode(), nodes, calls, policy.metric(callSite), callSite.getCallNode()); } private static final class InliningPolicy { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Mon Feb 17 13:48:41 2014 +0100 @@ -58,7 +58,6 @@ truffleReplacements.registerSubstitutions(FrameWithoutBoxingSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedAssumptionSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedCallTargetSubstitutions.class); - truffleReplacements.registerSubstitutions(DefaultCallTargetSubstitutions.class); return truffleReplacements; } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/UnoptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/UnoptimizedCallTarget.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.truffle; - -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Call target that is not optimized by Graal upon surpassing a specific invocation threshold. - */ -public final class UnoptimizedCallTarget extends DefaultCallTarget { - - protected UnoptimizedCallTarget(RootNode rootNode) { - super(rootNode); - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -74,7 +74,7 @@ @Override public void generate(LIRGenerator generator) { generator.setResult(this, generateArithmetic(generator)); - generator.emitOverflowCheckBranch(generator.getLIRBlock(getNext()), generator.getLIRBlock(getOverflowSuccessor())); + generator.emitOverflowCheckBranch(generator.getLIRBlock(getOverflowSuccessor()), generator.getLIRBlock(getNext()), probability(getOverflowSuccessor())); } protected abstract Value generateArithmetic(LIRGeneratorTool generator); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, 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.truffle.nodes.typesystem; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.truffle.api.*; + +/** + * Load of a final value from a location specified as an offset relative to an object. + * + * Substitution for method {@link CompilerDirectives#unsafeGetFinalObject} and friends. + */ +public class CustomizedUnsafeLoadFinalNode extends FixedWithNextNode implements Canonicalizable, Virtualizable, Lowerable { + @Input private ValueNode object; + @Input private ValueNode offset; + @Input private ValueNode condition; + @Input private ValueNode location; + private final Kind accessKind; + + public CustomizedUnsafeLoadFinalNode(ValueNode object, ValueNode offset, ValueNode condition, ValueNode location, Kind accessKind) { + super(StampFactory.forKind(accessKind.getStackKind())); + this.object = object; + this.offset = offset; + this.condition = condition; + this.location = location; + this.accessKind = accessKind; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (object.isConstant() && !object.isNullConstant() && offset.isConstant()) { + Constant constant = tool.getConstantReflection().readUnsafeConstant(accessKind, object.asConstant().asObject(), offset.asConstant().asLong(), accessKind == Kind.Object); + return ConstantNode.forConstant(constant, tool.getMetaAccess(), graph()); + } + return this; + } + + /** + * @see UnsafeLoadNode#virtualize(VirtualizerTool) + */ + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(object); + if (state != null && state.getState() == EscapeState.Virtual) { + ValueNode offsetValue = tool.getReplacedValue(offset); + if (offsetValue.isConstant()) { + long constantOffset = offsetValue.asConstant().asLong(); + int entryIndex = state.getVirtualObject().entryIndexForOffset(constantOffset); + if (entryIndex != -1) { + ValueNode entry = state.getEntry(entryIndex); + if (entry.kind() == kind() || state.getVirtualObject().entryKind(entryIndex) == accessKind) { + tool.replaceWith(entry); + } + } + } + } + } + + @Override + public void lower(LoweringTool tool) { + CompareNode compare = CompareNode.createCompareNode(graph(), Condition.EQ, condition, ConstantNode.forBoolean(true, graph())); + Object locationIdentityObject = location.asConstant().asObject(); + LocationIdentity locationIdentity; + if (locationIdentityObject == null) { + locationIdentity = LocationIdentity.ANY_LOCATION; + } else { + locationIdentity = ObjectLocationIdentity.create(locationIdentityObject); + } + UnsafeLoadNode result = graph().add(new UnsafeLoadNode(object, offset, accessKind, locationIdentity, compare)); + graph().replaceFixedWithFixed(this, result); + result.lower(tool); + } + + @SuppressWarnings("unused") + @NodeIntrinsic + public static T load(Object object, long offset, boolean condition, Object locationIdentity, @ConstantNodeParameter Kind kind) { + return UnsafeLoadNode.load(object, offset, kind, null); + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Mon Feb 17 13:48:41 2014 +0100 @@ -91,6 +91,9 @@ public static native int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity); @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true) + public static native long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity); + + @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true) public static native float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity); @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true) @@ -122,4 +125,44 @@ @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true) public static native void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity); + + @MethodSubstitution + public static boolean unsafeGetFinalBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Boolean); + } + + @MethodSubstitution + public static byte unsafeGetFinalByte(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Byte); + } + + @MethodSubstitution + public static short unsafeGetFinalShort(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Short); + } + + @MethodSubstitution + public static int unsafeGetFinalInt(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Int); + } + + @MethodSubstitution + public static long unsafeGetFinalLong(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Long); + } + + @MethodSubstitution + public static float unsafeGetFinalFloat(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Float); + } + + @MethodSubstitution + public static double unsafeGetFinalDouble(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Double); + } + + @MethodSubstitution + public static Object unsafeGetFinalObject(Object receiver, long offset, boolean condition, Object locationIdentity) { + return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Object); + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/DefaultCallTargetSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/DefaultCallTargetSubstitutions.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.truffle.substitutions; - -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.truffle.nodes.asserts.*; -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.impl.*; - -@ClassSubstitution(DefaultCallTarget.class) -public class DefaultCallTargetSubstitutions { - - @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) - public static native Object call(DefaultCallTarget target, PackedFrame caller, Arguments args); -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java Mon Feb 17 13:48:41 2014 +0100 @@ -46,10 +46,4 @@ private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { return NewFrameNode.allocate(descriptor, caller, args); } - - @SuppressWarnings("unused") - @MethodSubstitution(isStatic = false) - private static VirtualFrame create(OptimizedCallTarget target, FrameDescriptor descriptor, PackedFrame caller, Arguments args) { - return createFrame(descriptor, caller, args); - } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon Feb 17 13:48:41 2014 +0100 @@ -36,6 +36,7 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; import com.oracle.graal.word.*; import com.oracle.graal.word.Word.Opcode; import com.oracle.graal.word.Word.Operation; @@ -63,7 +64,7 @@ @Override protected void run(StructuredGraph graph) { - inferStamps(graph); + InferStamps.inferStamps(graph); for (Node n : graph.getNodes()) { if (n instanceof ValueNode) { @@ -77,68 +78,6 @@ } /** - * Infer the stamps for all Object nodes in the graph, to make the stamps as precise as - * possible. For example, this propagates the word-type through phi functions. To handle phi - * functions at loop headers, the stamp inference is called until a fix point is reached. - *

- * Note that we cannot rely on the normal canonicalizer to propagate stamps: The word type - * rewriting must run before the first run of the canonicalizer because many nodes are not - * prepared to see the word type during canonicalization. - */ - protected void inferStamps(StructuredGraph graph) { - /* - * We want to make the stamps more precise. For cyclic phi functions, this means we have to - * ignore the initial stamp because the imprecise stamp would always propagate around the - * cycle. We therefore set the stamp to an illegal stamp, which is automatically ignored - * when the phi function performs the "meet" operator on its input stamps. - */ - for (Node n : graph.getNodes()) { - if (n instanceof PhiNode || n instanceof ProxyNode) { - ValueNode node = (ValueNode) n; - if (node.kind() == Kind.Object) { - assert !(node.stamp() instanceof IllegalStamp) : "We assume all Phi and Proxy stamps are legal before the analysis"; - node.setStamp(StampFactory.illegal(node.kind())); - } - } - } - - boolean stampChanged; - do { - stampChanged = false; - /* - * We could use GraphOrder.forwardGraph() to process the nodes in a defined order and - * propagate long def-use chains in fewer iterations. However, measurements showed that - * we have few iterations anyway, and the overhead of computing the order is much higher - * than the benefit. - */ - for (Node n : graph.getNodes()) { - if (n instanceof ValueNode) { - ValueNode node = (ValueNode) n; - if (node.kind() == Kind.Object) { - stampChanged |= node.inferStamp(); - } - } - } - } while (stampChanged); - - /* - * Check that all the illegal stamps we introduced above are correctly replaced with real - * stamps again. - */ - assert checkNoIllegalStamp(graph); - } - - private static boolean checkNoIllegalStamp(StructuredGraph graph) { - for (Node n : graph.getNodes()) { - if (n instanceof PhiNode || n instanceof ProxyNode) { - ValueNode node = (ValueNode) n; - assert !(node.stamp() instanceof IllegalStamp) : "Stamp is illegal after analysis. This is not necessarily an error, but a condition that we want to investigate (and then maybe relax or remove the assertion)."; - } - } - return true; - } - - /** * Change the stamp for word nodes from the object stamp ({@link WordBase} or anything extending * or implementing that interface) to the primitive word stamp. */ diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Mon Feb 17 13:48:41 2014 +0100 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; import com.oracle.graal.word.*; import com.oracle.graal.word.Word.Operation; @@ -58,7 +59,7 @@ * modifies the stamp of nodes, we copy the graph before running the verification. */ StructuredGraph graph = inputGraph.copy(); - wordAccess.inferStamps(graph); + InferStamps.inferStamps(graph); for (ValueNode node : graph.getNodes().filter(ValueNode.class)) { if (!node.recordsUsages()) { @@ -81,7 +82,6 @@ } else if (usage instanceof StoreIndexedNode) { verify(!isWord(node) || ((StoreIndexedNode) usage).array() != node, node, usage, "cannot store to word value"); verify(!isWord(node) || ((StoreIndexedNode) usage).index() != node, node, usage, "cannot use word value as index"); - verify(!isWord(node) || ((StoreIndexedNode) usage).value() != node, node, usage, "cannot store word value to array"); } else if (usage instanceof MethodCallTargetNode) { MethodCallTargetNode callTarget = (MethodCallTargetNode) usage; verifyInvoke(node, callTarget); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Mon Feb 17 13:48:41 2014 +0100 @@ -242,7 +242,7 @@ } /** - * Unsafe access to a int value within an object. The condition parameter gives a hint to the + * Unsafe access to an int value within an object. The condition parameter gives a hint to the * compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. @@ -314,8 +314,8 @@ } /** - * Unsafe access to a Object value within an object. The condition parameter gives a hint to the - * compiler under which circumstances this access can be moved to an earlier location in the + * Unsafe access to an Object value within an object. The condition parameter gives a hint to + * the compiler under which circumstances this access can be moved to an earlier location in the * program. The location identity gives a hint to the compiler for improved global value * numbering. * @@ -374,7 +374,7 @@ } /** - * Write a int value within an object. The location identity gives a hint to the compiler for + * Write an int value within an object. The location identity gives a hint to the compiler for * improved global value numbering. * * @param receiver the object that is written to @@ -430,8 +430,8 @@ } /** - * Write a Object value within an object. The location identity gives a hint to the compiler for - * improved global value numbering. + * Write an Object value within an object. The location identity gives a hint to the compiler + * for improved global value numbering. * * @param receiver the object that is written to * @param offset the offset at which to write to the object in bytes @@ -444,6 +444,150 @@ } /** + * Unsafe access to a final boolean value within an object. The condition parameter gives a hint + * to the compiler under which circumstances this access can be moved to an earlier location in + * the program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static boolean unsafeGetFinalBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getBoolean(receiver, offset); + } + + /** + * Unsafe access to a final byte value within an object. The condition parameter gives a hint to + * the compiler under which circumstances this access can be moved to an earlier location in the + * program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static byte unsafeGetFinalByte(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getByte(receiver, offset); + } + + /** + * Unsafe access to a final short value within an object. The condition parameter gives a hint + * to the compiler under which circumstances this access can be moved to an earlier location in + * the program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static short unsafeGetFinalShort(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getShort(receiver, offset); + } + + /** + * Unsafe access to a final int value within an object. The condition parameter gives a hint to + * the compiler under which circumstances this access can be moved to an earlier location in the + * program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static int unsafeGetFinalInt(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getInt(receiver, offset); + } + + /** + * Unsafe access to a final long value within an object. The condition parameter gives a hint to + * the compiler under which circumstances this access can be moved to an earlier location in the + * program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static long unsafeGetFinalLong(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getLong(receiver, offset); + } + + /** + * Unsafe access to a final float value within an object. The condition parameter gives a hint + * to the compiler under which circumstances this access can be moved to an earlier location in + * the program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static float unsafeGetFinalFloat(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getFloat(receiver, offset); + } + + /** + * Unsafe access to a final double value within an object. The condition parameter gives a hint + * to the compiler under which circumstances this access can be moved to an earlier location in + * the program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static double unsafeGetFinalDouble(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getDouble(receiver, offset); + } + + /** + * Unsafe access to a final Object value within an object. The condition parameter gives a hint + * to the compiler under which circumstances this access can be moved to an earlier location in + * the program. The location identity gives a hint to the compiler for improved global value + * numbering. + * + * @param receiver the object that is accessed + * @param offset the offset at which to access the object in bytes + * @param condition the condition that makes this access safe also at an earlier location in the + * program + * @param locationIdentity the location identity token that can be used for improved global + * value numbering or null + * @return the accessed value + */ + public static Object unsafeGetFinalObject(Object receiver, long offset, boolean condition, Object locationIdentity) { + return UNSAFE.getObject(receiver, offset); + } + + /** * Marks methods that are considered slowpath and should therefore not be inlined by default. */ @Retention(RetentionPolicy.RUNTIME) diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/FrameFactory.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/FrameFactory.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.nodes; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; - -/** - * Factory for virtual frame creation. - */ -public interface FrameFactory { - - /** - * Creates a new virtual frame from the given frame descriptor and arguments. - * - * @param descriptor describes the frame to be created - * @param caller the packed caller frame or {@code null} - * @param args {@link Arguments} object to be stored in the frame - * @return a new virtual frame - */ - VirtualFrame create(FrameDescriptor descriptor, PackedFrame caller, Arguments args); -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Feb 17 13:48:41 2014 +0100 @@ -172,7 +172,7 @@ * @return the new node */ public final T replace(T newNode, String reason) { - CompilerDirectives.transferToInterpreter(); + CompilerDirectives.transferToInterpreterAndInvalidate(); if (this.getParent() == null) { throw new IllegalStateException("This node cannot be replaced, because it does not yet have a parent."); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -211,27 +211,35 @@ } public void leave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, (Object) result); } public void leave(Node astNode, VirtualFrame frame, Object result) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java Mon Feb 17 13:48:41 2014 +0100 @@ -17,6 +17,7 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.ruby.nodes.*; import com.oracle.truffle.ruby.nodes.control.*; +import com.oracle.truffle.ruby.nodes.debug.*; import com.oracle.truffle.ruby.nodes.methods.arguments.*; import com.oracle.truffle.ruby.nodes.objects.*; import com.oracle.truffle.ruby.runtime.*; @@ -30,7 +31,13 @@ * given the Object class object, which should already be initialized with all the core classes. */ public static void addMethods(RubyClass rubyObjectClass) { - for (MethodDetails methodDetails : getMethods()) { + addMethods(rubyObjectClass, getMethods()); + } + + public static void addMethods(RubyClass rubyObjectClass, List methods) { + // Same as above, but allows passing of a specific list of core methods. + // This allows extending Truffle-Ruby with non-standard Core Method. + for (MethodDetails methodDetails : methods) { addMethod(rubyObjectClass, methodDetails); } } @@ -74,13 +81,14 @@ getMethods(methods, ThreadNodesFactory.getFactories()); getMethods(methods, TimeNodesFactory.getFactories()); getMethods(methods, TrueClassNodesFactory.getFactories()); + getMethods(methods, DebugNodesFactory.getFactories()); return methods; } /** * Collect up the core methods created by a factory. */ - private static void getMethods(List methods, List> nodeFactories) { + public static void getMethods(List methods, List> nodeFactories) { for (NodeFactory nodeFactory : nodeFactories) { final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class); final Class nodeClass = generatedBy.value(); diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveEnterDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveEnterDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.ruby.nodes.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.core.*; + +public abstract class ActiveEnterDebugProbe extends RubyProbe { + + private final Assumption activeAssumption; + + private final InlinableMethodImplementation inlinable; + private final RubyRootNode inlinedRoot; + + public ActiveEnterDebugProbe(RubyContext context, Assumption activeAssumption, RubyProc proc) { + super(context, false); + this.activeAssumption = activeAssumption; + inlinable = ((InlinableMethodImplementation) proc.getMethod().getImplementation()); + inlinedRoot = inlinable.getCloneOfPristineRootNode(); + } + + @Override + public void enter(Node astNode, VirtualFrame frame) { + try { + activeAssumption.check(); + } catch (InvalidAssumptionException e) { + replace(createInactive()); + return; + } + + final RubyArguments arguments = new RubyArguments(inlinable.getDeclarationFrame(), NilPlaceholder.INSTANCE, null, 14); + final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, inlinable.getFrameDescriptor()); + inlinedRoot.execute(inlinedFrame); + } + + protected abstract InactiveEnterDebugProbe createInactive(); + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveLeaveDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveLeaveDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.ruby.nodes.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.core.*; + +public abstract class ActiveLeaveDebugProbe extends RubyProbe { + + private final Assumption activeAssumption; + + private final InlinableMethodImplementation inlinable; + private final RubyRootNode inlinedRoot; + + public ActiveLeaveDebugProbe(RubyContext context, Assumption activeAssumption, RubyProc proc) { + super(context, false); + this.activeAssumption = activeAssumption; + inlinable = ((InlinableMethodImplementation) proc.getMethod().getImplementation()); + inlinedRoot = inlinable.getCloneOfPristineRootNode(); + } + + @Override + public void leave(Node astNode, VirtualFrame frame, Object result) { + try { + activeAssumption.check(); + } catch (InvalidAssumptionException e) { + replace(createInactive()); + return; + } + + final RubyArguments arguments = new RubyArguments(inlinable.getDeclarationFrame(), NilPlaceholder.INSTANCE, null, result); + final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, inlinable.getFrameDescriptor()); + inlinedRoot.execute(inlinedFrame); + } + + protected abstract InactiveLeaveDebugProbe createInactive(); + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveLineDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveLineDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.source.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.core.*; +import com.oracle.truffle.ruby.runtime.debug.*; + +public class ActiveLineDebugProbe extends ActiveEnterDebugProbe { + + private final SourceLineLocation sourceLine; + + public ActiveLineDebugProbe(RubyContext context, SourceLineLocation sourceLine, Assumption activeAssumption, RubyProc proc) { + super(context, activeAssumption, proc); + this.sourceLine = sourceLine; + } + + @Override + protected InactiveEnterDebugProbe createInactive() { + final RubyContext rubyContext = (RubyContext) getContext(); + final RubyDebugManager manager = rubyContext.getRubyDebugManager(); + return new InactiveLineDebugProbe(rubyContext, sourceLine, manager.getAssumption(sourceLine)); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveLocalDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/ActiveLocalDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.core.*; +import com.oracle.truffle.ruby.runtime.debug.*; + +public class ActiveLocalDebugProbe extends ActiveLeaveDebugProbe { + + private final MethodLocal methodLocal; + + public ActiveLocalDebugProbe(RubyContext context, MethodLocal methodLocal, Assumption activeAssumption, RubyProc proc) { + super(context, activeAssumption, proc); + this.methodLocal = methodLocal; + } + + @Override + protected InactiveLeaveDebugProbe createInactive() { + final RubyContext rubyContext = (RubyContext) getContext(); + final RubyDebugManager manager = rubyContext.getRubyDebugManager(); + return new InactiveLocalDebugProbe(rubyContext, methodLocal, manager.getAssumption(methodLocal)); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/DebugNodes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/DebugNodes.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.*; +import com.oracle.truffle.ruby.nodes.core.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.control.*; +import com.oracle.truffle.ruby.runtime.core.*; +import com.oracle.truffle.ruby.runtime.debug.*; +import com.oracle.truffle.ruby.runtime.methods.*; + +@CoreClass(name = "Debug") +public abstract class DebugNodes { + + @CoreMethod(names = "break", isModuleMethod = true, needsSelf = false, needsBlock = true, appendCallNode = true, minArgs = 0, maxArgs = 3) + public abstract static class BreakNode extends CoreMethodNode { + + public BreakNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public BreakNode(BreakNode prev) { + super(prev); + } + + @Specialization(order = 1) + public NilPlaceholder debugBreak(VirtualFrame frame, Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder undefined0, @SuppressWarnings("unused") UndefinedPlaceholder undefined1, + @SuppressWarnings("unused") UndefinedPlaceholder block) { + getContext().runShell(callNode, frame.materialize()); + return NilPlaceholder.INSTANCE; + } + + @Specialization(order = 2) + public NilPlaceholder debugBreak(RubyString fileName, int line, @SuppressWarnings("unused") Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder block) { + final RubyContext context = getContext(); + if (context.getConfiguration().getDebug()) { + final Source source = context.getSourceManager().get(fileName.toString()); + final SourceLineLocation lineLocation = new SourceLineLocation(source, line); + context.getRubyDebugManager().setBreakpoint(lineLocation, null); + } + return NilPlaceholder.INSTANCE; + } + + @Specialization(order = 3) + public NilPlaceholder debugBreak(RubyString fileName, int line, @SuppressWarnings("unused") Node callNode, RubyProc block) { + final RubyContext context = getContext(); + if (context.getConfiguration().getDebug()) { + final Source source = context.getSourceManager().get(fileName.toString()); + final SourceLineLocation lineLocation = new SourceLineLocation(source, line); + context.getRubyDebugManager().setBreakpoint(lineLocation, block); + } + return NilPlaceholder.INSTANCE; + } + + @Specialization(order = 4) + public NilPlaceholder debugBreak(RubySymbol methodName, RubySymbol localName, @SuppressWarnings("unused") Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder block) { + final RubyContext context = getContext(); + if (context.getConfiguration().getDebug()) { + final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString()); + final MethodLocal methodLocal = new MethodLocal(method.getUniqueIdentifier(), localName.toString()); + context.getRubyDebugManager().setBreakpoint(methodLocal, null); + } + return NilPlaceholder.INSTANCE; + } + + @Specialization(order = 5) + public NilPlaceholder debugBreak(RubySymbol methodName, RubySymbol localName, @SuppressWarnings("unused") Node callNode, RubyProc block) { + final RubyContext context = getContext(); + if (context.getConfiguration().getDebug()) { + final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString()); + final MethodLocal methodLocal = new MethodLocal(method.getUniqueIdentifier(), localName.toString()); + context.getRubyDebugManager().setBreakpoint(methodLocal, block); + } + return NilPlaceholder.INSTANCE; + } + + } + + @CoreMethod(names = "continue", isModuleMethod = true, needsSelf = false, maxArgs = 0) + public abstract static class ContinueNode extends CoreMethodNode { + + public ContinueNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public ContinueNode(ContinueNode prev) { + super(prev); + } + + @Specialization + public Object debugContinue() { + if (getContext().getConfiguration().getDebug()) { + throw new BreakShellException(); + } + return NilPlaceholder.INSTANCE; + } + + } + + @CoreMethod(names = "enabled?", isModuleMethod = true, needsSelf = false, maxArgs = 0) + public abstract static class EnabledNode extends CoreMethodNode { + + public EnabledNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public EnabledNode(ContinueNode prev) { + super(prev); + } + + @Specialization + public boolean enabled() { + return getContext().getConfiguration().getDebug(); + } + + } + + @CoreMethod(names = "where", isModuleMethod = true, needsSelf = false, appendCallNode = true, minArgs = 1, maxArgs = 1) + public abstract static class WhereNode extends CoreMethodNode { + + public WhereNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public WhereNode(WhereNode prev) { + super(prev); + } + + @Specialization + public NilPlaceholder where(Node callNode) { + getContext().getConfiguration().getStandardOut().println(callNode.getSourceSection()); + return NilPlaceholder.INSTANCE; + } + + } + + @CoreMethod(names = "remove", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 2, maxArgs = 2) + public abstract static class RemoveNode extends CoreMethodNode { + + public RemoveNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public RemoveNode(RemoveNode prev) { + super(prev); + } + + @Specialization + public NilPlaceholder debugRemove(RubyString fileName, int line) { + final RubyContext context = getContext(); + if (context.getConfiguration().getDebug()) { + final Source source = context.getSourceManager().get(fileName.toString()); + final SourceLineLocation lineLocation = new SourceLineLocation(source, line); + context.getRubyDebugManager().removeBreakpoint(lineLocation); + } + return NilPlaceholder.INSTANCE; + } + + @Specialization + public NilPlaceholder debugRemove(RubySymbol methodName, RubySymbol localName) { + final RubyContext context = getContext(); + if (context.getConfiguration().getDebug()) { + final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString()); + final MethodLocal methodLocal = new MethodLocal(method.getUniqueIdentifier(), localName.toString()); + context.getRubyDebugManager().removeBreakpoint(methodLocal); + } + return NilPlaceholder.INSTANCE; + } + + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveEnterDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveEnterDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.ruby.runtime.*; + +public abstract class InactiveEnterDebugProbe extends RubyProbe { + + private final Assumption inactiveAssumption; + + public InactiveEnterDebugProbe(RubyContext context, Assumption inactiveAssumption) { + super(context, false); + this.inactiveAssumption = inactiveAssumption; + } + + @Override + public void enter(Node astNode, VirtualFrame frame) { + try { + inactiveAssumption.check(); + } catch (InvalidAssumptionException e) { + final ActiveEnterDebugProbe activeNode = createActive(); + replace(activeNode); + activeNode.enter(astNode, frame); + } + } + + protected abstract ActiveEnterDebugProbe createActive(); + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveLeaveDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveLeaveDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.ruby.runtime.*; + +public abstract class InactiveLeaveDebugProbe extends RubyProbe { + + private final Assumption inactiveAssumption; + + public InactiveLeaveDebugProbe(RubyContext context, Assumption inactiveAssumption) { + super(context, false); + this.inactiveAssumption = inactiveAssumption; + } + + @Override + public void leave(Node astNode, VirtualFrame frame, Object result) { + try { + inactiveAssumption.check(); + } catch (InvalidAssumptionException e) { + final ActiveLeaveDebugProbe activeNode = createActive(); + replace(activeNode); + activeNode.leave(astNode, frame, result); + } + } + + protected abstract ActiveLeaveDebugProbe createActive(); + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveLineDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveLineDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.source.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.debug.*; + +public class InactiveLineDebugProbe extends InactiveEnterDebugProbe { + + private final SourceLineLocation sourceLine; + + public InactiveLineDebugProbe(RubyContext context, SourceLineLocation sourceLine, Assumption inactiveAssumption) { + super(context, inactiveAssumption); + this.sourceLine = sourceLine; + } + + @Override + protected ActiveEnterDebugProbe createActive() { + final RubyContext rubyContext = (RubyContext) getContext(); + final RubyDebugManager manager = rubyContext.getRubyDebugManager(); + return new ActiveLineDebugProbe(rubyContext, sourceLine, manager.getAssumption(sourceLine), manager.getBreakpoint(sourceLine)); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveLocalDebugProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/InactiveLocalDebugProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.debug.*; + +public class InactiveLocalDebugProbe extends InactiveLeaveDebugProbe { + + private final MethodLocal methodLocal; + + public InactiveLocalDebugProbe(RubyContext context, MethodLocal methodLocal, Assumption inactiveAssumption) { + super(context, inactiveAssumption); + this.methodLocal = methodLocal; + } + + @Override + protected ActiveLeaveDebugProbe createActive() { + final RubyContext rubyContext = (RubyContext) getContext(); + final RubyDebugManager manager = rubyContext.getRubyDebugManager(); + return new ActiveLocalDebugProbe(rubyContext, methodLocal, manager.getAssumption(methodLocal), manager.getBreakpoint(methodLocal)); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.nodes.instrument.*; +import com.oracle.truffle.ruby.runtime.*; + +/** + * A "probe node" implemented specifically for the Ruby implementation; subclasses need only + * override those members of {@link InstrumentationProbeEvents} for which some action is needed. + */ +public abstract class RubyProbe extends InstrumentationProbeNode.DefaultProbeNode { + + protected final boolean oneShot; + + protected final RubyContext context; + + /** + * OneShot is this a one-shot (self-removing) probe? + */ + public RubyProbe(RubyContext context, boolean oneShot) { + super(context); + this.oneShot = oneShot; + this.context = context; + } + + /** + * Is this a one-shot (self-removing) probe? If so, it will remove itself the first time + * activated. + */ + public boolean isOneShot() { + return oneShot; + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyTraceProbe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyTraceProbe.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.nodes.debug; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.subsystems.*; + +/** + * A "trace" probe that has no runtime cost until activated, at which time it invokes a trace + * message. + */ +public final class RubyTraceProbe extends RubyProbe { + + private final Assumption notTracingAssumption; + + @CompilerDirectives.CompilationFinal private boolean tracingEverEnabled = false; + + public RubyTraceProbe(RubyContext context) { + super(context, false); + this.notTracingAssumption = context.getTraceManager().getNotTracingAssumption(); + } + + @Override + public void enter(Node astNode, VirtualFrame frame) { + if (!tracingEverEnabled) { + try { + notTracingAssumption.check(); + } catch (InvalidAssumptionException e) { + tracingEverEnabled = true; + } + } + final TraceManager traceManager = context.getTraceManager(); + if (tracingEverEnabled && traceManager.hasTraceProc()) { + final SourceSection sourceSection = astNode.getEncapsulatingSourceSection(); + traceManager.trace("line", sourceSection.getSource().getName(), sourceSection.getStartLine(), 0, null, null); + } + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DefaultRubyNodeInstrumenter.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DefaultRubyNodeInstrumenter.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DefaultRubyNodeInstrumenter.java Mon Feb 17 13:48:41 2014 +0100 @@ -9,7 +9,9 @@ */ package com.oracle.truffle.ruby.parser; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.instrument.*; +import com.oracle.truffle.api.source.*; import com.oracle.truffle.ruby.nodes.*; import com.oracle.truffle.ruby.nodes.debug.*; import com.oracle.truffle.ruby.runtime.*; @@ -26,17 +28,33 @@ public DefaultRubyNodeInstrumenter() { } - public RubyNode instrumentAsStatement(RubyNode rubyNode) { - assert rubyNode != null; - assert !(rubyNode instanceof RubyProxyNode); - final RubyContext context = rubyNode.getContext(); + public RubyNode instrumentAsStatement(RubyNode node) { + assert node != null; + + final RubyContext context = node.getContext(); + + RubyProxyNode proxy; + + if (node instanceof RubyProxyNode) { + proxy = (RubyProxyNode) node; + } else { + proxy = new RubyProxyNode(node.getContext(), node); + proxy.markAs(NodePhylum.STATEMENT); + proxy.clearSourceSection(); + proxy.assignSourceSection(node.getSourceSection()); + } + if (context.getConfiguration().getTrace()) { - final RubyProxyNode proxy = new RubyProxyNode(context, rubyNode); - proxy.markAs(NodePhylum.STATEMENT); proxy.getProbeChain().appendProbe(new RubyTraceProbe(context)); - return proxy; } - return rubyNode; + + if (context.getConfiguration().getDebug()) { + final SourceSection sourceSection = proxy.getChild().getSourceSection(); + final SourceLineLocation sourceLine = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine()); + proxy.getProbeChain().appendProbe(new InactiveLineDebugProbe(context, sourceLine, context.getRubyDebugManager().getAssumption(sourceLine))); + } + + return proxy; } public RubyNode instrumentAsCall(RubyNode node, String callName) { @@ -44,7 +62,27 @@ } public RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName) { - return node; + assert node != null; + + final RubyContext context = node.getContext(); + + RubyProxyNode proxy; + + if (node instanceof RubyProxyNode) { + proxy = (RubyProxyNode) node; + } else { + proxy = new RubyProxyNode(node.getContext(), node); + proxy.markAs(NodePhylum.STATEMENT); + proxy.clearSourceSection(); + proxy.assignSourceSection(node.getSourceSection()); + } + + if (context.getConfiguration().getDebug()) { + final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName); + proxy.getProbeChain().appendProbe(new InactiveLocalDebugProbe(context, methodLocal, context.getRubyDebugManager().getAssumption(methodLocal))); + } + + return proxy; } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java Mon Feb 17 13:48:41 2014 +0100 @@ -1102,7 +1102,6 @@ @Override public Object visitLocalAsgnNode(org.jrubyparser.ast.LocalAsgnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); if (environment.getNeverAssignInParentScope()) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java Mon Feb 17 13:48:41 2014 +0100 @@ -22,6 +22,7 @@ import com.oracle.truffle.ruby.runtime.configuration.*; import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; +import com.oracle.truffle.ruby.runtime.debug.*; import com.oracle.truffle.ruby.runtime.methods.*; import com.oracle.truffle.ruby.runtime.objects.*; import com.oracle.truffle.ruby.runtime.subsystems.*; @@ -41,6 +42,7 @@ private final FiberManager fiberManager; private final AtExitManager atExitManager; private final DebugManager debugManager; + private final RubyDebugManager rubyDebugManager; private final SourceManager sourceManager; private final ASTPrinter astPrinter; @@ -77,6 +79,7 @@ sourceManager = new SourceManager(); debugManager = new DefaultDebugManager(this); + rubyDebugManager = new RubyDebugManager(); // Must initialize threads before fibers @@ -300,4 +303,8 @@ return sourceManager; } + public RubyDebugManager getRubyDebugManager() { + return rubyDebugManager; + } + } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/MethodLocal.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/MethodLocal.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.runtime.debug; + +import com.oracle.truffle.ruby.runtime.methods.*; + +/* + * Identifies a local in a method. + */ +public class MethodLocal { + + private final UniqueMethodIdentifier method; + private final String local; + + public MethodLocal(UniqueMethodIdentifier method, String local) { + this.method = method; + this.local = local; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((local == null) ? 0 : local.hashCode()); + result = prime * result + ((method == null) ? 0 : method.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MethodLocal other = (MethodLocal) obj; + if (local == null) { + if (other.local != null) { + return false; + } + } else if (!local.equals(other.local)) { + return false; + } + if (method == null) { + if (other.method != null) { + return false; + } + } else if (!method.equals(other.method)) { + return false; + } + return true; + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyDebugManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyDebugManager.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.runtime.debug; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.source.*; +import com.oracle.truffle.api.utilities.*; +import com.oracle.truffle.ruby.runtime.core.*; + +public final class RubyDebugManager { + + private final Map lineAssumptions = new HashMap<>(); + private final Map lineBreakpoints = new HashMap<>(); + + private final Map localAssumptions = new HashMap<>(); + private final Map localBreakpoints = new HashMap<>(); + + public void setBreakpoint(SourceLineLocation sourceLine, RubyProc proc) { + final CyclicAssumption assumption = lineAssumptions.get(sourceLine); + + if (assumption == null) { + throw new RuntimeException("Breakpoint " + sourceLine + " not found"); + } else { + lineBreakpoints.put(sourceLine, proc); + assumption.invalidate(); + } + } + + public void setBreakpoint(MethodLocal methodLocal, RubyProc proc) { + final CyclicAssumption assumption = localAssumptions.get(methodLocal); + + if (assumption == null) { + throw new RuntimeException("Breakpoint " + methodLocal + " not found"); + } else { + localBreakpoints.put(methodLocal, proc); + assumption.invalidate(); + } + } + + public void removeBreakpoint(SourceLineLocation sourceLine) { + final CyclicAssumption assumption = lineAssumptions.get(sourceLine); + + if (assumption == null) { + throw new RuntimeException("Breakpoint " + sourceLine + " not found"); + } else { + lineBreakpoints.remove(sourceLine); + assumption.invalidate(); + } + } + + public void removeBreakpoint(MethodLocal methodLocal) { + final CyclicAssumption assumption = localAssumptions.get(methodLocal); + + if (assumption == null) { + throw new RuntimeException("Breakpoint " + methodLocal + " not found"); + } else { + localBreakpoints.remove(methodLocal); + assumption.invalidate(); + } + } + + public Assumption getAssumption(SourceLineLocation sourceLine) { + CyclicAssumption assumption = lineAssumptions.get(sourceLine); + + if (assumption == null) { + assumption = new CyclicAssumption(sourceLine.toString()); + lineAssumptions.put(sourceLine, assumption); + } + + return assumption.getAssumption(); + } + + public RubyProc getBreakpoint(SourceLineLocation sourceLine) { + return lineBreakpoints.get(sourceLine); + } + + public Assumption getAssumption(MethodLocal methodLocal) { + CyclicAssumption assumption = localAssumptions.get(methodLocal); + + if (assumption == null) { + assumption = new CyclicAssumption(methodLocal.toString()); + localAssumptions.put(methodLocal, assumption); + } + + return assumption.getAssumption(); + } + + public RubyProc getBreakpoint(MethodLocal methodLocal) { + return localBreakpoints.get(methodLocal); + } + +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProbe.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.nodes.instrument.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A "probe node" implemented specifically for the Ruby implementation; subclasses need only - * override those members of {@link InstrumentationProbeEvents} for which some action is needed. - */ -public abstract class RubyProbe extends InstrumentationProbeNode.DefaultProbeNode { - - protected final boolean oneShot; - - protected final RubyContext context; - - /** - * OneShot is this a one-shot (self-removing) probe? - */ - public RubyProbe(RubyContext context, boolean oneShot) { - super(context); - this.oneShot = oneShot; - this.context = context; - } - - /** - * Is this a one-shot (self-removing) probe? If so, it will remove itself the first time - * activated. - */ - public boolean isOneShot() { - return oneShot; - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyTraceProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyTraceProbe.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.subsystems.*; - -/** - * A "trace" probe that has no runtime cost until activated, at which time it invokes a trace - * message. - */ -public final class RubyTraceProbe extends RubyProbe { - - private final Assumption notTracingAssumption; - - @CompilerDirectives.CompilationFinal private boolean tracingEverEnabled = false; - - public RubyTraceProbe(RubyContext context) { - super(context, false); - this.notTracingAssumption = context.getTraceManager().getNotTracingAssumption(); - } - - @Override - public void enter(Node astNode, VirtualFrame frame) { - if (!tracingEverEnabled) { - try { - notTracingAssumption.check(); - } catch (InvalidAssumptionException e) { - tracingEverEnabled = true; - } - } - final TraceManager traceManager = context.getTraceManager(); - if (tracingEverEnabled && traceManager.hasTraceProc()) { - final SourceSection sourceSection = astNode.getEncapsulatingSourceSection(); - traceManager.trace("line", sourceSection.getSource().getName(), sourceSection.getStartLine(), 0, null, null); - } - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java Mon Feb 17 13:48:41 2014 +0100 @@ -22,6 +22,7 @@ */ package com.oracle.truffle.sl.test; +import org.junit.*; import org.junit.runner.*; @RunWith(SLTestRunner.class) @@ -32,4 +33,11 @@ SLTestRunner.runInMain(SLSimpleTestSuite.class, args); } + /* + * Our "mx unittest" command looks for methods that are annotated with @Test. By just defining + * an empty method, this class gets included and the test suite is properly executed. + */ + @Test + public void unittest() { + } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Mon Feb 17 13:48:41 2014 +0100 @@ -89,11 +89,6 @@ return testCases; } - @Override - public void filter(Filter filter) throws NoTestsRemainException { - super.filter(filter); - } - protected List createTests(final Class c) throws IOException, InitializationError { SLTestSuite suite = c.getAnnotation(SLTestSuite.class); if (suite == null) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output --- a/graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output Mon Feb 17 13:48:41 2014 +0100 @@ -1,1 +1,1 @@ -Type error at TypeError05.sl line 3 col 3: operation "call" not defined for Boolean true +Type error at TypeError05.sl line 3 col 3: operation "invoke" not defined for Boolean true diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Mon Feb 17 13:48:41 2014 +0100 @@ -80,7 +80,7 @@ *

  • Basic control flow statements: {@link SLBlockNode blocks}, {@link SLIfNode if}, * {@link SLWhileNode while} with {@link SLBreakNode break} and {@link SLContinueNode continue}, * {@link SLReturnNode return}. - *
  • Function calls: {@link SLCallNode calls} are efficiently implemented with + *
  • Function calls: {@link SLInvokeNode invocations} are efficiently implemented with * {@link SLAbstractDispatchNode polymorphic inline caches}. * * diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java Mon Feb 17 13:48:41 2014 +0100 @@ -38,14 +38,14 @@ @Specialization public String defineFunction(String code) { - return doDefineFunction(getContext(), code); + doDefineFunction(getContext(), code); + return code; } @SlowPath - private static String doDefineFunction(SLContext context, String code) { + private static void doDefineFunction(SLContext context, String code) { Source source = context.getSourceManager().get("[defineFunction]", code); /* The same parsing code as for parsing the initial source. */ Parser.parseSL(context, source); - return code; } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java Mon Feb 17 13:48:41 2014 +0100 @@ -60,11 +60,11 @@ } /** - * Informs the Truffle DSL that a primitive {@code long} value can used in all specializations - * where a {@link BigInteger} is expected. This models the semantic of SL: It only has an - * arbitrary precision Number type (implemented as {@link BigInteger}, and {@code long} is only - * used as a performance optimization to avoid the costly {@link BigInteger} arithmetic for - * values that fit into a 64-bit primitive value. + * Informs the Truffle DSL that a primitive {@code long} value can be used in all + * specializations where a {@link BigInteger} is expected. This models the semantic of SL: It + * only has an arbitrary precision Number type (implemented as {@link BigInteger}, and + * {@code long} is only used as a performance optimization to avoid the costly + * {@link BigInteger} arithmetic for values that fit into a 64-bit primitive value. */ @ImplicitCast public BigInteger castBigInteger(long value) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -35,14 +35,14 @@ * a single {@link SLGenericDispatchNode}. All this rewriting happens on runtime, based on profiling * feedback of the actual execution. *

    - * Example of the chain of nodes ({@code C}: {@link SLCallNode}; {@code U}: + * Example of the chain of nodes ({@code I}: {@link SLInvokeNode}; {@code U}: * {@link SLUninitializedDispatchNode}; {@code D}: {@link SLDirectDispatchNode}; {@code G}: * {@link SLGenericDispatchNode}): *

      - *
    1. After parsing: {@code C->U} - *
    2. After execution of function {@code f1}: {@code C->D(f1)->U} - *
    3. After execution of function {@code f2}: {@code C->D(f1)->D(f2)->U} - *
    4. After execution of function {@code f3}: {@code C->G} + *
    5. After parsing: {@code I->U} + *
    6. After execution of function {@code f1}: {@code I->D(f1)->U} + *
    7. After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U} + *
    8. After execution of function {@code f3}: {@code I->G} *
    * */ public abstract class SLAbstractDispatchNode extends Node { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLCallNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLCallNode.java Thu Feb 06 17:41:51 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2013, 2014, 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.truffle.sl.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -/** - * The node for a function call in SL. Since SL has first class functions, the {@link SLFunction - * target function} can be computed by an {@link #functionNode arbitrary expression}. This node is - * responsible for evaluating this expression, as well as evaluating the {@link #argumentNodes - * arguments}. The actual call dispatch is then delegated to a chain of - * {@link SLAbstractDispatchNode}s that form a polymorphic inline cache. - */ -@NodeInfo(shortName = "call") -public final class SLCallNode extends SLExpressionNode { - - public static SLCallNode create(SLExpressionNode function, SLExpressionNode[] arguments) { - return new SLCallNode(function, arguments, new SLUninitializedDispatchNode()); - } - - @Child protected SLExpressionNode functionNode; - @Children protected final SLExpressionNode[] argumentNodes; - @Child protected SLAbstractDispatchNode dispatchNode; - - private SLCallNode(SLExpressionNode functionNode, SLExpressionNode[] argumentNodes, SLAbstractDispatchNode dispatchNode) { - this.functionNode = adoptChild(functionNode); - this.argumentNodes = adoptChildren(argumentNodes); - this.dispatchNode = adoptChild(dispatchNode); - } - - @Override - @ExplodeLoop - public Object executeGeneric(VirtualFrame frame) { - SLFunction function = evaluateFunction(frame); - - /* - * The number of arguments is constant for one call node. During compilation, the loop is - * unrolled and the execute methods of all arguments are inlined. This is triggered by the - * ExplodeLoop annotation on the method. The compiler assertion below illustrates that the - * array length is really constant. - */ - CompilerAsserts.compilationConstant(argumentNodes.length); - - Object[] argumentValues = new Object[argumentNodes.length]; - for (int i = 0; i < argumentNodes.length; i++) { - argumentValues[i] = argumentNodes[i].executeGeneric(frame); - } - SLArguments arguments = new SLArguments(argumentValues); - - return dispatchNode.executeDispatch(frame, function, arguments); - } - - private SLFunction evaluateFunction(VirtualFrame frame) { - try { - /* - * The function node must evaluate to a SLFunction value, so we call - * function-specialized method. - */ - return functionNode.executeFunction(frame); - } catch (UnexpectedResultException ex) { - /* - * The function node evaluated to a non-function result. This is a type error in the SL - * program. We report it with the same exception that Truffle DSL generated nodes use to - * report type errors. - */ - throw new UnsupportedSpecializationException(this, new Node[]{functionNode}, ex.getResult()); - } - } -} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013, 2014, 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.truffle.sl.nodes.call; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * The node for function invocation in SL. Since SL has first class functions, the + * {@link SLFunction target function} can be computed by an {@link #functionNode arbitrary + * expression}. This node is responsible for evaluating this expression, as well as evaluating the + * {@link #argumentNodes arguments}. The actual dispatch is then delegated to a chain of + * {@link SLAbstractDispatchNode}s that form a polymorphic inline cache. + */ +@NodeInfo(shortName = "invoke") +public final class SLInvokeNode extends SLExpressionNode { + + public static SLInvokeNode create(SLExpressionNode function, SLExpressionNode[] arguments) { + return new SLInvokeNode(function, arguments, new SLUninitializedDispatchNode()); + } + + @Child protected SLExpressionNode functionNode; + @Children protected final SLExpressionNode[] argumentNodes; + @Child protected SLAbstractDispatchNode dispatchNode; + + private SLInvokeNode(SLExpressionNode functionNode, SLExpressionNode[] argumentNodes, SLAbstractDispatchNode dispatchNode) { + this.functionNode = adoptChild(functionNode); + this.argumentNodes = adoptChildren(argumentNodes); + this.dispatchNode = adoptChild(dispatchNode); + } + + @Override + @ExplodeLoop + public Object executeGeneric(VirtualFrame frame) { + SLFunction function = evaluateFunction(frame); + + /* + * The number of arguments is constant for one invoke node. During compilation, the loop is + * unrolled and the execute methods of all arguments are inlined. This is triggered by the + * ExplodeLoop annotation on the method. The compiler assertion below illustrates that the + * array length is really constant. + */ + CompilerAsserts.compilationConstant(argumentNodes.length); + + Object[] argumentValues = new Object[argumentNodes.length]; + for (int i = 0; i < argumentNodes.length; i++) { + argumentValues[i] = argumentNodes[i].executeGeneric(frame); + } + SLArguments arguments = new SLArguments(argumentValues); + + return dispatchNode.executeDispatch(frame, function, arguments); + } + + private SLFunction evaluateFunction(VirtualFrame frame) { + try { + /* + * The function node must evaluate to a SLFunction value, so we call + * function-specialized method. + */ + return functionNode.executeFunction(frame); + } catch (UnexpectedResultException ex) { + /* + * The function node evaluated to a non-function result. This is a type error in the SL + * program. We report it with the same exception that Truffle DSL generated nodes use to + * report type errors. + */ + throw new UnsupportedSpecializationException(this, new Node[]{functionNode}, ex.getResult()); + } + } +} diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -54,9 +54,9 @@ cur = cur.getParent(); depth++; } - SLCallNode callNode = (SLCallNode) cur.getParent(); + SLInvokeNode invokeNode = (SLInvokeNode) cur.getParent(); - SLAbstractDispatchNode specialized; + SLAbstractDispatchNode replacement; if (function.getCallTarget() == null) { /* Corner case: the function is not defined, so report an error to the user. */ throw new SLException("Call of undefined function: " + function.getName()); @@ -64,21 +64,21 @@ } else if (depth < INLINE_CACHE_SIZE) { /* Extend the inline cache. Allocate the new cache entry, and the new end of the cache. */ SLAbstractDispatchNode next = new SLUninitializedDispatchNode(); - SLAbstractDispatchNode direct = new SLDirectDispatchNode(next, function); + replacement = new SLDirectDispatchNode(next, function); /* Replace ourself with the new cache entry. */ - specialized = replace(direct); + replace(replacement); } else { /* Cache size exceeded, fall back to a single generic dispatch node. */ - SLAbstractDispatchNode generic = new SLGenericDispatchNode(); + replacement = new SLGenericDispatchNode(); /* Replace the whole chain, not just ourself, with the new generic node. */ - specialized = callNode.dispatchNode.replace(generic); + invokeNode.dispatchNode.replace(replacement); } /* * Execute the newly created node perform the actual dispatch. That saves us from * duplicating the actual call logic here. */ - return specialized.executeDispatch(frame, function, arguments); + return replacement.executeDispatch(frame, function, arguments); } } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -70,7 +70,9 @@ * operand are {@link BigInteger} values. Because the type system defines an * {@link ImplicitCast implicit conversion} from {@code long} to {@link BigInteger} in * {@link SLTypes#castBigInteger(long)}, this specialization is also taken if the left or the - * right operand is a {@code long} value. + * right operand is a {@code long} value. Because the {@link #add(long, long) long} + * specialization} has the {@code rewriteOn} attribute, this specialization is also taken if + * both input values are {@code long} values but the primitive addition overflows. */ @Specialization protected BigInteger add(BigInteger left, BigInteger right) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -42,17 +42,17 @@ */ protected abstract FrameSlot getSlot(); - @Specialization(rewriteOn = {FrameSlotTypeException.class}) + @Specialization(rewriteOn = FrameSlotTypeException.class) protected long readLong(VirtualFrame frame) throws FrameSlotTypeException { return frame.getLong(getSlot()); } - @Specialization(rewriteOn = {FrameSlotTypeException.class}) + @Specialization(rewriteOn = FrameSlotTypeException.class) protected boolean readBoolean(VirtualFrame frame) throws FrameSlotTypeException { return frame.getBoolean(getSlot()); } - @Specialization(order = 1, rewriteOn = {FrameSlotTypeException.class}) + @Specialization(order = 1, rewriteOn = FrameSlotTypeException.class) protected Object readObject(VirtualFrame frame) throws FrameSlotTypeException { return frame.getObject(getSlot()); } diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java Mon Feb 17 13:48:41 2014 +0100 @@ -31,7 +31,7 @@ * Node to write a local variable to a function's {@link VirtualFrame frame}. The Truffle frame API * allows to store primitive values of all Java primitive types, and Object values. */ -@NodeChild(value = "valueNode") +@NodeChild("valueNode") @NodeField(name = "slot", type = FrameSlot.class) public abstract class SLWriteLocalVariableNode extends SLExpressionNode { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Mon Feb 17 13:48:41 2014 +0100 @@ -197,7 +197,7 @@ public SLExpressionNode createCall(Token nameToken, List parameterNodes) { SLExpressionNode functionNode = createRead(nameToken); - return assignSource(nameToken, SLCallNode.create(functionNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()]))); + return assignSource(nameToken, SLInvokeNode.create(functionNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()]))); } public SLExpressionNode createAssignment(Token nameToken, SLExpressionNode valueNode) { diff -r 8df361535530 -r d68f5d0c97f0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java Thu Feb 06 17:41:51 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java Mon Feb 17 13:48:41 2014 +0100 @@ -36,7 +36,7 @@ private final Object[] argumentValues; /** - * Used by the caller, i.e., the {@link SLCallNode node that performs a function call}. + * Used by the caller, i.e., the {@link SLInvokeNode node that performs a function call}. */ public SLArguments(Object[] arguments) { this.argumentValues = arguments; diff -r 8df361535530 -r d68f5d0c97f0 mx/mx_graal.py --- a/mx/mx_graal.py Thu Feb 06 17:41:51 2014 +0100 +++ b/mx/mx_graal.py Mon Feb 17 13:48:41 2014 +0100 @@ -81,6 +81,8 @@ _minVersion = mx.VersionSpec('1.7.0_04') +JDK_UNIX_PERMISSIONS = 0755 + def _get_vm(): """ Gets the configured VM, presenting a dialogue if there is no currently configured VM. @@ -324,7 +326,7 @@ assert defaultVM is not None, 'Could not find default VM in ' + jvmCfg if mx.get_os() != 'windows': - chmodRecursive(jdk, 0755) + chmodRecursive(jdk, JDK_UNIX_PERMISSIONS) shutil.move(join(_vmLibDirInJdk(jdk), defaultVM), join(_vmLibDirInJdk(jdk), 'original')) @@ -402,7 +404,9 @@ fd, tmp = tempfile.mkstemp(suffix='', prefix='graal.jar', dir=jreLibDir) shutil.copyfile(graalJar, tmp) os.close(fd) - shutil.move(tmp, join(jreLibDir, 'graal.jar')) + graalJar = join(jreLibDir, 'graal.jar') + shutil.move(tmp, graalJar) + os.chmod(graalJar, JDK_UNIX_PERMISSIONS) # run a command in the windows SDK Debug Shell def _runInDebugShell(cmd, workingDir, logFile=None, findInOutput=None, respondTo=None): @@ -568,7 +572,7 @@ vmDir = join(_vmLibDirInJdk(jdk), vm) if not exists(vmDir): if mx.get_os() != 'windows': - chmodRecursive(jdk, 0755) + chmodRecursive(jdk, JDK_UNIX_PERMISSIONS) mx.log('Creating VM directory in JDK7: ' + vmDir) os.makedirs(vmDir) @@ -685,7 +689,7 @@ if not found: mx.log('Appending "' + prefix + 'KNOWN" to ' + jvmCfg) if mx.get_os() != 'windows': - os.chmod(jvmCfg, 0755) + os.chmod(jvmCfg, JDK_UNIX_PERMISSIONS) with open(jvmCfg, 'w') as f: for line in lines: if line.startswith(prefix): @@ -708,7 +712,7 @@ """run the fastdebug build of VM selected by the '--vm' option""" return vm(args, vmbuild='fastdebug') -def vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, vmbuild=None): +def _parseVmArgs(args, vm=None, cwd=None, vmbuild=None): """run the VM selected by the '--vm' option""" if vm is None: @@ -725,10 +729,6 @@ mx.expand_project_in_args(args) if _make_eclipse_launch: mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True)) - if len([a for a in args if 'PrintAssembly' in a]) != 0: - hsdis([], copyToDir=_vmLibDirInJdk(jdk)) - if mx.java().debug_port is not None: - args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args if _jacoco == 'on' or _jacoco == 'append': jacocoagent = mx.library("JACOCOAGENT", True) # Exclude all compiler tests and snippets @@ -746,9 +746,6 @@ 'destfile' : 'jacoco.exec' } args = ['-javaagent:' + jacocoagent.get_path(True) + '=' + ','.join([k + '=' + v for k, v in agentOptions.items()])] + args - if '-d64' not in args: - args = ['-d64'] + args - exe = join(jdk, 'bin', mx.exe_suffix('java')) pfx = _vm_prefix.split() if _vm_prefix is not None else [] @@ -757,7 +754,12 @@ if len(ignoredArgs) > 0: mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs)) - return mx.run(pfx + [exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) + args = mx.java().processArgs(args) + return (pfx, exe, vm, args, cwd) + +def vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, vmbuild=None): + (pfx_, exe_, vm_, args_, cwd) = _parseVmArgs(args, vm, cwd, vmbuild) + return mx.run(pfx_ + [exe_, '-' + vm_] + args_, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) def _find_classes_with_annotations(p, pkgRoot, annotations, includeInnerClasses=False): """ @@ -1067,21 +1069,23 @@ mx.pylint([]) tasks.append(t.stop()) - t = Task('Clean') - cleanArgs = [] - if not args.cleanNative: - cleanArgs.append('--no-native') - if not args.cleanJava: - cleanArgs.append('--no-java') - clean(cleanArgs) - tasks.append(t.stop()) + def _clean(name='Clean'): + t = Task(name) + cleanArgs = [] + if not args.cleanNative: + cleanArgs.append('--no-native') + if not args.cleanJava: + cleanArgs.append('--no-java') + clean(cleanArgs) + tasks.append(t.stop()) + _clean() t = Task('IDEConfigCheck') mx.ideclean([]) mx.ideinit([]) tasks.append(t.stop()) - eclipse_exe = os.environ.get('ECLIPSE_EXE') + eclipse_exe = mx.get_env('ECLIPSE_EXE') if eclipse_exe is not None: t = Task('CodeFormatCheck') if mx.eclipseformat(['-e', eclipse_exe]) != 0: @@ -1094,8 +1098,15 @@ t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.') tasks.append(t.stop()) - t = Task('BuildJava') - build(['--no-native', '--jdt-warning-as-error']) + if mx.get_env('JDT'): + t = Task('BuildJavaWithEcj') + build(['--no-native', '--jdt-warning-as-error']) + tasks.append(t.stop()) + + _clean('CleanAfterEcjBuild') + + t = Task('BuildJavaWithJavac') + build(['--no-native', '--force-javac']) tasks.append(t.stop()) t = Task('Checkstyle') @@ -1251,6 +1262,76 @@ with open(resultFile, 'w') as f: f.write(json.dumps(results)) +def jmh(args): + """run the JMH_BENCHMARKS""" + + # TODO: add option for `mvn clean package' + # TODO: add options to pass through arguments directly to JMH + + vmArgs, benchmarks = _extract_VM_args(args) + jmhPath = mx.get_env('JMH_BENCHMARKS', None) + if not jmhPath or not exists(jmhPath): + mx.abort("$JMH_BENCHMARKS not properly definied") + + def _blackhole(x): + mx.logv(x[:-1]) + mx.log("Building benchmarks...") + mx.run(['mvn', 'package'], cwd = jmhPath, out = _blackhole) + + matchedSuites = set() + numBench = [0] + for micros in os.listdir(jmhPath): + absoluteMicro = os.path.join(jmhPath, micros) + if not os.path.isdir(absoluteMicro): + continue + if not micros.startswith("micros-"): + mx.logv('JMH: ignored ' + absoluteMicro + " because it doesn't start with 'micros-'") + continue + + microJar = os.path.join(absoluteMicro, "target", "microbenchmarks.jar") + if not exists(microJar): + mx.logv('JMH: ignored ' + absoluteMicro + " because it doesn't contain the expected jar file ('" + microJar + "')") + continue + if benchmarks: + def _addBenchmark(x): + if x.startswith("Benchmark:"): + return + match = False + for b in benchmarks: + match = match or (b in x) + + if match: + numBench[0] += 1 + matchedSuites.add(micros) + + mx.run_java(['-jar', microJar, "-l"], cwd = jmhPath, out = _addBenchmark, addDefaultArgs = False) + else: + matchedSuites.add(micros) + + mx.logv("matchedSuites: " + str(matchedSuites)) + plural = 's' if not benchmarks or numBench[0] > 1 else '' + number = str(numBench[0]) if benchmarks else "all" + mx.log("Running " + number + " benchmark" + plural + '...') + + regex = [] + if benchmarks: + regex.append(r".*(" + "|".join(benchmarks) + ").*") + + for suite in matchedSuites: + absoluteMicro = os.path.join(jmhPath, suite) + (pfx, exe, vm, forkedVmArgs, _) = _parseVmArgs(vmArgs) + if pfx: + mx.warn("JMH ignores prefix: \"" + pfx + "\"") + mx.run_java( + ['-jar', os.path.join(absoluteMicro, "target", "microbenchmarks.jar"), + "-f", "1", + "-i", "10", "-wi", "10", + "--jvm", exe, + "--jvmArgs", " ".join(["-" + vm] + forkedVmArgs)] + regex, + addDefaultArgs = False, + cwd = jmhPath) + + def specjvm2008(args): """run one or more SPECjvm2008 benchmarks""" @@ -1535,6 +1616,7 @@ 'hcfdis': [hcfdis, ''], 'igv' : [igv, ''], 'jdkhome': [print_jdkhome, ''], + 'jmh': [jmh, '[VM options] [filters...]'], 'dacapo': [dacapo, '[VM options] benchmarks...|"all" [DaCapo options]'], 'scaladacapo': [scaladacapo, '[VM options] benchmarks...|"all" [Scala DaCapo options]'], 'specjvm2008': [specjvm2008, '[VM options] benchmarks...|"all" [SPECjvm2008 options]'], diff -r 8df361535530 -r d68f5d0c97f0 mx/projects --- a/mx/projects Thu Feb 06 17:41:51 2014 +0100 +++ b/mx/projects Mon Feb 17 13:48:41 2014 +0100 @@ -37,26 +37,26 @@ library@JRUBYPARSER@path=lib/jrubyparser-0.5.0.jar library@JRUBYPARSER@urls=http://repo1.maven.org/maven2/org/jruby/jrubyparser/0.5.0/jrubyparser-0.5.0.jar -library@JLINE@path=lib/jline-2.10.jar -library@JLINE@urls=http://repo1.maven.org/maven2/jline/jline/2.10/jline-2.10.jar +library@JLINE@path=lib/jline-2.11.jar +library@JLINE@urls=http://repo1.maven.org/maven2/jline/jline/2.11/jline-2.11.jar library@JRUBYSTDLIB@path=lib/jruby-stdlib-1.7.4.jar library@JRUBYSTDLIB@urls=http://repo1.maven.org/maven2/org/jruby/jruby-stdlib/1.7.4/jruby-stdlib-1.7.4.jar -library@JNR_POSIX@path=lib/jnr-posix-3.0.0.jar -library@JNR_POSIX@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-posix/3.0.0/jnr-posix-3.0.0.jar +library@JNR_POSIX@path=lib/jnr-posix-3.0.1.jar +library@JNR_POSIX@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-posix/3.0.1/jnr-posix-3.0.1.jar -library@JNR_CONSTANTS@path=lib/jnr-constants-0.8.4.jar -library@JNR_CONSTANTS@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.8.4/jnr-constants-0.8.4.jar +library@JNR_CONSTANTS@path=lib/jnr-constants-0.8.5.jar +library@JNR_CONSTANTS@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.8.5/jnr-constants-0.8.5.jar -library@JNR_FFI@path=lib/jnr-ffi-1.0.4.jar -library@JNR_FFI@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-ffi/1.0.4/jnr-ffi-1.0.4.jar +library@JNR_FFI@path=lib/jnr-ffi-1.0.10.jar +library@JNR_FFI@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-ffi/1.0.10/jnr-ffi-1.0.10.jar -library@JFFI@path=lib/jffi-1.2.1.jar -library@JFFI@urls=http://repo1.maven.org/maven2/com/github/jnr/jffi/1.2.1/jffi-1.2.1.jar +library@JFFI@path=lib/jffi-1.2.7.jar +library@JFFI@urls=http://repo1.maven.org/maven2/com/github/jnr/jffi/1.2.7/jffi-1.2.7.jar -library@JFFI_NATIVE@path=lib/jffi-1.2.1-native.jar -library@JFFI_NATIVE@urls=http://search.maven.org/remotecontent?filepath=com/github/jnr/jffi/1.2.1/jffi-1.2.1-native.jar +library@JFFI_NATIVE@path=lib/jffi-1.2.7-native.jar +library@JFFI_NATIVE@urls=http://search.maven.org/remotecontent?filepath=com/github/jnr/jffi/1.2.7/jffi-1.2.7-native.jar library@JNR_X86ASM@path=lib/jnr-x86asm-1.0.2.jar library@JNR_X86ASM@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar @@ -184,7 +184,7 @@ # graal.hotspot.amd64 project@com.oracle.graal.hotspot.amd64@subDir=graal project@com.oracle.graal.hotspot.amd64@sourceDirs=src -project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.nfi.hotspot.amd64,com.oracle.graal.replacements.amd64 +project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.compiler.amd64,com.oracle.graal.hotspot,com.oracle.graal.replacements.amd64 project@com.oracle.graal.hotspot.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.amd64@annotationProcessors=com.oracle.graal.service.processor project@com.oracle.graal.hotspot.amd64@javaCompliance=1.7 @@ -651,22 +651,6 @@ project@com.oracle.graal.asm.sparc@javaCompliance=1.7 project@com.oracle.graal.asm.sparc@workingSets=Graal,Assembler,SPARC -# graal.nfi.hotspot.amd64 -project@com.oracle.graal.nfi.hotspot.amd64@subDir=graal -project@com.oracle.graal.nfi.hotspot.amd64@sourceDirs=src -project@com.oracle.graal.nfi.hotspot.amd64@dependencies=com.oracle.graal.compiler.amd64,com.oracle.graal.hotspot -project@com.oracle.graal.nfi.hotspot.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.nfi.hotspot.amd64@javaCompliance=1.7 -project@com.oracle.graal.nfi.hotspot.amd64@workingSets=Graal,AMD64 - -# graal.nfi.test -project@com.oracle.graal.nfi.test@subDir=graal -project@com.oracle.graal.nfi.test@sourceDirs=test -project@com.oracle.graal.nfi.test@dependencies=JUNIT,com.oracle.graal.runtime -project@com.oracle.graal.nfi.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.nfi.test@javaCompliance=1.7 -project@com.oracle.graal.nfi.test@workingSets=Graal,Test - # truffle.api project@com.oracle.truffle.api@subDir=graal project@com.oracle.truffle.api@sourceDirs=src diff -r 8df361535530 -r d68f5d0c97f0 mxtool/mx.py --- a/mxtool/mx.py Thu Feb 06 17:41:51 2014 +0100 +++ b/mxtool/mx.py Mon Feb 17 13:48:41 2014 +0100 @@ -38,6 +38,7 @@ import socket import xml.parsers.expat import shutil, re, xml.dom.minidom +import pipes from collections import Callable from threading import Thread from argparse import ArgumentParser, REMAINDER @@ -989,7 +990,7 @@ self.add_argument('-d', action='store_const', const=8000, dest='java_dbg_port', help='alias for "-dbg 8000"') self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='') self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='') - self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@', default='-ea -Xss2m -Xmx1g') + self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@') self.add_argument('--Jp', action='append', dest='java_args_pfx', help='prefix Java VM arguments (e.g. --Jp @-dsa)', metavar='@', default=[]) self.add_argument('--Ja', action='append', dest='java_args_sfx', help='suffix Java VM arguments (e.g. --Ja @-dsa)', metavar='@', default=[]) self.add_argument('--user-home', help='users home directory', metavar='', default=os.path.expanduser('~')) @@ -1052,8 +1053,8 @@ assert _java is not None return _java -def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None): - return run(java().format_cmd(args), nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd) +def run_java(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, addDefaultArgs=True): + return run(java().format_cmd(args, addDefaultArgs), nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd) def _kill_process_group(pid): pgid = os.getpgid(pid) @@ -1131,7 +1132,7 @@ log('Environment variables:') for key in sorted(env.keys()): log(' ' + key + '=' + env[key]) - log(' '.join(args)) + log(' '.join(map(pipes.quote, args))) if timeout is None and _opts.ptimeout != 0: timeout = _opts.ptimeout @@ -1309,7 +1310,7 @@ def delAtAndSplit(s): return shlex.split(s.lstrip('@')) - self.java_args = delAtAndSplit(_opts.java_args) + self.java_args = delAtAndSplit(_opts.java_args) if _opts.java_args else [] self.java_args_pfx = sum(map(delAtAndSplit, _opts.java_args_pfx), []) self.java_args_sfx = sum(map(delAtAndSplit, _opts.java_args_sfx), []) @@ -1332,8 +1333,14 @@ if self.debug_port is not None: self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)] - def format_cmd(self, args): - return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args + def format_cmd(self, args, addDefaultArgs): + if addDefaultArgs: + return [self.java] + self.processArgs(args) + else: + return [self.java] + args + + def processArgs(self, args): + return self.java_args_pfx + self.java_args + self.java_args_sfx + args def bootclasspath(self): if self._bootclasspath is None: @@ -1557,6 +1564,7 @@ parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)') parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects') parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects') + parser.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not') parser.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='') parser.add_argument('--jdt-warning-as-error', action='store_true', help='convert all Eclipse batch compiler warnings to errors') @@ -1566,12 +1574,16 @@ args = parser.parse_args(args) jdtJar = None - if args.jdt is not None: - if args.jdt.endswith('.jar'): - jdtJar = args.jdt - if not exists(jdtJar) and os.path.abspath(jdtJar) == os.path.abspath(defaultEcjPath) and get_env('JDT', None) is None: - # Silently ignore JDT if default location is used but not ecj.jar exists there + if not args.javac and args.jdt is not None: + if not args.jdt.endswith('.jar'): + abort('Path for Eclipse batch compiler does not look like a jar file: ' + args.jdt) + jdtJar = args.jdt + if not exists(jdtJar): + if os.path.abspath(jdtJar) == os.path.abspath(defaultEcjPath) and get_env('JDT', None) is None: + # Silently ignore JDT if default location is used but does not exist jdtJar = None + else: + abort('Eclipse batch compiler jar does not exist: ' + args.jdt) built = set() diff -r 8df361535530 -r d68f5d0c97f0 src/gpu/hsail/vm/hsailKernelArguments.cpp --- a/src/gpu/hsail/vm/hsailKernelArguments.cpp Thu Feb 06 17:41:51 2014 +0100 +++ b/src/gpu/hsail/vm/hsailKernelArguments.cpp Mon Feb 17 13:48:41 2014 +0100 @@ -70,7 +70,7 @@ jvalue jValue; java_lang_boxing_object::get_value(arg, &jValue); if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::double value = %e", jValue.d); + tty->print_cr("[HSAIL] HSAILKernelArguments::do_double, _index=%d, value = %e", _index - 1, jValue.d); } bool pushed = Hsail::_okra_push_double(_kernel, jValue.d); assert(pushed == true, "arg push failed"); @@ -84,7 +84,7 @@ jvalue jValue; java_lang_boxing_object::get_value(arg, &jValue); if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::float value = %f", jValue.f); + tty->print_cr("[HSAIL] HSAILKernelArguments::do_float, _index=%d, value = %f", _index - 1, jValue.f); } bool pushed = Hsail::_okra_push_float(_kernel, jValue.f); assert(pushed == true, "float push failed"); @@ -93,7 +93,7 @@ void HSAILKernelArguments::do_int() { // The last int is the iteration variable in an IntStream, but we don't pass it // since we use the HSAIL workitemid in place of that int value - if (_parameter_index == _parameter_count - 1) { + if (isLastParameter()) { if (TraceGPUInteraction) { tty->print_cr("[HSAIL] HSAILKernelArguments::not pushing trailing int"); } @@ -106,6 +106,9 @@ jvalue jValue; java_lang_boxing_object::get_value(arg, &jValue); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] HSAILKernelArguments::do_int, _index=%d, value = %d", _index - 1, jValue.i); + } bool pushed = Hsail::_okra_push_int(_kernel, jValue.i); assert(pushed == true, "arg push failed"); @@ -118,6 +121,9 @@ jvalue jValue; java_lang_boxing_object::get_value(arg, &jValue); + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] HSAILKernelArguments::do_long, _index=%d, value = %d", _index - 1, jValue.j); + } bool pushed = Hsail::_okra_push_long(_kernel, jValue.j); assert(pushed == true, "arg push failed"); @@ -127,7 +133,7 @@ oop arg = _args->obj_at(_index++); assert(arg->is_array(), "arg type mismatch"); if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_array 0x%08x, is a %s", (address) arg, arg->klass()->external_name()); + tty->print_cr("[HSAIL] HSAILKernelArguments::do_array, _index=%d, 0x%08x, is a %s", _index - 1, (address) arg, arg->klass()->external_name()); } bool pushed = Hsail::_okra_push_object(_kernel, arg); @@ -135,14 +141,14 @@ } void HSAILKernelArguments::do_object() { - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, _parameter_index=%d", _parameter_index); - } + + bool isLastParam = isLastParameter(); // determine this before incrementing _index + oop arg = _args->obj_at(_index++); // check if this is last arg in signature // an object as last parameter requires an object stream source array to be passed - if (_parameter_index == _parameter_count - 1) { + if (isLastParam) { if (TraceGPUInteraction) { tty->print_cr("[HSAIL] HSAILKernelArguments::trailing object ref should be object source array ref"); } @@ -150,7 +156,7 @@ } if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, 0x%08x is a %s", (address) arg, arg->klass()->external_name()); + tty->print_cr("[HSAIL] HSAILKernelArguments::do_object, _index=%d, 0x%08x is a %s", _index - 1, (address) arg, arg->klass()->external_name()); } bool pushed = Hsail::_okra_push_object(_kernel, arg); diff -r 8df361535530 -r d68f5d0c97f0 src/gpu/hsail/vm/hsailKernelArguments.hpp --- a/src/gpu/hsail/vm/hsailKernelArguments.hpp Thu Feb 06 17:41:51 2014 +0100 +++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp Mon Feb 17 13:48:41 2014 +0100 @@ -63,7 +63,8 @@ _parameter_count = ArgumentCount(signature).size(); if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] sig:%s args length=%d", signature->as_C_string(), _length); + char buf[O_BUFLEN]; + tty->print_cr("[HSAIL] sig:%s args length=%d, _parameter_count=%d", signature->as_C_string(buf, O_BUFLEN), _length, _parameter_count); } if (!_is_static) { // First object in args should be 'this' @@ -103,6 +104,11 @@ /* TODO : To be implemented */ guarantee(false, "do_short:NYI"); } + + bool isLastParameter() { + return (_index == (_is_static ? _parameter_count - 1 : _parameter_count)); + } + }; #endif // KERNEL_ARGUMENTS_HPP diff -r 8df361535530 -r d68f5d0c97f0 src/gpu/ptx/vm/gpu_ptx.cpp --- a/src/gpu/ptx/vm/gpu_ptx.cpp Thu Feb 06 17:41:51 2014 +0100 +++ b/src/gpu/ptx/vm/gpu_ptx.cpp Mon Feb 17 13:48:41 2014 +0100 @@ -48,7 +48,7 @@ // Entry to GPU native method implementation that transitions current thread to '_thread_in_vm'. #define GPU_VMENTRY(result_type, name, signature) \ JNIEXPORT result_type JNICALL name signature { \ - if (TraceGPUInteraction) tty->print_cr("[CUDA] Ptx::" #name); \ + if (TraceGPUInteraction) tty->print_cr("[CUDA] " #name); \ GRAAL_VM_ENTRY_MARK; \ // Entry to GPU native method implementation that calls a JNI function @@ -69,9 +69,10 @@ {CC"generateKernel", CC"([B" STRING ")J", FN_PTR(Ptx::generate_kernel)}, {CC"getLaunchKernelAddress", CC"()J", FN_PTR(Ptx::get_execute_kernel_from_vm_address)}, {CC"getAvailableProcessors0", CC"()I", FN_PTR(Ptx::get_total_cores)}, + {CC"destroyContext", CC"()V", FN_PTR(Ptx::destroy_ptx_context)}, }; -void * Ptx::_device_context; +void * Ptx::_device_context = 0; int Ptx::_cu_device = 0; Ptx::cuda_cu_init_func_t Ptx::_cuda_cu_init; @@ -218,8 +219,8 @@ version = (float) major + ((float) minor)/10; if (version < GRAAL_SUPPORTED_COMPUTE_CAPABILITY_VERSION) { - tty->print_cr("[CUDA] Only cuda compute capability 3.0 and later supported. Device %d supports %.1f", - _cu_device, version); + tty->print_cr("[CUDA] Only cuda compute capability %.1f and later supported. Device %d supports %.1f", + (float) GRAAL_SUPPORTED_COMPUTE_CAPABILITY_VERSION, _cu_device, version); return false; } @@ -253,6 +254,18 @@ tty->print_cr("[CUDA] Using %s", device_name); } + // Create CUDA context to compile and execute the kernel + + status = _cuda_cu_ctx_create(&_device_context, GRAAL_CU_CTX_MAP_HOST, _cu_device); + + if (status != GRAAL_CUDA_SUCCESS) { + tty->print_cr("[CUDA] Failed to create CUDA context for device(%d): %d", _cu_device, status); + return false; + } + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Success: Created context for device: %d", _cu_device); + } + gpu::initialized_gpu(device_name); return true; @@ -381,23 +394,20 @@ jit_options[2] = GRAAL_CU_JIT_MAX_REGISTERS; jit_option_values[2] = (void *)(size_t)jit_register_count; - // Create CUDA context to compile and execute the kernel - int status = _cuda_cu_ctx_create(&_device_context, GRAAL_CU_CTX_MAP_HOST, _cu_device); + // Set CUDA context to compile and execute the kernel - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] Failed to create CUDA context for device(%d): %d", _cu_device, status); - return 0L; - } - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Created context for device: %d", _cu_device); + if (_device_context == NULL) { + tty->print_cr("[CUDA] Encountered uninitialized CUDA context for device(%d)", _cu_device); + return 0L; } - status = _cuda_cu_ctx_set_current(_device_context); + int status = _cuda_cu_ctx_set_current(_device_context); if (status != GRAAL_CUDA_SUCCESS) { tty->print_cr("[CUDA] Failed to set current context for device: %d", _cu_device); return 0L; } + if (TraceGPUInteraction) { tty->print_cr("[CUDA] Success: Set current context for device: %d", _cu_device); tty->print_cr("[CUDA] PTX Kernel\n%s", code); @@ -573,17 +583,9 @@ } } - void destroy_context() { - if (Ptx::_device_context != NULL) { - check(Ptx::_cuda_cu_ctx_destroy(Ptx::_device_context), "Destroy context"); - Ptx::_device_context = NULL; - } - } - ~PtxCall() { unpin_objects(); free_return_value(); - destroy_context(); if (_gc_locked) { GC_locker::unlock_critical(_thread); if (TraceGPUInteraction) { @@ -669,6 +671,23 @@ } } +GPU_VMENTRY(void, Ptx::destroy_ptx_context, (void)) + if (_device_context != NULL) { + int status = _cuda_cu_ctx_destroy(_device_context); + if (status != GRAAL_CUDA_SUCCESS) { + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Error(%d) : Failed to destroy context", status); + } + _device_context = NULL; + } else { + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Destroyed context", status); + } + } + } + +GPU_END + GPU_VMENTRY(jlong, Ptx::get_execute_kernel_from_vm_address, (JNIEnv *env, jclass)) return (jlong) Ptx::execute_kernel_from_vm; GPU_END @@ -720,7 +739,7 @@ JRT_END #if defined(LINUX) -static const char cuda_library_name[] = "libcuda.so"; +static const char cuda_library_name[] = "/usr/lib/libcuda.so"; #elif defined(__APPLE__) static char const cuda_library_name[] = "/usr/local/cuda/lib/libcuda.dylib"; #else diff -r 8df361535530 -r d68f5d0c97f0 src/gpu/ptx/vm/gpu_ptx.hpp --- a/src/gpu/ptx/vm/gpu_ptx.hpp Thu Feb 06 17:41:51 2014 +0100 +++ b/src/gpu/ptx/vm/gpu_ptx.hpp Mon Feb 17 13:48:41 2014 +0100 @@ -112,6 +112,8 @@ // static native int getAvailableProcessors0(); JNIEXPORT static jint get_total_cores(JNIEnv *env, jobject); + JNIEXPORT static void destroy_ptx_context(); + // Links the CUDA driver library functions static bool link(); diff -r 8df361535530 -r d68f5d0c97f0 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Feb 06 17:41:51 2014 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon Feb 17 13:48:41 2014 +0100 @@ -197,9 +197,14 @@ HotSpotResolvedJavaMethod::set_ignoredBySecurityStackWalk(hotspot_method, method->is_ignored_by_security_stack_walk()); C2V_END -C2V_VMENTRY(jboolean, isMethodCompilable,(JNIEnv *, jobject, jlong metaspace_method)) +C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jlong metaspace_method)) methodHandle method = asMethod(metaspace_method); - return !method->is_not_compilable() && !CompilerOracle::should_not_inline(method); + return !method->is_not_compilable() && !CompilerOracle::should_not_inline(method) && !method->dont_inline(); +C2V_END + +C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jlong metaspace_method)) + methodHandle method = asMethod(metaspace_method); + return CompilerOracle::should_inline(method) || method->force_inline(); C2V_END C2V_ENTRY(jint, getCompiledCodeSize, (JNIEnv *env, jobject, jlong metaspace_method)) @@ -558,8 +563,8 @@ //------------------------------------------------------------------------------------------------ - set_long("libraryLoadAddress", (jlong) os::dll_load); - set_long("functionLookupAddress", (jlong) os::dll_lookup); + set_long("dllLoad", (jlong) os::dll_load); + set_long("dllLookup", (jlong) os::dll_lookup); #if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux) set_long("rtldDefault", (jlong) RTLD_DEFAULT); #endif @@ -883,7 +888,8 @@ {CC"getStackTraceElement", CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, {CC"initializeMethod", CC"("METASPACE_METHOD HS_RESOLVED_METHOD")V", FN_PTR(initializeMethod)}, {CC"doNotInlineOrCompile", CC"("METASPACE_METHOD")V", FN_PTR(doNotInlineOrCompile)}, - {CC"isMethodCompilable", CC"("METASPACE_METHOD")Z", FN_PTR(isMethodCompilable)}, + {CC"canInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(canInlineMethod)}, + {CC"shouldInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(shouldInlineMethod)}, {CC"getCompiledCodeSize", CC"("METASPACE_METHOD")I", FN_PTR(getCompiledCodeSize)}, {CC"lookupType", CC"("STRING CLASS"Z)"METASPACE_KLASS, FN_PTR(lookupType)}, {CC"lookupConstantInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupConstantInPool)}, diff -r 8df361535530 -r d68f5d0c97f0 src/share/vm/runtime/compilationPolicy.cpp --- a/src/share/vm/runtime/compilationPolicy.cpp Thu Feb 06 17:41:51 2014 +0100 +++ b/src/share/vm/runtime/compilationPolicy.cpp Mon Feb 17 13:48:41 2014 +0100 @@ -172,16 +172,20 @@ { ResourceMark rm; if (klass_name != NULL) { - if (klass_name != NULL && method_name != NULL) { - const char* lambdaPrefix = "lambda$"; - char* methodPrefix = strstr(method_name->as_C_string(), lambdaPrefix); - if (methodPrefix != 0) { - if ((strncmp(lambdaPrefix, methodPrefix, strlen(lambdaPrefix)) == 0)) { - if (TraceGPUInteraction) { - char buf[O_BUFLEN]; - tty->print_cr("Selected lambda method %s for GPU offload", m->name_and_sig_as_C_string(buf, O_BUFLEN)); + const char* javaClass = "java/"; + // Exclude java library classes - for now + if (strncmp(klass_name->as_C_string(), javaClass, strlen(javaClass))) { + if (method_name != NULL) { + const char* lambdaPrefix = "lambda$"; + char* methodPrefix = strstr(method_name->as_C_string(), lambdaPrefix); + if (methodPrefix != 0) { + if ((strncmp(lambdaPrefix, methodPrefix, strlen(lambdaPrefix)) == 0)) { + if (TraceGPUInteraction) { + char buf[O_BUFLEN]; + tty->print_cr("Selected lambda method %s for GPU offload", m->name_and_sig_as_C_string(buf, O_BUFLEN)); + } + return true; } - return true; } } } diff -r 8df361535530 -r d68f5d0c97f0 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Feb 06 17:41:51 2014 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Mon Feb 17 13:48:41 2014 +0100 @@ -813,6 +813,34 @@ static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ + static_field(StubRoutines, _jbyte_arraycopy, address) \ + static_field(StubRoutines, _jshort_arraycopy, address) \ + static_field(StubRoutines, _jint_arraycopy, address) \ + static_field(StubRoutines, _jlong_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _checkcast_arraycopy, address) \ + static_field(StubRoutines, _checkcast_arraycopy_uninit, address) \ + static_field(StubRoutines, _unsafe_arraycopy, address) \ + static_field(StubRoutines, _generic_arraycopy, address) \ \ /*****************/ \ /* SharedRuntime */ \