# HG changeset patch # User Michael Van De Vanter # Date 1394077215 28800 # Node ID a124cc76cde9ad6876ce58d0ccea6f4c65fea151 # Parent d0e82d536325e1264ee9cf7befd329fd45641554# Parent 1b84e499127b0086271898a1298577d15e0b3101 Merge with 1b84e499127b0086271898a1298577d15e0b3101 diff -r d0e82d536325 -r a124cc76cde9 .hgignore --- a/.hgignore Sun Feb 23 17:00:35 2014 -0800 +++ b/.hgignore Wed Mar 05 19:40:15 2014 -0800 @@ -85,5 +85,3 @@ agent/build/* agent/make/filelist agent/make/sa17.tar.gz -graal/com.oracle.truffle.ruby.test/specs/mspec -graal/com.oracle.truffle.ruby.test/specs/rubyspec diff -r d0e82d536325 -r a124cc76cde9 .hgtags --- a/.hgtags Sun Feb 23 17:00:35 2014 -0800 +++ b/.hgtags Wed Mar 05 19:40:15 2014 -0800 @@ -403,3 +403,4 @@ 05fedd51e40da22c9460bf17c7185889e435db3d hs25-b62 fca262db9c4309f99d2f5542ab0780e45c2f1578 jdk8-b120 41f4cad94c581034d4c427d2aaabcc20f26342d0 hs25-b63 +b124e22eb772806c13d942cc110de38da0108147 graal-0.1 diff -r d0e82d536325 -r a124cc76cde9 AUTHORS.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AUTHORS.md Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,25 @@ +# Graal Authors + +The GraalVM is based on the source code of HotSpot. The following authors have contributed to the Graal-specific part of the source base: + +* Tom Deneau (tdeneau) +* Gilles Duboscq (gdub) +* Matthias Grimmer (mgrimmer) +* Peter Hofer +* Christian Haeubl (chaeubl) +* Michael Haupt (mhaupt) +* Christian Humer (chumer) +* Morris Meyer (morris) +* Roland Schatz +* Doug Simon (dnsimon) +* Lukas Stadler (lstadler) +* Roland Schatz (rschatz) +* Alexander Stipsits +* Katrin Strassl +* Christian Thalinger (twisti) +* Vasanth Venkatachalam (vvenkat) +* Christian Wimmer (cwimmer) +* Christian Wirth (cwirth) +* Andreas Woess (aw) +* Thomas Wuerthinger (thomaswue) +* Bharadwaj Yadavalli (bharadwaj) diff -r d0e82d536325 -r a124cc76cde9 CHANGELOG.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CHANGELOG.md Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,25 @@ +# GraalVM Changelog + +## `tip` +### Graal +* New methods for querying memory usage of individual objects and object graphs in Graal API (MetaAccessProvider#getMemorySize, MetaUtil#getMemorySizeRecursive). +* ... + +### 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). + diff -r d0e82d536325 -r a124cc76cde9 GRAAL_AUTHORS --- a/GRAAL_AUTHORS Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -Gilles Duboscq (gdub) -Peter Hofer -Christian Haeubl (chaeubl) -Christian Humer (chumer) -Roland Schatz -Doug Simon (dnsimon) -Lukas Stadler (lstadler) -Alexander Stipsits -Katrin Strassl -Christian Wimmer (cwimmer) -Andreas Woess (aw) -Thomas Wuerthinger (thomaswue) diff -r d0e82d536325 -r a124cc76cde9 README --- a/README Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -README: - This file should be located at the top of the hotspot Mercurial repository. - - See http://openjdk.java.net/ for more information about the OpenJDK. - - See ../README-builds.html for complete details on build machine requirements. - -Simple Build Instructions: - - cd make && gnumake - - The files that will be imported into the jdk build will be in the "build" - directory. - diff -r d0e82d536325 -r a124cc76cde9 README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,82 @@ +## Building Graal + +There is a Python script in mxtool/mx.py that simplifies working with the code +base. It requires Python 2.7. While you can run this script by using an absolute path, +it's more convenient to add graal/mxtool to your PATH environment variable so that the +'mx' helper script can be used. The following instructions in this file assume this +setup. + +Building both the Java and C++ source code comprising the Graal VM +can be done with the following simple command. + +``` +% mx build +``` + +There are a number of VM configurations supported by mx which can +be explicitly specified using the --vm option. However, you'll typically +want one of these VM configurations: + +1. The 'server' configuration is a standard HotSpot VM that includes the + runtime support for Graal but uses the existing compilers for normal + compilation (e.g., when the interpreter threshold is hit for a method). + Compilation with Graal is only done by explicit requests to the + Graal API. This is how Truffle uses Graal. + +2. The 'graal' configuration is a VM where all compilation is performed + by Graal and no other compilers are built into the VM binary. This + VM will bootstrap Graal itself at startup unless the -XX:-BootstrapGraal + VM option is given. + +Unless you use the --vm option with the build command, you will be presented +with a dialogue to choose one of the above VM configurations for the build +as well as have the option to make it your default for subsequent commands +that need a VM specified. + +To build the debug or fastdebug builds: + +``` +% mx --vmbuild debug build +% mx --vmbuild fastdebug build +``` + +## Running Graal + +To run the VM, use 'mx vm' in place of the standard 'java' command: + +``` +% mx vm ... +``` + +To select the fastdebug or debug builds of the VM: + +``` +% mx --vmbuild fastdebug vm ... +% mx --vmbuild debug vm ... +``` + +## Other VM Configurations + +In addition to the VM configurations described above, there are +VM configurations that omit all VM support for Graal: + +``` +% mx --vm server-nograal build +% mx --vm server-nograal vm -version +java version "1.7.0_25" +Java(TM) SE Runtime Environment (build 1.7.0_25-b15) +OpenJDK 64-Bit Server VM (build 25.0-b43-internal, mixed mode) +``` + +``` +% mx --vm client-nograal build +% mx --vm client-nograal vm -version +java version "1.7.0_25" +Java(TM) SE Runtime Environment (build 1.7.0_25-b15) +OpenJDK 64-Bit Client VM (build 25.0-b43-internal, mixed mode) +``` + +These configurations aim to match as closely as possible the +VM(s) included in the OpenJDK binaries one can download. + No newline at end of file + diff -r d0e82d536325 -r a124cc76cde9 README_GRAAL.txt --- a/README_GRAAL.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -Building Graal --------------- -There is a Python script in mxtool/mx.py that simplifies working with the code -base. It requires Python 2.7. While you can run this script by using an absolute path, -it's more convenient to add graal/mxtool to your PATH environment variable so that the -'mx' helper script can be used. The following instructions in this file assume this -setup. - -Building both the Java and C++ source code comprising the Graal VM -can be done with the following simple command. - -% mx build - -There are a number of VM configurations supported by mx which can -be explicitly specified using the --vm option. However, you'll typically -want one of these VM configurations: - -1. The 'server' configuration is a standard HotSpot VM that includes the - runtime support for Graal but uses the existing compilers for normal - compilation (e.g., when the interpreter threshold is hit for a method). - Compilation with Graal is only done by explicit requests to the - Graal API. This is how Truffle uses Graal. - -2. The 'graal' configuration is a VM where all compilation is performed - by Graal and no other compilers are built into the VM binary. This - VM will bootstrap Graal itself at startup unless the -XX:-BootstrapGraal - VM option is given. - -Unless you use the --vm option with the build command, you will be presented -with a dialogue to choose one of the above VM configurations for the build -as well as have the option to make it your default for subsequent commands -that need a VM specified. - -To build the debug or fastdebug builds: - -% mx --vmbuild debug build -% mx --vmbuild fastdebug build - -Running Graal -------------- - -To run the VM, use 'mx vm' in place of the standard 'java' command: - -% mx vm ... - -To select the fastdebug or debug builds of the VM: - -% mx --vmbuild fastdebug vm ... -% mx --vmbuild debug vm ... - -Other VM Configurations ------------------------ - -In addition to the VM configurations described above, there are -VM configurations that omit all VM support for Graal: - -% mx --vm server-nograal build -% mx --vm server-nograal vm -version -java version "1.7.0_25" -Java(TM) SE Runtime Environment (build 1.7.0_25-b15) -OpenJDK 64-Bit Server VM (build 25.0-b43-internal, mixed mode) - -% mx --vm client-nograal build -% mx --vm client-nograal vm -version -java version "1.7.0_25" -Java(TM) SE Runtime Environment (build 1.7.0_25-b15) -OpenJDK 64-Bit Cleint VM (build 25.0-b43-internal, mixed mode) - -These configurations aim to match as closely as possible the -VM(s) included in the OpenJDK binaries one can download. \ No newline at end of file diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Wed Mar 05 19:40:15 2014 -0800 @@ -172,31 +172,6 @@ } /** - * Determine the maximum vector length supported for vector operations on values of a given - * {@link Kind}. - * - * @param kind the kind of the individual vector elements - * @return the maximum supported vector size - */ - public int getMaxVectorLength(Kind kind) { - return 1; - } - - /** - * Get a natively supported vector length for breaking down some vector operation on a constant - * length vector. - * - * @param kind the kind of the individual vector elements - * @param maxLength the maximum length that should be returned - * @param arithmetic the arithmetic operation for which the vector size should be determined, or - * null if no arithmetic needs to be performed on the vector - * @return a supported vector size, but at most {@code maxLength} - */ - public int getSupportedVectorLength(Kind kind, int maxLength, Class arithmetic) { - return 1; - } - - /** * Gets the size in bytes of the specified kind for this target. * * @param kind the kind for which to get the size diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Wed Mar 05 19:40:15 2014 -0800 @@ -119,6 +119,24 @@ } /** + * 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 and alternative backends that can't be done. + */ + public 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; + } + + /** * Gets the value representing the specified local variable. * * @param i the local variable index diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ExternalCompilationResult.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ExternalCompilationResult.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ExternalCompilationResult.java Wed Mar 05 19:40:15 2014 -0800 @@ -60,4 +60,11 @@ public long getEntryPoint() { return entryPoint; } + + /** + * Gets the {@linkplain #getTargetCode() code} in this compilation result as a string. + */ + public String getCodeString() { + return new String(getTargetCode(), 0, getTargetCodeSize()); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionHandle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionHandle.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,49 @@ +/* + * 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.api.code; + +/** + * A handle that can be used to {@linkplain #call(Object[]) call} a native function. + */ +public interface NativeFunctionHandle { + + /** + * 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 function + * @return boxed return value of the function call + */ + Object call(Object... args); + + /** + * Returns the installed code of the call stub for the native function call. + * + * @return the installed code of the native call stub + */ + InstalledCode getCallStub(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionInterface.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,122 @@ +/* + * 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.api.code; + +/** + * 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 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); + + /** + * 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 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 function + * @throws UnsatisfiedLinkError if the function handle could not be resolved + */ + NativeFunctionHandle getFunctionHandle(NativeLibraryHandle library, String name, Class returnType, Class... argumentTypes); + + /** + * 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 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 + */ + NativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class returnType, Class... argumentTypes); + + /** + * 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 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 function + * @throws UnsatisfiedLinkError if the function handle could not be created + */ + NativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraries, String name, Class returnType, Class... argumentTypes); + + /** + * 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 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 function + * @throws UnsatisfiedLinkError if default library searching is not + * {@linkplain #isDefaultLibrarySearchSupported() supported} or if the function + * could not be resolved + */ + NativeFunctionHandle getFunctionHandle(String name, Class returnType, Class... argumentTypes); + + /** + * Creates a {@link NativeFunctionPointer} from a raw value. + * + * @param rawValue raw function pointer + * @return {@code NativeFunctionPointer} for {@code rawValue} + */ + NativeFunctionPointer getNativeFunctionPointerFromRawValue(long rawValue); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionPointer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeFunctionPointer.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,41 @@ +/* + * 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.api.code; + +/** + * An opaque representation of a native function pointer. + *

+ * 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 the name of the function. + * + * @return name of the function + */ + String getName(); + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeLibraryHandle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/NativeLibraryHandle.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,37 @@ +/* + * 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.api.code; + +/** + * 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 { + /** + * Gets a name for this library. This may be the path for the file from which the library was + * loaded. + */ + String getName(); +} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/FieldUniverse.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/FieldUniverse.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,45 @@ +/* + * 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.api.meta.test; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.meta.*; + +/** + * Context for field related api.meta tests. + */ +public class FieldUniverse extends TypeUniverse { + + public final Map fields = new HashMap<>(); + + public FieldUniverse() { + for (Class c : classes) { + for (Field f : c.getDeclaredFields()) { + ResolvedJavaField field = metaAccess.lookupJavaField(f); + fields.put(f, field); + } + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestJavaField.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.meta.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; + +/** + * Tests for {@link JavaField}. + */ +public class TestJavaField extends FieldUniverse { + + @Test + public void getNameTest() { + for (Map.Entry e : fields.entrySet()) { + String expected = e.getKey().getName(); + String actual = e.getValue().getName(); + assertEquals(expected, actual); + } + } + + @Test + public void getTypeTest() { + for (Map.Entry e : fields.entrySet()) { + // Must resolve types first as a resolved types != unresolved types + ResolvedJavaField rf = e.getValue(); + JavaType expected = metaAccess.lookupJavaType(e.getKey().getType()).resolve(rf.getDeclaringClass()); + JavaType actual = rf.getType().resolve(rf.getDeclaringClass()); + assertEquals(expected, actual); + } + } + + @Test + public void getKindTest() { + for (Map.Entry e : fields.entrySet()) { + Kind expected = metaAccess.lookupJavaType(e.getKey().getType()).getKind(); + Kind actual = e.getValue().getKind(); + assertEquals(expected, actual); + } + } + + @Test + public void getDeclaringClassTest() { + for (Map.Entry e : fields.entrySet()) { + Class expected = e.getKey().getDeclaringClass(); + ResolvedJavaType actual = e.getValue().getDeclaringClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java --- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestMetaAccessProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -69,7 +69,7 @@ for (Field reflect : c.getDeclaredFields()) { ResolvedJavaField field = metaAccess.lookupJavaField(reflect); assertNotNull(field); - int expected = reflect.getModifiers() & Modifier.fieldModifiers(); + int expected = reflect.getModifiers(); int actual = field.getModifiers(); assertEquals(String.format("%s: 0x%x != 0x%x", reflect, expected, actual), expected, actual); assertTrue(field.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass()))); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.meta.test; + +import static java.lang.reflect.Modifier.*; +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; + +/** + * Tests for {@link ResolvedJavaField}. + */ +public class TestResolvedJavaField extends FieldUniverse { + + public TestResolvedJavaField() { + } + + @Test + public void getModifiersTest() { + for (Map.Entry e : fields.entrySet()) { + int expected = e.getKey().getModifiers(); + int actual = e.getValue().getModifiers(); + assertEquals(expected, actual); + } + } + + @Test + public void isSyntheticTest() { + for (Map.Entry e : fields.entrySet()) { + boolean expected = e.getKey().isSynthetic(); + boolean actual = e.getValue().isSynthetic(); + assertEquals(expected, actual); + } + } + + @Test + public void getAnnotationTest() { + for (Map.Entry e : fields.entrySet()) { + for (Annotation expected : e.getKey().getAnnotations()) { + if (expected != null) { + Annotation actual = e.getValue().getAnnotation(expected.annotationType()); + assertEquals(expected, actual); + } + } + } + } + + @Test + public void readConstantValueTest() throws NoSuchFieldException { + for (Map.Entry e : fields.entrySet()) { + Field field = e.getKey(); + if (isStatic(field.getModifiers())) { + try { + Object expected = field.get(null); + Object actual = e.getValue().readConstantValue(null).asBoxedValue(); + assertEquals(expected, actual); + } catch (IllegalArgumentException | IllegalAccessException e1) { + } + } else { + try { + Object receiver = field.getDeclaringClass().newInstance(); + Object expected = field.get(receiver); + Object actual = e.getValue().readConstantValue(Constant.forObject(receiver)).asBoxedValue(); + assertEquals(expected, actual); + } catch (InstantiationException | IllegalArgumentException | IllegalAccessException e1) { + } + } + } + + ResolvedJavaField field = metaAccess.lookupJavaField(getClass().getDeclaredField("stringField")); + for (Object receiver : new Object[]{this, null, new String()}) { + Constant value = field.readConstantValue(Constant.forObject(receiver)); + assertNull(value); + } + + ResolvedJavaField constField = metaAccess.lookupJavaField(getClass().getDeclaredField("constantStringField")); + for (Object receiver : new Object[]{this, null, new String()}) { + Constant value = constField.readConstantValue(Constant.forObject(receiver)); + if (value != null) { + Object expected = "constantField"; + assertTrue(value.asObject() == expected); + } + } + } + + @Test + public void readValueTest() throws IllegalArgumentException, IllegalAccessException { + for (Map.Entry e : fields.entrySet()) { + Field field = e.getKey(); + field.setAccessible(true); + if (isStatic(field.getModifiers())) { + try { + Object expected = field.get(null); + Object actual = e.getValue().readValue(null).asBoxedValue(); + assertEquals(expected, actual); + } catch (IllegalArgumentException | IllegalAccessException e1) { + } + } + } + + String testString = "a test string"; + testString.hashCode(); // create hash + for (Field f : String.class.getDeclaredFields()) { + f.setAccessible(true); + ResolvedJavaField rf = metaAccess.lookupJavaField(f); + Object receiver = isStatic(f.getModifiers()) ? null : testString; + Object expected = f.get(receiver); + Object actual = rf.readValue(receiver == null ? null : Constant.forObject(receiver)).asBoxedValue(); + assertEquals(expected, actual); + } + } + + String stringField = "field"; + final String constantStringField = "constantField"; + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "getDeclaringClass", + "isInternal" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaField.class.getDeclaredMethods()) { + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java Wed Mar 05 19:40:15 2014 -0800 @@ -290,6 +290,7 @@ "reprofile", "getCompilerStorage", "canBeInlined", + "shouldBeInlined", "getLineNumberTable", "getLocalVariableTable", "isInVirtualMethodTable", diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java --- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Wed Mar 05 19:40:15 2014 -0800 @@ -40,6 +40,7 @@ /** * Tests for {@link ResolvedJavaType}. */ +@SuppressWarnings("unused") public class TestResolvedJavaType extends TypeUniverse { public TestResolvedJavaType() { @@ -503,7 +504,6 @@ public ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) { for (ResolvedJavaField rf : fields) { if (fieldsEqual(key, rf)) { - assert (fieldModifiers() & key.getModifiers()) == rf.getModifiers() : key + ": " + toHexString(key.getModifiers()) + " != " + toHexString(rf.getModifiers()); return rf; } } @@ -513,7 +513,6 @@ public Field lookupField(Set fields, ResolvedJavaField key) { for (Field f : fields) { if (fieldsEqual(f, key)) { - assert key.getModifiers() == (fieldModifiers() & f.getModifiers()) : key + ": " + toHexString(key.getModifiers()) + " != " + toHexString(f.getModifiers()); return f; } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Wed Mar 05 19:40:15 2014 -0800 @@ -424,6 +424,18 @@ } /** + * Creates a {@link Constant} from a primitive integer of a certain width. + */ + public static Constant forPrimitiveInt(int bits, long i) { + assert bits <= 64; + if (bits > 32) { + return new Constant(Kind.Long, null, i); + } else { + return new Constant(Kind.Int, null, (int) i); + } + } + + /** * Creates a boxed constant for the given kind from an Object. The object needs to be of the * Java boxed type corresponding to the kind. * diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java Wed Mar 05 19:40:15 2014 -0800 @@ -95,4 +95,8 @@ public String toString() { return "BaseProfilingInfo<" + MetaUtil.profileToString(this, null, "; ") + ">"; } + + public void setMature() { + // Do nothing + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Wed Mar 05 19:40:15 2014 -0800 @@ -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()); } @@ -129,6 +129,15 @@ } /** + * Checks whether this type is a Java primitive type representing an unsigned number. + * + * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}. + */ + public boolean isUnsigned() { + return this == Kind.Boolean || this == Kind.Char; + } + + /** * Checks whether this type is a Java primitive type representing a floating point number. * * @return {@code true} if this is {@link #Float} or {@link #Double}. @@ -138,6 +147,15 @@ } /** + * Checks whether this represent an Object of some sort. + * + * @return {@code true} if this is {@link #Object} or {@link #NarrowOop}. + */ + public boolean isObject() { + return this == Kind.Object || this == Kind.NarrowOop; + } + + /** * Returns the kind corresponding to the Java type string. * * @param typeString the Java type string @@ -255,19 +273,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 +309,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(); } } @@ -370,6 +401,19 @@ } /** + * Number of bytes that are necessary to represent a value of this kind. + * + * @return the number of bytes + */ + public int getByteCount() { + if (this == Boolean) { + return 1; + } else { + return getBitCount() >> 3; + } + } + + /** * Number of bits that are necessary to represent a value of this kind. * * @return the number of bits diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Wed Mar 05 19:40:15 2014 -0800 @@ -41,4 +41,8 @@ */ LocationIdentity FINAL_LOCATION = new NamedLocationIdentity("FINAL_LOCATION"); + /** + * Denotes the location of the length field of a Java array. + */ + LocationIdentity ARRAY_LENGTH_LOCATION = new NamedLocationIdentity("[].length"); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -60,6 +60,14 @@ ResolvedJavaType lookupJavaType(Constant constant); /** + * Returns the number of bytes occupied by this constant value or constant object. + * + * @param constant the constant whose bytes should be measured + * @return the number of bytes occupied by this constant + */ + long getMemorySize(Constant constant); + + /** * Parses a method * descriptor into a {@link Signature}. The behavior of this method is undefined if the diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,7 @@ import static java.lang.reflect.Modifier.*; +import java.io.*; import java.lang.annotation.*; import java.lang.reflect.*; import java.util.*; @@ -36,6 +37,104 @@ */ public class MetaUtil { + private static class ClassInfo { + public long totalSize; + public long instanceCount; + + @Override + public String toString() { + return "totalSize=" + totalSize + ", instanceCount=" + instanceCount; + } + } + + /** + * Returns the number of bytes occupied by this constant value or constant object and + * recursively all values reachable from this value. + * + * @param constant the constant whose bytes should be measured + * @param printTopN print total size and instance count of the top n classes is desired + * @return the number of bytes occupied by this constant + */ + public static long getMemorySizeRecursive(MetaAccessProvider access, Constant constant, PrintStream out, int printTopN) { + IdentityHashMap marked = new IdentityHashMap<>(); + Stack stack = new Stack<>(); + if (constant.getKind() == Kind.Object && constant.isNonNull()) { + marked.put(constant.asObject(), Boolean.TRUE); + } + final HashMap histogram = new HashMap<>(); + stack.push(constant); + long sum = 0; + while (!stack.isEmpty()) { + Constant c = stack.pop(); + long memorySize = access.getMemorySize(constant); + sum += memorySize; + if (c.getKind() == Kind.Object && c.isNonNull()) { + Class clazz = c.asObject().getClass(); + if (!histogram.containsKey(clazz)) { + histogram.put(clazz, new ClassInfo()); + } + ClassInfo info = histogram.get(clazz); + info.instanceCount++; + info.totalSize += memorySize; + ResolvedJavaType type = access.lookupJavaType(c); + if (type.isArray()) { + if (!type.getComponentType().isPrimitive()) { + Object[] array = (Object[]) c.asObject(); + for (Object value : array) { + Constant forObject = Constant.forObject(value); + pushConstant(marked, stack, forObject); + } + } + } else { + ResolvedJavaField[] instanceFields = type.getInstanceFields(true); + for (ResolvedJavaField f : instanceFields) { + if (f.getKind() == Kind.Object) { + Constant value = f.readValue(c); + pushConstant(marked, stack, value); + } + } + } + } + } + ArrayList clazzes = new ArrayList<>(); + clazzes.addAll(histogram.keySet()); + Collections.sort(clazzes, new Comparator() { + + @Override + public int compare(Class o1, Class o2) { + long l1 = histogram.get(o1).totalSize; + long l2 = histogram.get(o2).totalSize; + if (l1 > l2) { + return -1; + } else if (l1 == l2) { + return 0; + } else { + return 1; + } + } + }); + + int z = 0; + for (Class c : clazzes) { + if (z > printTopN) { + break; + } + out.println("Class " + c + ", " + histogram.get(c)); + ++z; + } + + return sum; + } + + private static void pushConstant(IdentityHashMap marked, Stack stack, Constant value) { + if (value.isNonNull()) { + if (!marked.containsKey(value.asObject())) { + marked.put(value.asObject(), Boolean.TRUE); + stack.push(value); + } + } + } + /** * Returns true if the specified typed is exactly the type {@link java.lang.Object}. */ diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java Wed Mar 05 19:40:15 2014 -0800 @@ -121,4 +121,9 @@ */ boolean isMature(); + /** + * Force data to be treated as mature if possible. + */ + + void setMature(); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java Wed Mar 05 19:40:15 2014 -0800 @@ -64,7 +64,7 @@ /** * Gets the current value of this field for a given object, if available. There is no guarantee * that the same value will be returned by this method for a field unless the field is - * considered to be {@link #readConstantValue(Constant)} by the runtime. + * considered to be {@linkplain #readConstantValue(Constant) constant} by the runtime. * * @param receiver object from which this field's value is to be read. This value is ignored if * this field is static. diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java --- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/ClassSubstitution.java Wed Mar 05 19:40:15 2014 -0800 @@ -61,6 +61,5 @@ * Determines if the substitutions in a class are globally enabled. Individual * MethodSubstitutions can also have guards and those override this guard. */ - Class defaultGuard() default SubstitutionGuard.class; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java --- a/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -30,7 +30,6 @@ import com.oracle.graal.api.code.CompilationResult.ConstantData; import com.oracle.graal.api.code.CompilationResult.RawData; import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.Buffer; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.asm.test.*; @@ -41,12 +40,12 @@ CodeGenTest test = new CodeGenTest() { @Override - public Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { + public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { AMD64Assembler asm = new AMD64Assembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Int); asm.movl(ret, 8472); asm.ret(0); - return asm.codeBuffer; + return asm.close(true); } }; assertReturn("intStub", test, 8472); @@ -57,13 +56,13 @@ CodeGenTest test = new CodeGenTest() { @Override - public Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { + public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { AMD64MacroAssembler asm = new AMD64MacroAssembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Double); - compResult.recordDataReference(asm.codeBuffer.position(), new ConstantData(Constant.forDouble(84.72), 8)); + compResult.recordDataReference(asm.position(), new ConstantData(Constant.forDouble(84.72), 8)); asm.movdbl(ret, asm.getPlaceholder()); asm.ret(0); - return asm.codeBuffer; + return asm.close(true); } }; assertReturn("doubleStub", test, 84.72); @@ -74,16 +73,16 @@ CodeGenTest test = new CodeGenTest() { @Override - public Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { + public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) { AMD64MacroAssembler asm = new AMD64MacroAssembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Double); byte[] rawBytes = new byte[8]; ByteBuffer.wrap(rawBytes).order(ByteOrder.nativeOrder()).putDouble(84.72); - compResult.recordDataReference(asm.codeBuffer.position(), new RawData(rawBytes, 8)); + compResult.recordDataReference(asm.position(), new RawData(rawBytes, 8)); asm.movdbl(ret, asm.getPlaceholder()); asm.ret(0); - return asm.codeBuffer; + return asm.close(true); } }; assertReturn("doubleStub", test, 84.72); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,7 +34,7 @@ /** * This class implements an assembler that can encode most X86 instructions. */ -public class AMD64Assembler extends AbstractAssembler { +public class AMD64Assembler extends Assembler { private static final int MinEncodingNeedsRex = 8; @@ -746,7 +746,7 @@ public void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) { int shortSize = 2; int longSize = 6; - long disp = jumpTarget - codeBuffer.position(); + long disp = jumpTarget - position(); if (!forceDisp32 && isByte(disp - shortSize)) { // 0111 tttn #8-bit disp emitByte(0x70 | cc.getValue()); @@ -769,7 +769,7 @@ // is the same however, seems to be rather unlikely case. // Note: use jccb() if label to be bound is very close to get // an 8-bit displacement - l.addPatchAt(codeBuffer.position()); + l.addPatchAt(position()); emitByte(0x0F); emitByte(0x80 | cc.getValue()); emitInt(0); @@ -781,13 +781,13 @@ if (l.isBound()) { int shortSize = 2; int entry = l.position(); - assert isByte(entry - (codeBuffer.position() + shortSize)) : "Dispacement too large for a short jmp"; - long disp = entry - codeBuffer.position(); + assert isByte(entry - (position() + shortSize)) : "Dispacement too large for a short jmp"; + long disp = entry - position(); // 0111 tttn #8-bit disp emitByte(0x70 | cc.getValue()); emitByte((int) ((disp - shortSize) & 0xFF)); } else { - l.addPatchAt(codeBuffer.position()); + l.addPatchAt(position()); emitByte(0x70 | cc.getValue()); emitByte(0); } @@ -796,7 +796,7 @@ public final void jmp(int jumpTarget, boolean forceDisp32) { int shortSize = 2; int longSize = 5; - long disp = jumpTarget - codeBuffer.position(); + long disp = jumpTarget - position(); if (!forceDisp32 && isByte(disp - shortSize)) { emitByte(0xEB); emitByte((int) ((disp - shortSize) & 0xFF)); @@ -816,7 +816,7 @@ // the forward jump will not run beyond 256 bytes, use jmpb to // force an 8-bit displacement. - l.addPatchAt(codeBuffer.position()); + l.addPatchAt(position()); emitByte(0xE9); emitInt(0); } @@ -832,13 +832,13 @@ if (l.isBound()) { int shortSize = 2; int entry = l.position(); - assert isByte((entry - codeBuffer.position()) + shortSize) : "Dispacement too large for a short jmp"; - long offs = entry - codeBuffer.position(); + assert isByte((entry - position()) + shortSize) : "Dispacement too large for a short jmp"; + long offs = entry - position(); emitByte(0xEB); emitByte((int) ((offs - shortSize) & 0xFF)); } else { - l.addPatchAt(codeBuffer.position()); + l.addPatchAt(position()); emitByte(0xEB); emitByte(0); } @@ -1034,6 +1034,20 @@ emitByte(0xC0 | encode); } + public final void movsbq(Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x0F); + emitByte(0xBE); + emitOperandHelper(dst, src); + } + + public final void movsbq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x0F); + emitByte(0xBE); + emitByte(0xC0 | encode); + } + public final void movsd(Register dst, Register src) { assert dst.getRegisterCategory() == AMD64.XMM; assert src.getRegisterCategory() == AMD64.XMM; @@ -1104,6 +1118,20 @@ emitByte(0xC0 | encode); } + public final void movswq(Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x0F); + emitByte(0xBF); + emitOperandHelper(dst, src); + } + + public final void movswq(Register dst, Register src) { + int encode = prefixqAndEncode(dst.encoding, src.encoding); + emitByte(0x0F); + emitByte(0xBF); + emitByte(0xC0 | encode); + } + public final void movw(AMD64Address dst, int imm16) { emitByte(0x66); // switch to 16-bit mode prefix(dst); @@ -2418,21 +2446,21 @@ @Override protected final void patchJumpTarget(int branch, int branchTarget) { - int op = codeBuffer.getByte(branch); + int op = getByte(branch); assert op == 0xE8 // call || op == 0x00 // jump table entry || op == 0xE9 // jmp || op == 0xEB // short jmp || (op & 0xF0) == 0x70 // short jcc - || op == 0x0F && (codeBuffer.getByte(branch + 1) & 0xF0) == 0x80 // jcc + || op == 0x0F && (getByte(branch + 1) & 0xF0) == 0x80 // jcc : "Invalid opcode at patch point branch=" + branch + ", branchTarget=" + branchTarget + ", op=" + op; if (op == 0x00) { - int offsetToJumpTableBase = codeBuffer.getShort(branch + 1); + int offsetToJumpTableBase = getShort(branch + 1); int jumpTableBase = branch - offsetToJumpTableBase; int imm32 = branchTarget - jumpTableBase; - codeBuffer.emitInt(imm32, branch); + emitInt(imm32, branch); } else if (op == 0xEB || (op & 0xF0) == 0x70) { // short offset operators (jmp and jcc) @@ -2444,7 +2472,7 @@ if (!NumUtil.isByte(imm8)) { throw new InternalError("branch displacement out of range: " + imm8); } - codeBuffer.emitByte(imm8, branch + 1); + emitByte(imm8, branch + 1); } else { @@ -2454,7 +2482,7 @@ } int imm32 = branchTarget - (branch + 4 + off); - codeBuffer.emitInt(imm32, branch + off); + emitInt(imm32, branch + off); } } @@ -2464,8 +2492,8 @@ @Override public void align(int modulus) { - if (codeBuffer.position() % modulus != 0) { - nop(modulus - (codeBuffer.position() % modulus)); + if (position() % modulus != 0) { + nop(modulus - (position() % modulus)); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java --- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/AbstractHSAILAssembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,7 +28,7 @@ /** * The platform-dependent base class for the HSAIL assembler. */ -public abstract class AbstractHSAILAssembler extends AbstractAssembler { +public abstract class AbstractHSAILAssembler extends Assembler { public AbstractHSAILAssembler(TargetDescription target) { super(target); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java --- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -120,7 +120,13 @@ } private void emitAddrOp(String instr, Value reg, HSAILAddress addr) { - emitString(instr + " " + HSAIL.mapRegister(reg) + ", " + mapAddress(addr) + ";"); + String storeValue = null; + if (reg instanceof RegisterValue) { + storeValue = HSAIL.mapRegister(reg); + } else if (reg instanceof Constant) { + storeValue = ((Constant) reg).asBoxedValue().toString(); + } + emitString(instr + " " + storeValue + ", " + mapAddress(addr) + ";"); } /** @@ -160,10 +166,31 @@ emitAddrOp("st_global_" + argTypeStr, dest, addr); } + private void storeImmediateImpl(String storeType, String value, HSAILAddress addr) { + emitString("st_global_" + storeType + " " + value + ", " + mapAddress(addr) + ";"); + } + + public final void emitStoreImmediate(Kind kind, long src, HSAILAddress addr) { + assert (kind != Kind.Float && kind != Kind.Double); + storeImmediateImpl(getArgTypeFromKind(kind), Long.toString(src), addr); + } + + public final void emitStoreImmediate(float src, HSAILAddress addr) { + storeImmediateImpl("f32", Float.toString(src), addr); + } + + public final void emitStoreImmediate(double src, HSAILAddress addr) { + storeImmediateImpl("f64", Double.toString(src), addr); + } + public final void emitSpillLoad(Value dest, Value src) { emitString("ld_spill_" + getArgType(dest) + " " + HSAIL.mapRegister(dest) + ", " + mapStackSlot(src, getArgSize(dest)) + ";"); } + public final void emitStore(Value src, HSAILAddress addr) { + emitString("st_global_" + getArgType(src) + " " + HSAIL.mapRegister(src) + ", " + mapAddress(addr) + ";"); + } + public final void emitSpillStore(Value src, Value dest) { int sizestored = getArgSize(src); if (maxDataTypeSize < sizestored) { @@ -206,7 +233,7 @@ } } - public static final String getArgType(Value src) { + private static String getArgType(Value src) { return getArgTypeFromKind(src.getKind()); } @@ -237,6 +264,9 @@ case Byte: prefix = "s8"; break; + case NarrowOop: + prefix = "u32"; + break; default: throw GraalInternalError.shouldNotReachHere(); } @@ -282,9 +312,7 @@ emitString(prefix + " $c0, " + mapRegOrConstToString(src0) + ", " + mapRegOrConstToString(src1) + ";" + comment); } - public void emitConvert(Value dest, Value src, Kind destKind, Kind srcKind) { - String destType = getArgTypeFromKind(destKind); - String srcType = getArgTypeFromKind(srcKind); + public void emitConvert(Value dest, Value src, String destType, String srcType) { String prefix = (destType.equals("f32") && srcType.equals("f64")) ? "cvt_near_" : "cvt_"; emitString(prefix + destType + "_" + srcType + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapRegister(src) + ";"); } @@ -506,4 +534,8 @@ public void emitComment(String comment) { emitString(comment); } + + public void emitStoreRelease(Value src, HSAILAddress address) { + emitAddrOp("st_global_rel_u" + getArgSize(src), src, address); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/AbstractPTXAssembler.java --- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/AbstractPTXAssembler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/AbstractPTXAssembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,7 +28,7 @@ /** * The platform-dependent base class for the PTX assembler. */ -public abstract class AbstractPTXAssembler extends AbstractAssembler { +public abstract class AbstractPTXAssembler extends Assembler { public AbstractPTXAssembler(TargetDescription target) { super(target); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java --- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -397,13 +397,17 @@ } // Checkstyle: stop method name check - public final void bra(String tgt, int pred) { + /* + * Emit conditional branch to target 'tgt' guarded by predicate register 'pred' whose state is + * tested to be 'predCheck'. + */ + public final void bra(String tgt, int pred, boolean predCheck) { assert pred >= 0; if (tgt.equals("?")) { Thread.dumpStack(); } - emitString("@%p" + pred + " " + "bra" + " " + tgt + ";"); + emitString("@" + (predCheck ? "%p" : "!%p") + pred + " " + "bra" + " " + tgt + ";"); } public final void bra(String src) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,7 +33,7 @@ /** * This class implements an assembler that can encode most SPARC instructions. */ -public abstract class SPARCAssembler extends AbstractAssembler { +public abstract class SPARCAssembler extends Assembler { /** * Constructs an assembler for the SPARC architecture. @@ -89,7 +89,7 @@ } public static Fmt00a read(SPARCAssembler masm, int pos) { - final int inst = masm.codeBuffer.getInt(pos); + final int inst = masm.getInt(pos); // Make sure it's the right instruction: final int op = (inst & OP_MASK) >> OP_SHIFT; @@ -105,7 +105,7 @@ public void write(SPARCAssembler masm, int pos) { verify(); - masm.codeBuffer.emitInt(getInstructionBits(), pos); + masm.emitInt(getInstructionBits(), pos); } public void emit(SPARCAssembler masm) { @@ -253,7 +253,7 @@ } public static Fmt00c read(SPARCAssembler masm, int pos) { - final int inst = masm.codeBuffer.getInt(pos); + final int inst = masm.getInt(pos); // Make sure it's the right instruction: final int op = (inst & OP_MASK) >> OP_SHIFT; @@ -274,13 +274,13 @@ public void write(SPARCAssembler masm, int pos) { verify(); - masm.codeBuffer.emitInt(getInstructionBits(), pos); + masm.emitInt(getInstructionBits(), pos); } public void emit(SPARCAssembler masm) { if (label != null) { final int pos = label.isBound() ? label.position() : patchUnbound(masm, label); - final int disp = pos - masm.codeBuffer.position(); + final int disp = pos - masm.position(); setDisp19(disp); } verify(); @@ -288,7 +288,7 @@ } private static int patchUnbound(SPARCAssembler masm, Label label) { - label.addPatchAt(masm.codeBuffer.position()); + label.addPatchAt(masm.position()); return 0; } @@ -370,7 +370,7 @@ } public static Fmt01 read(SPARCAssembler masm, int pos) { - final int inst = masm.codeBuffer.getInt(pos); + final int inst = masm.getInt(pos); // Make sure it's the right instruction: final int op = (inst & OP_MASK) >> OP_SHIFT; @@ -386,7 +386,7 @@ public void write(SPARCAssembler masm, int pos) { verify(); - masm.codeBuffer.emitInt(getInstructionBits(), pos); + masm.emitInt(getInstructionBits(), pos); } public void emit(SPARCAssembler masm) { @@ -550,7 +550,7 @@ } public static Fmt10 read(SPARCAssembler masm, int pos) { - final int inst = masm.codeBuffer.getInt(pos); + final int inst = masm.getInt(pos); // Make sure it's the right instruction: final int op = (inst & OP_MASK) >> OP_SHIFT; @@ -571,7 +571,7 @@ public void write(SPARCAssembler masm, int pos) { verify(); - masm.codeBuffer.emitInt(getInstructionBits(), pos); + masm.emitInt(getInstructionBits(), pos); } public void emit(SPARCAssembler masm) { @@ -654,7 +654,7 @@ } /** - * Special constructor for Casa and Casxa. + * Special constructor for {@link Casa} and {@link Casxa}. */ public Fmt11(Op3s op3, Register rs1, Register rs2, Register rd, Asi asi) { this(rd.encoding(), op3.getValue(), rs1.encoding(), asi.isValid() ? 0 : 1, asi.isValid() ? asi.getValue() : 0, rs2.encoding(), 0); @@ -666,6 +666,18 @@ */ public Fmt11(Op3s op3, SPARCAddress addr, Register rd) { this(rd.encoding(), op3.getValue(), addr.getBase().encoding(), 0, 0, 0, 0); + decodeAddress(addr); + } + + /** + * Special constructor for {@link Prefetch} and Prefetcha. + */ + public Fmt11(Op3s op3, SPARCAddress addr, Prefetch.Fcn fcn) { + this(fcn.getValue(), op3.getValue(), addr.getBase().encoding(), 0, 0, 0, 0); + decodeAddress(addr); + } + + private void decodeAddress(SPARCAddress addr) { if (!addr.getIndex().equals(Register.None)) { this.rs2 = addr.getIndex().encoding(); } else { @@ -684,7 +696,7 @@ } public static Fmt11 read(SPARCAssembler masm, int pos) { - final int inst = masm.codeBuffer.getInt(pos); + final int inst = masm.getInt(pos); // Make sure it's the right instruction: final int op = (inst & OP_MASK) >> OP_SHIFT; @@ -704,7 +716,7 @@ public void write(SPARCAssembler masm, int pos) { verify(); - masm.codeBuffer.emitInt(getInstructionBits(), pos); + masm.emitInt(getInstructionBits(), pos); } public void emit(SPARCAssembler masm) { @@ -820,7 +832,7 @@ } public static Fmt10c read(SPARCAssembler masm, int pos) { - final int inst = masm.codeBuffer.getInt(pos); + final int inst = masm.getInt(pos); // Make sure it's the right instruction: final int op = (inst & OP_MASK) >> OP_SHIFT; @@ -840,7 +852,7 @@ public void write(SPARCAssembler masm, int pos) { verify(); - masm.codeBuffer.emitInt(getInstructionBits(), pos); + masm.emitInt(getInstructionBits(), pos); } public void emit(SPARCAssembler masm) { @@ -1009,6 +1021,8 @@ Retry(0x3e, "retry"), Casa(0b111100, "casa"), Casxa(0b111110, "casxa"), + Prefetch(0b101101, "prefetch"), + Prefetcha(0b111101, "prefetcha"), Lduw(0b00000, "lduw"), Ldub(0b00001, "ldub"), @@ -2921,6 +2935,27 @@ } } + public static class Prefetch extends Fmt11 { + + public enum Fcn { + SeveralReads(0), OneRead(1), SeveralWritesAndPossiblyReads(2), OneWrite(3), Page(4); + + private final int value; + + private Fcn(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + public Prefetch(SPARCAddress addr, Prefetch.Fcn fcn) { + super(Op3s.Prefetch, addr, fcn); + } + } + // A.44 Read State Register @Deprecated diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -42,8 +42,8 @@ @Override public void align(int modulus) { - if (codeBuffer.position() % modulus != 0) { - final int count = modulus - (codeBuffer.position() % modulus); + if (position() % modulus != 0) { + final int count = modulus - (position() % modulus); for (int i = 0; i < count; i++) { new Nop().emit(this); } @@ -364,7 +364,7 @@ int lo = (int) (value & ~0); // This is the same logic as MacroAssembler::internal_set. - final int startPc = masm.codeBuffer.position(); + final int startPc = masm.position(); if (hi == 0 && lo >= 0) { new Sethi(hi22(lo), dst).emit(masm); @@ -399,7 +399,7 @@ } // Pad out the instruction sequence so it can be patched later. if (forceRelocatable) { - while (masm.codeBuffer.position() < (startPc + (INSTRUCTION_SIZE * 4))) { + while (masm.position() < (startPc + (INSTRUCTION_SIZE * 4))) { new Nop().emit(masm); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java --- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -29,7 +29,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; -import com.oracle.graal.asm.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.runtime.*; import com.oracle.graal.test.*; @@ -40,8 +39,7 @@ protected final CodeCacheProvider codeCache; public interface CodeGenTest { - - Buffer generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc); + byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc); } public AssemblerTest() { @@ -60,8 +58,8 @@ CallingConvention cc = CodeUtil.getCallingConvention(codeCache, CallingConvention.Type.JavaCallee, method, false); CompilationResult compResult = new CompilationResult(); - Buffer codeBuffer = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc); - compResult.setTargetCode(codeBuffer.close(true), codeBuffer.position()); + byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc); + compResult.setTargetCode(targetCode, targetCode.length); InstalledCode code = codeCache.addMethod(method, compResult, null); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.asm; - -import java.nio.*; -import java.util.*; - -import com.oracle.graal.api.code.*; - -/** - * The platform-independent base class for the assembler. - */ -public abstract class AbstractAssembler { - - public final TargetDescription target; - public final Buffer codeBuffer; - - public AbstractAssembler(TargetDescription target) { - this.target = target; - - if (target.arch.getByteOrder() == ByteOrder.BIG_ENDIAN) { - this.codeBuffer = new Buffer.BigEndian(); - } else { - this.codeBuffer = new Buffer.LittleEndian(); - } - } - - public void bind(Label l) { - assert !l.isBound() : "can bind label only once"; - l.bind(codeBuffer.position()); - l.patchInstructions(this); - } - - public abstract void align(int modulus); - - public abstract void jmp(Label l); - - protected abstract void patchJumpTarget(int branch, int jumpTarget); - - private Map nameMap; - - /** - * Creates a name for a label. - * - * @param l the label for which a name is being created - * @param id a label identifier that is unique with the scope of this assembler - * @return a label name in the form of "L123" - */ - protected String createLabelName(Label l, int id) { - return "L" + id; - } - - /** - * Gets a name for a label, creating it if it does not yet exist. By default, the returned name - * is only unique with the scope of this assembler. - */ - public String nameOf(Label l) { - if (nameMap == null) { - nameMap = new HashMap<>(); - } - String name = nameMap.get(l); - if (name == null) { - name = createLabelName(l, nameMap.size()); - nameMap.put(l, name); - } - return name; - } - - protected final void emitByte(int x) { - codeBuffer.emitByte(x); - } - - protected final void emitShort(int x) { - codeBuffer.emitShort(x); - } - - protected final void emitInt(int x) { - codeBuffer.emitInt(x); - } - - protected final void emitLong(long x) { - codeBuffer.emitLong(x); - } - - /** - * Some GPU architectures have a text based encoding. - */ - protected final void emitString(String x) { - codeBuffer.emitString(x); - } - - // XXX for pretty-printing - protected final void emitString0(String x) { - codeBuffer.emitString0(x); - } - - /** - * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an - * {@link AbstractAddress}. - */ - public abstract AbstractAddress makeAddress(Register base, int displacement); - - /** - * Returns a target specific placeholder address that can be used for code patching. - */ - public abstract AbstractAddress getPlaceholder(); -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.asm; + +import java.nio.*; +import java.util.*; + +import com.oracle.graal.api.code.*; + +/** + * The platform-independent base class for the assembler. + */ +public abstract class Assembler { + + public final TargetDescription target; + + /** + * Backing code buffer. + */ + private final Buffer codeBuffer; + + public Assembler(TargetDescription target) { + this.target = target; + if (target.arch.getByteOrder() == ByteOrder.BIG_ENDIAN) { + this.codeBuffer = new Buffer.BigEndian(); + } else { + this.codeBuffer = new Buffer.LittleEndian(); + } + } + + /** + * Returns the current position of the underlying code buffer. + * + * @return current position in code buffer + */ + public int position() { + return codeBuffer.position(); + } + + public final void emitByte(int x) { + codeBuffer.emitByte(x); + } + + public final void emitShort(int x) { + codeBuffer.emitShort(x); + } + + public final void emitInt(int x) { + codeBuffer.emitInt(x); + } + + public final void emitLong(long x) { + codeBuffer.emitLong(x); + } + + public final void emitByte(int b, int pos) { + codeBuffer.emitByte(b, pos); + } + + public final void emitShort(int b, int pos) { + codeBuffer.emitShort(b, pos); + } + + public final void emitInt(int b, int pos) { + codeBuffer.emitInt(b, pos); + } + + public final void emitLong(long b, int pos) { + codeBuffer.emitLong(b, pos); + } + + public final int getByte(int pos) { + return codeBuffer.getByte(pos); + } + + public final int getShort(int pos) { + return codeBuffer.getShort(pos); + } + + public final int getInt(int pos) { + return codeBuffer.getInt(pos); + } + + private static final String NEWLINE = System.getProperty("line.separator"); + + /** + * Some GPU architectures have a text based encoding. + */ + public final void emitString(String x) { + emitString0("\t"); // XXX REMOVE ME pretty-printing + emitString0(x); + emitString0(NEWLINE); + } + + // XXX for pretty-printing + public final void emitString0(String x) { + codeBuffer.emitBytes(x.getBytes(), 0, x.length()); + } + + public void emitString(String s, int pos) { + codeBuffer.emitBytes(s.getBytes(), pos); + } + + /** + * Closes this assembler. No extra data can be written to this assembler after this call. + * + * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not + * including) {@code position()} is returned + * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true} + */ + public byte[] close(boolean trimmedCopy) { + return codeBuffer.close(trimmedCopy); + } + + public void bind(Label l) { + assert !l.isBound() : "can bind label only once"; + l.bind(position()); + l.patchInstructions(this); + } + + public abstract void align(int modulus); + + public abstract void jmp(Label l); + + protected abstract void patchJumpTarget(int branch, int jumpTarget); + + private Map nameMap; + + /** + * Creates a name for a label. + * + * @param l the label for which a name is being created + * @param id a label identifier that is unique with the scope of this assembler + * @return a label name in the form of "L123" + */ + protected String createLabelName(Label l, int id) { + return "L" + id; + } + + /** + * Gets a name for a label, creating it if it does not yet exist. By default, the returned name + * is only unique with the scope of this assembler. + */ + public String nameOf(Label l) { + if (nameMap == null) { + nameMap = new HashMap<>(); + } + String name = nameMap.get(l); + if (name == null) { + name = createLabelName(l, nameMap.size()); + nameMap.put(l, name); + } + return name; + } + + /** + * This is used by the CompilationResultBuilder to convert a {@link StackSlot} to an + * {@link AbstractAddress}. + */ + public abstract AbstractAddress makeAddress(Register base, int displacement); + + /** + * Returns a target specific placeholder address that can be used for code patching. + */ + public abstract AbstractAddress getPlaceholder(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,7 +28,7 @@ * Code buffer management for the assembler. Support for little endian and big endian architectures * is implemented using subclasses. */ -public abstract class Buffer { +abstract class Buffer { protected byte[] data; protected int position; @@ -105,19 +105,6 @@ position = emitLong(b, position); } - private static final String NEWLINE = System.getProperty("line.separator"); - - public void emitString(String s) { - position = emitString("\t", position); // XXX REMOVE ME pretty-printing - position = emitString(s, position); - position = emitString(NEWLINE, position); - } - - // XXX for pretty-printing - public void emitString0(String s) { - emitBytes(s.getBytes(), 0, s.length()); - } - public int emitBytes(byte[] arr, int pos) { final int len = arr.length; final int newPos = pos + len; @@ -140,10 +127,6 @@ public abstract int emitLong(long b, int pos); - public int emitString(String s, int pos) { - return emitBytes(s.getBytes(), pos); - } - public int getByte(int pos) { return data[pos] & 0xff; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Label.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Label.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Label.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,8 +34,7 @@ /** * References to instructions that jump to this unresolved label. These instructions need to be - * patched when the label is bound using the {@link #patchInstructions(AbstractAssembler)} - * method. + * patched when the label is bound using the {@link #patchInstructions(Assembler)} method. */ private ArrayList patchPositions = null; @@ -82,7 +81,7 @@ patchPositions.add(branchLocation); } - protected void patchInstructions(AbstractAssembler masm) { + protected void patchInstructions(Assembler masm) { assert isBound() : "Label should be bound"; if (patchPositions != null) { int target = position; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaslineCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaslineCompiler.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,710 @@ +/* + * 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.baseline; + +import static com.oracle.graal.api.code.TypeCheckHints.*; +import static com.oracle.graal.api.meta.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.bytecode.Bytecodes.*; +import static com.oracle.graal.phases.GraalOptions.*; +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.api.meta.ResolvedJavaType.Representation; +import com.oracle.graal.bytecode.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; +import com.oracle.graal.java.BciBlockMapping.Block; +import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; +import com.oracle.graal.java.GraphBuilderPhase.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; + +/** + * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. + */ +@SuppressWarnings("all") +public class BaslineCompiler { + + public BaslineCompiler(GraphBuilderConfiguration graphBuilderConfig, MetaAccessProvider metaAccess) { + this.graphBuilderConfig = graphBuilderConfig; + this.metaAccess = metaAccess; + } + + private final MetaAccessProvider metaAccess; + private ConstantPool constantPool; + private ResolvedJavaMethod method; + private int entryBCI; + private ProfilingInfo profilingInfo; + private BytecodeStream stream; // the bytecode stream + + private Block currentBlock; + + private ValueNode methodSynchronizedObject; + private ExceptionDispatchBlock unwindBlock; + + private final GraphBuilderConfiguration graphBuilderConfig; + private Block[] loopHeaders; + + /** + * Meters the number of actual bytecodes parsed. + */ + public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed"); + + protected ResolvedJavaMethod getMethod() { + return method; + } + + public LIR generate(ResolvedJavaMethod method, int entryBCI) { + this.method = method; + this.entryBCI = entryBCI; + profilingInfo = method.getProfilingInfo(); + assert method.getCode() != null : "method must contain bytecodes: " + method; + this.stream = new BytecodeStream(method.getCode()); + this.constantPool = method.getConstantPool(); + unwindBlock = null; + methodSynchronizedObject = null; + TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); + try { + build(); + } finally { + filter.remove(); + } + return null; + } + + protected void build() { + if (PrintProfilingInformation.getValue()) { + TTY.println("Profiling info for " + MetaUtil.format("%H.%n(%p)", method)); + TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), " ")); + } + + Indent indent = Debug.logAndIndent("build graph for %s", method); + + // compute the block map, setup exception handlers and get the entrypoint(s) + BciBlockMapping blockMap = BciBlockMapping.create(method); + loopHeaders = blockMap.loopHeaders; + + if (isSynchronized(method.getModifiers())) { + throw GraalInternalError.unimplemented("Handle synchronized methods"); + } + + // TODO: clear non live locals + + currentBlock = blockMap.startBlock; + if (blockMap.startBlock.isLoopHeader) { + throw GraalInternalError.unimplemented("Handle start block as loop header"); + } + + for (Block block : blockMap.blocks) { + processBlock(block); + } + + indent.outdent(); + } + + public BytecodeStream stream() { + return stream; + } + + public int bci() { + return stream.currentBCI(); + } + + private void loadLocal(int index, Kind kind) { + throw GraalInternalError.unimplemented(); + } + + private void storeLocal(Kind kind, int index) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param type the unresolved type of the constant + */ + protected void handleUnresolvedLoadConstant(JavaType type) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param type the unresolved type of the type check + * @param object the object value whose type is being checked against {@code type} + */ + protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param type the unresolved type of the type check + * @param object the object value whose type is being checked against {@code type} + */ + protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param type the type being instantiated + */ + protected void handleUnresolvedNewInstance(JavaType type) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param type the type of the array being instantiated + * @param length the length of the array + */ + protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param type the type being instantiated + * @param dims the dimensions for the multi-array + */ + protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param field the unresolved field + * @param receiver the object containing the field or {@code null} if {@code field} is static + */ + protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param field the unresolved field + * @param value the value being stored to the field + * @param receiver the object containing the field or {@code null} if {@code field} is static + */ + protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { + throw GraalInternalError.unimplemented(); + } + + /** + * @param representation + * @param type + */ + protected void handleUnresolvedExceptionType(Representation representation, JavaType type) { + throw GraalInternalError.unimplemented(); + } + + protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { + throw GraalInternalError.unimplemented(); + } + + private DispatchBeginNode handleException(ValueNode exceptionObject, int bci) { + throw GraalInternalError.unimplemented(); + } + + private void genLoadConstant(int cpi, int opcode) { + throw GraalInternalError.unimplemented(); + } + + private void genLoadIndexed(Kind kind) { + throw GraalInternalError.unimplemented(); + } + + private void genStoreIndexed(Kind kind) { + throw GraalInternalError.unimplemented(); + } + + private void stackOp(int opcode) { + throw GraalInternalError.unimplemented(); + } + + private void genArithmeticOp(Kind result, int opcode) { + throw GraalInternalError.unimplemented(); + } + + private void genIntegerDivOp(Kind result, int opcode) { + throw GraalInternalError.unimplemented(); + } + + private void genNegateOp(Kind kind) { + throw GraalInternalError.unimplemented(); + } + + private void genShiftOp(Kind kind, int opcode) { + throw GraalInternalError.unimplemented(); + } + + private void genLogicOp(Kind kind, int opcode) { + throw GraalInternalError.unimplemented(); + } + + private void genCompareOp(Kind kind, boolean isUnorderedLess) { + throw GraalInternalError.unimplemented(); + } + + private void genFloatConvert(FloatConvert op, Kind from, Kind to) { + throw GraalInternalError.unimplemented(); + } + + private void genSignExtend(Kind from, Kind to) { + throw GraalInternalError.unimplemented(); + } + + private void genZeroExtend(Kind from, Kind to) { + throw GraalInternalError.unimplemented(); + } + + private void genNarrow(Kind from, Kind to) { + throw GraalInternalError.unimplemented(); + } + + private void genIncrement() { + throw GraalInternalError.unimplemented(); + } + + private void genGoto() { + throw GraalInternalError.unimplemented(); + } + + private void genIfZero(Condition cond) { + throw GraalInternalError.unimplemented(); + } + + private void genIfNull(Condition cond) { + throw GraalInternalError.unimplemented(); + } + + private void genIfSame(Kind kind, Condition cond) { + throw GraalInternalError.unimplemented(); + } + + private void genThrow() { + throw GraalInternalError.unimplemented(); + } + + private JavaType lookupType(int cpi, int bytecode) { + eagerResolvingForSnippets(cpi, bytecode); + JavaType result = constantPool.lookupType(cpi, bytecode); + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; + return result; + } + + private JavaMethod lookupMethod(int cpi, int opcode) { + eagerResolvingForSnippets(cpi, opcode); + JavaMethod result = constantPool.lookupMethod(cpi, opcode); + /* + * assert !graphBuilderConfig.unresolvedIsError() || ((result instanceof ResolvedJavaMethod) + * && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result; + */ + return result; + } + + private JavaField lookupField(int cpi, int opcode) { + eagerResolvingForSnippets(cpi, opcode); + JavaField result = constantPool.lookupField(cpi, opcode); + assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; + return result; + } + + private Object lookupConstant(int cpi, int opcode) { + eagerResolvingForSnippets(cpi, opcode); + Object result = constantPool.lookupConstant(cpi); + assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType); + return result; + } + + private void eagerResolvingForSnippets(int cpi, int bytecode) { + if (graphBuilderConfig.eagerResolving()) { + constantPool.loadReferencedType(cpi, bytecode); + } + } + + private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) { + if (!canHaveSubtype(type)) { + return null; + } else { + return profilingInfo.getTypeProfile(bci()); + } + } + + private void genCheckCast() { + throw GraalInternalError.unimplemented(); + } + + private void genInstanceOf() { + throw GraalInternalError.unimplemented(); + } + + void genNewInstance(int cpi) { + throw GraalInternalError.unimplemented(); + } + + protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) { + return new NewInstanceNode(type, fillContents); + } + + private void genNewPrimitiveArray(int typeCode) { + throw GraalInternalError.unimplemented(); + } + + private void genNewObjectArray(int cpi) { + throw GraalInternalError.unimplemented(); + } + + private void genNewMultiArray(int cpi) { + throw GraalInternalError.unimplemented(); + } + + private void genGetField(JavaField field) { + throw GraalInternalError.unimplemented(); + } + + private void genPutField(JavaField field) { + throw GraalInternalError.unimplemented(); + } + + private void genGetStatic(JavaField field) { + throw GraalInternalError.unimplemented(); + } + + private void genPutStatic(JavaField field) { + throw GraalInternalError.unimplemented(); + } + + private void genInvokeStatic(JavaMethod target) { + throw GraalInternalError.unimplemented(); + } + + private void genInvokeInterface(JavaMethod target) { + throw GraalInternalError.unimplemented(); + } + + private void genInvokeDynamic(JavaMethod target) { + throw GraalInternalError.unimplemented(); + } + + private void genInvokeVirtual(JavaMethod target) { + throw GraalInternalError.unimplemented(); + } + + private void genInvokeSpecial(JavaMethod target) { + throw GraalInternalError.unimplemented(); + } + + private void genJsr(int dest) { + throw GraalInternalError.unimplemented(); + } + + private void genRet(int localIndex) { + throw GraalInternalError.unimplemented(); + } + + private void genSwitch(BytecodeSwitch bs) { + throw GraalInternalError.unimplemented(); + } + + private void processBlock(Block block) { + Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader); + currentBlock = block; + iterateBytecodesForBlock(block); + indent.outdent(); + } + + private void createExceptionDispatch(ExceptionDispatchBlock block) { + throw GraalInternalError.unimplemented(); + } + + private void iterateBytecodesForBlock(Block block) { + + int endBCI = stream.endBCI(); + + stream.setBCI(block.startBci); + int bci = block.startBci; + BytecodesParsed.add(block.endBci - bci); + + while (bci < endBCI) { + + // read the opcode + int opcode = stream.currentBC(); + traceInstruction(bci, opcode, bci == block.startBci); + if (bci == entryBCI) { + throw GraalInternalError.unimplemented(); + } + processBytecode(bci, opcode); + + stream.next(); + bci = stream.currentBCI(); + } + } + + private void processBytecode(int bci, int opcode) { + int cpi; + + // Checkstyle: stop + // @formatter:off + switch (opcode) { + case NOP : /* nothing to do */ break; +// case ACONST_NULL : frameState.apush(appendConstant(Constant.NULL_OBJECT)); break; +// case ICONST_M1 : frameState.ipush(appendConstant(Constant.INT_MINUS_1)); break; +// case ICONST_0 : frameState.ipush(appendConstant(Constant.INT_0)); break; +// case ICONST_1 : frameState.ipush(appendConstant(Constant.INT_1)); break; +// case ICONST_2 : frameState.ipush(appendConstant(Constant.INT_2)); break; +// case ICONST_3 : frameState.ipush(appendConstant(Constant.INT_3)); break; +// case ICONST_4 : frameState.ipush(appendConstant(Constant.INT_4)); break; +// case ICONST_5 : frameState.ipush(appendConstant(Constant.INT_5)); break; +// case LCONST_0 : frameState.lpush(appendConstant(Constant.LONG_0)); break; +// case LCONST_1 : frameState.lpush(appendConstant(Constant.LONG_1)); break; +// case FCONST_0 : frameState.fpush(appendConstant(Constant.FLOAT_0)); break; +// case FCONST_1 : frameState.fpush(appendConstant(Constant.FLOAT_1)); break; +// case FCONST_2 : frameState.fpush(appendConstant(Constant.FLOAT_2)); break; +// case DCONST_0 : frameState.dpush(appendConstant(Constant.DOUBLE_0)); break; +// case DCONST_1 : frameState.dpush(appendConstant(Constant.DOUBLE_1)); break; +// case BIPUSH : frameState.ipush(appendConstant(Constant.forInt(stream.readByte()))); break; +// case SIPUSH : frameState.ipush(appendConstant(Constant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; + case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; + case IALOAD : genLoadIndexed(Kind.Int ); break; + case LALOAD : genLoadIndexed(Kind.Long ); break; + case FALOAD : genLoadIndexed(Kind.Float ); break; + case DALOAD : genLoadIndexed(Kind.Double); break; + case AALOAD : genLoadIndexed(Kind.Object); break; + case BALOAD : genLoadIndexed(Kind.Byte ); break; + case CALOAD : genLoadIndexed(Kind.Char ); break; + case SALOAD : genLoadIndexed(Kind.Short ); break; + case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(Kind.Int ); break; + case LASTORE : genStoreIndexed(Kind.Long ); break; + case FASTORE : genStoreIndexed(Kind.Float ); break; + case DASTORE : genStoreIndexed(Kind.Double); break; + case AASTORE : genStoreIndexed(Kind.Object); break; + case BASTORE : genStoreIndexed(Kind.Byte ); break; + case CASTORE : genStoreIndexed(Kind.Char ); break; + case SASTORE : genStoreIndexed(Kind.Short ); break; + case POP : // fall through + case POP2 : // fall through + case DUP : // fall through + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(Kind.Int, opcode); break; + case IDIV : // fall through + case IREM : genIntegerDivOp(Kind.Int, opcode); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(Kind.Long, opcode); break; + case LDIV : // fall through + case LREM : genIntegerDivOp(Kind.Long, opcode); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(Kind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(Kind.Double, opcode); break; + case INEG : genNegateOp(Kind.Int); break; + case LNEG : genNegateOp(Kind.Long); break; + case FNEG : genNegateOp(Kind.Float); break; + case DNEG : genNegateOp(Kind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(Kind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(Kind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(Kind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(Kind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; + case L2I : genNarrow(Kind.Long, Kind.Int); break; + case I2L : genSignExtend(Kind.Int, Kind.Long); break; + case I2B : genSignExtend(Kind.Byte, Kind.Int); break; + case I2S : genSignExtend(Kind.Short, Kind.Int); break; + case I2C : genZeroExtend(Kind.Char, Kind.Int); break; + case LCMP : genCompareOp(Kind.Long, false); break; + case FCMPL : genCompareOp(Kind.Float, true); break; + case FCMPG : genCompareOp(Kind.Float, false); break; + case DCMPL : genCompareOp(Kind.Double, true); break; + case DCMPG : genCompareOp(Kind.Double, false); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; + case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; + case GOTO : genGoto(); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genSwitch(new BytecodeTableSwitch(stream(), bci())); break; + case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(stream(), bci())); break; +// case IRETURN : genReturn(frameState.ipop()); break; +// case LRETURN : genReturn(frameState.lpop()); break; +// case FRETURN : genReturn(frameState.fpop()); break; +// case DRETURN : genReturn(frameState.dpop()); break; +// case ARETURN : genReturn(frameState.apop()); break; +// case RETURN : genReturn(null); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; +// case MONITORENTER : genMonitorEnter(frameState.apop()); break; +// case MONITOREXIT : genMonitorExit(frameState.apop(), null); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(); break; + case JSR_W : genJsr(stream.readBranchDest()); break; + case BREAKPOINT: + throw new BailoutException("concurrent setting of breakpoint"); + default: + throw new BailoutException("Unsupported opcode " + opcode + " (" + nameOf(opcode) + ") [bci=" + bci + "]"); + } + // @formatter:on + // Checkstyle: resume + } + + private void traceInstruction(int bci, int opcode, boolean blockStart) { + if (Debug.isLogEnabled()) { + StringBuilder sb = new StringBuilder(40); + sb.append(blockStart ? '+' : '|'); + if (bci < 10) { + sb.append(" "); + } else if (bci < 100) { + sb.append(' '); + } + sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); + for (int i = bci + 1; i < stream.nextBCI(); ++i) { + sb.append(' ').append(stream.readUByte(i)); + } + if (!currentBlock.jsrScope.isEmpty()) { + sb.append(' ').append(currentBlock.jsrScope); + } + Debug.log(sb.toString()); + } + } + + private void genArrayLength() { + throw GraalInternalError.unimplemented(); + } +} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -57,13 +57,12 @@ import com.oracle.graal.lir.amd64.AMD64ControlFlow.ReturnOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; -import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; -import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; -import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.util.*; /** @@ -77,17 +76,8 @@ private static final RegisterValue RDX_L = AMD64.rdx.asValue(Kind.Long); private static final RegisterValue RCX_I = AMD64.rcx.asValue(Kind.Int); - private class AMD64SpillMoveFactory implements LIR.SpillMoveFactory { - - @Override - public LIRInstruction createMove(AllocatableValue result, Value input) { - return AMD64LIRGenerator.this.createMove(result, input); - } - } - public AMD64LIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { super(graph, providers, frameMap, cc, lir); - lir.spillMoveFactory = new AMD64SpillMoveFactory(); } @Override @@ -125,24 +115,20 @@ @Override public Variable emitMove(Value input) { - Variable result = newVariable(input.getPlatformKind()); + PlatformKind kind; + if (input instanceof Constant) { + kind = input.getKind().getStackKind(); + } else { + kind = input.getPlatformKind(); + } + Variable result = newVariable(kind); emitMove(result, input); return result; } - protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { - if (src instanceof AMD64AddressValue) { - return new LeaOp(dst, (AMD64AddressValue) src); - } else if (isRegister(src) || isStackSlot(dst)) { - return new MoveFromRegOp(dst, src); - } else { - return new MoveToRegOp(dst, src); - } - } - @Override public void emitMove(AllocatableValue dst, Value src) { - append(createMove(dst, src)); + append(AMD64Move.createMove(dst, src)); } @Override @@ -172,7 +158,7 @@ } else if (scaleEnum == null) { /* Scale value that architecture cannot handle, so scale manually. */ - Value longIndex = index.getKind().getStackKind() == Kind.Int ? emitConvert(Kind.Int, Kind.Long, index) : index; + Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64); if (CodeUtil.isPowerOf2(scale)) { indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale))); } else { @@ -229,18 +215,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 +241,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 @@ -361,7 +339,7 @@ @Override public void emitNullCheck(ValueNode v, DeoptimizingNode deoping) { - assert v.kind() == Kind.Object; + assert v.stamp() instanceof ObjectStamp; append(new AMD64Move.NullCheckOp(load(operand(v)), state(deoping))); } @@ -714,181 +692,153 @@ } } - private AllocatableValue emitConvertMove(Kind kind, AllocatableValue input) { - Variable result = newVariable(kind); - emitMove(result, input); - return result; - } - - private AllocatableValue emitConvert1Op(Kind kind, AMD64Arithmetic op, AllocatableValue input) { + private AllocatableValue emitConvert1Op(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) { Variable result = newVariable(kind); append(new Unary1Op(op, result, input)); return result; } - private AllocatableValue emitConvert2Op(Kind kind, AMD64Arithmetic op, AllocatableValue input) { + private AllocatableValue emitConvert2Op(PlatformKind kind, AMD64Arithmetic op, AllocatableValue input) { Variable result = newVariable(kind); append(new Unary2Op(op, result, input)); return result; } @Override - public AllocatableValue emitConvert(Kind from, Kind to, Value inputVal) { - assert inputVal.getKind() == from.getStackKind(); + public Value emitReinterpret(PlatformKind to, Value inputVal) { + Kind from = inputVal.getKind(); + if (to == from) { + return inputVal; + } AllocatableValue input = asAllocatable(inputVal); - if (from == to) { - return input; - } - switch (to) { - case Byte: - switch (from) { - case Short: - case Char: - case Int: - case Long: - return emitConvert2Op(to, I2B, input); - case Float: - case Double: - AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal); - return emitConvert(Kind.Int, to, intVal); - } - break; - case Char: - switch (from) { - case Byte: - case Short: - case Int: - case Long: - return emitConvert1Op(to, I2C, input); - case Float: - case Double: - AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal); - return emitConvert(Kind.Int, to, intVal); - } - break; - case Short: - switch (from) { - case Byte: - case Char: - case Int: - case Long: - return emitConvert2Op(to, I2S, input); - case Float: - case Double: - AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal); - return emitConvert(Kind.Int, to, intVal); - } - break; + /* + * Conversions between integer to floating point types require moves between CPU and FPU + * registers. + */ + switch ((Kind) to) { case Int: switch (from) { - case Byte: - case Short: - case Char: - return emitConvertMove(to, input); - case Long: - return emitConvert1Op(to, L2I, input); case Float: - return emitConvert2Op(to, F2I, input); - case Double: - return emitConvert2Op(to, D2I, input); + return emitConvert2Op(to, MOV_F2I, input); } break; case Long: switch (from) { - case Byte: - case Short: - case Char: - case Int: - return emitConvert2Op(to, I2L, input); - case Float: - return emitConvert2Op(to, F2L, input); case Double: - return emitConvert2Op(to, D2L, input); + return emitConvert2Op(to, MOV_D2L, input); } break; case Float: switch (from) { - case Byte: - case Short: - case Char: case Int: - return emitConvert2Op(to, I2F, input); - case Long: - return emitConvert2Op(to, L2F, input); - case Double: - return emitConvert2Op(to, D2F, input); + return emitConvert2Op(to, MOV_I2F, input); } break; case Double: switch (from) { - case Byte: - case Short: - case Char: - case Int: - return emitConvert2Op(to, I2D, input); case Long: - return emitConvert2Op(to, L2D, input); - case Float: - return emitConvert2Op(to, F2D, input); + return emitConvert2Op(to, MOV_L2D, input); } break; } throw GraalInternalError.shouldNotReachHere(); } - public AllocatableValue emitReinterpret(Kind to, Value inputVal) { - Kind from = inputVal.getKind(); + public Value emitFloatConvert(FloatConvert op, Value inputVal) { AllocatableValue input = asAllocatable(inputVal); + switch (op) { + case D2F: + return emitConvert2Op(Kind.Float, D2F, input); + case D2I: + return emitConvert2Op(Kind.Int, D2I, input); + case D2L: + return emitConvert2Op(Kind.Long, D2L, input); + case F2D: + return emitConvert2Op(Kind.Double, F2D, input); + case F2I: + return emitConvert2Op(Kind.Int, F2I, input); + case F2L: + return emitConvert2Op(Kind.Long, F2L, input); + case I2D: + return emitConvert2Op(Kind.Double, I2D, input); + case I2F: + return emitConvert2Op(Kind.Float, I2F, input); + case L2D: + return emitConvert2Op(Kind.Double, L2D, input); + case L2F: + return emitConvert2Op(Kind.Float, L2F, input); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public Value emitNarrow(Value inputVal, int bits) { + if (inputVal.getKind() == Kind.Long && bits <= 32) { + // TODO make it possible to reinterpret Long as Int in LIR without move + return emitConvert1Op(Kind.Int, L2I, asAllocatable(inputVal)); + } else { + return inputVal; + } + } - /* - * Conversions between integer to floating point types require moves between CPU and FPU - * registers. - */ - switch (to) { - case Int: - switch (from) { - case Float: - case Double: - return emitConvert2Op(to, MOV_F2I, input); - } - break; - case Long: - switch (from) { - case Float: - case Double: - return emitConvert2Op(to, MOV_D2L, input); - case Int: - /* - * Unsigned int-to-long conversion: In theory, instructions that move or - * generate 32-bit register values also set the upper 32 bits of the - * register to zero. However, we cannot rely that the value was really - * generated by an instruction, it could come from an untrusted source such - * as native code. Therefore, make sure the high bits are really cleared. - */ - Variable temp = newVariable(Kind.Int); - Variable result = newVariable(Kind.Long); - append(new BinaryRegConst(AMD64Arithmetic.IAND, temp, input, Constant.forInt(0xFFFFFFFF))); - emitMove(result, temp); - return result; - } - break; - case Float: - switch (from) { - case Int: - case Long: - return emitConvert2Op(to, MOV_I2F, input); - } - break; - case Double: - switch (from) { - case Int: - case Long: - return emitConvert2Op(to, MOV_L2D, input); - } - break; + @Override + public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (toBits > 32) { + // sign extend to 64 bits + switch (fromBits) { + case 8: + return emitConvert2Op(Kind.Long, B2L, asAllocatable(inputVal)); + case 16: + return emitConvert2Op(Kind.Long, S2L, asAllocatable(inputVal)); + case 32: + return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal)); + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } else { + // sign extend to 32 bits (smaller values are internally represented as 32 bit values) + switch (fromBits) { + case 8: + return emitConvert2Op(Kind.Int, B2I, asAllocatable(inputVal)); + case 16: + return emitConvert2Op(Kind.Int, S2I, asAllocatable(inputVal)); + case 32: + return inputVal; + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } } - throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (fromBits > 32) { + assert inputVal.getKind() == Kind.Long; + Variable result = newVariable(Kind.Long); + long mask = IntegerStamp.defaultMask(fromBits); + append(new BinaryRegConst(AMD64Arithmetic.LAND, result, asAllocatable(inputVal), Constant.forLong(mask))); + return result; + } else { + assert inputVal.getKind() == Kind.Int; + Variable result = newVariable(Kind.Int); + int mask = (int) IntegerStamp.defaultMask(fromBits); + append(new BinaryRegConst(AMD64Arithmetic.IAND, result, asAllocatable(inputVal), Constant.forInt(mask))); + if (toBits > 32) { + Variable longResult = newVariable(Kind.Long); + emitMove(longResult, result); + return longResult; + } else { + return result; + } + } } @Override @@ -899,6 +849,8 @@ } } + public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments); + @Override protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { long maxOffset = linkage.getMaxCallTargetOffset(); @@ -980,8 +932,8 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { - append(new AMD64CharArrayEqualsOp(this, result, array1, array2, asAllocatable(length))); + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { + append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); } @Override diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,33 +27,50 @@ * This class extends KernelTester and provides a base class * for which the HSAIL code comes from the Graal compiler. */ +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.phases.GraalOptions.*; import java.io.*; import java.lang.reflect.*; +import org.junit.*; + import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.hsail.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hsail.*; import com.oracle.graal.options.*; - -import com.oracle.graal.phases.GraalOptions; -import static com.oracle.graal.options.OptionValue.OverrideScope; +import com.oracle.graal.options.OptionValue.OverrideScope; +import com.oracle.graal.phases.*; public abstract class GraalKernelTester extends KernelTester { - HSAILCompilationResult hsailCompResult; + public GraalKernelTester() { + super(getHSAILBackend().isDeviceInitialized()); + } + + private static HSAILHotSpotBackend getHSAILBackend() { + Backend backend = runtime().getBackend(HSAIL.class); + Assume.assumeTrue(backend instanceof HSAILHotSpotBackend); + return (HSAILHotSpotBackend) backend; + } + + ExternalCompilationResult hsailCode; private boolean showHsailSource = false; private boolean saveInFile = false; @Override public String getCompiledHSAILSource(Method method) { - if (hsailCompResult == null) { - hsailCompResult = HSAILCompilationResult.getHSAILCompilationResult(method); + if (hsailCode == null) { + HSAILHotSpotBackend backend = getHSAILBackend(); + ResolvedJavaMethod javaMethod = backend.getProviders().getMetaAccess().lookupJavaMethod(method); + hsailCode = backend.compileKernel(javaMethod, false); } - String hsailSource = hsailCompResult.getHSAILCode(); + String hsailSource = hsailCode.getCodeString(); if (showHsailSource) { logger.severe(hsailSource); } @@ -86,12 +103,11 @@ @Override protected void dispatchKernelOkra(int range, Object... args) { - HSAILCompilationResult hcr = HSAILCompilationResult.getHSAILCompilationResult(testMethod); - HotSpotNmethod code = (HotSpotNmethod) hcr.getInstalledCode(); - - if (code != null) { + HSAILHotSpotBackend backend = getHSAILBackend(); + if (backend.isDeviceInitialized()) { try { - code.executeParallel(range, 0, 0, args); + HotSpotNmethod code = backend.compileAndInstallKernel(testMethod); + backend.executeKernel(code, range, args); } catch (InvalidInstalledCodeException e) { Debug.log("WARNING:Invalid installed code: " + e); e.printStackTrace(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Wed Mar 05 19:40:15 2014 -0800 @@ -108,17 +108,17 @@ private static boolean gaveNoOkraWarning = false; private boolean onSimulator; - private boolean okraLibExists; + private final boolean okraLibExists; public boolean runningOnSimulator() { return onSimulator; } - public KernelTester() { - okraLibExists = OkraUtil.okraLibExists(); + public KernelTester(boolean okraLibExists) { dispatchMode = DispatchMode.SEQ; hsailMode = HsailMode.COMPILED; useLambdaMethod = false; + this.okraLibExists = okraLibExists; } public abstract void runTest(); diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java --- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/BasicHSAILTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,14 +22,17 @@ */ package com.oracle.graal.compiler.hsail.test; +import java.lang.reflect.*; + import org.junit.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.hotspot.hsail.*; import com.oracle.graal.hsail.*; -import com.oracle.graal.nodes.*; /** * Test class for small Java methods compiled to HSAIL kernels. @@ -332,11 +335,18 @@ out[gid] = val; } + @Override + protected HSAILHotSpotBackend getBackend() { + Backend backend = super.getBackend(); + Assume.assumeTrue(backend instanceof HSAILHotSpotBackend); + return (HSAILHotSpotBackend) backend; + } + private void test(final String snippet) { try (Scope s = Debug.scope("HSAILCodeGen")) { - StructuredGraph graph = parse(snippet); - HSAILCompilationResult compResult = HSAILCompilationResult.getHSAILCompilationResult(graph); - Debug.log("HSAIL code generated for %s:%n%s", snippet, compResult.getHSAILCode()); + Method method = getMethod(snippet); + ExternalCompilationResult hsailCode = getBackend().compileKernel(getMetaAccess().lookupJavaMethod(method), false); + Debug.log("HSAIL code generated for %s:%n%s", snippet, hsailCode.getCodeString()); } catch (Throwable e) { throw Debug.handle(e); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMethod16InArraysTest.java --- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMethod16InArraysTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMethod16InArraysTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -62,6 +62,7 @@ * there are registers. */ @Test(expected = java.lang.ClassCastException.class) + @Ignore("until GPU backends can co-exist") public void test() { DebugConfig debugConfig = DebugScope.getConfig(); DebugConfig noInterceptConfig = new DelegatingDebugConfig(debugConfig) { diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -47,12 +47,13 @@ import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCondMoveOp; import com.oracle.graal.lir.hsail.HSAILControlFlow.ReturnOp; import com.oracle.graal.lir.hsail.HSAILControlFlow.StrategySwitchOp; -import com.oracle.graal.lir.hsail.HSAILMove.LeaOp; import com.oracle.graal.lir.hsail.HSAILMove.MembarOp; import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp; import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.util.*; /** @@ -60,23 +61,8 @@ */ public abstract class HSAILLIRGenerator extends LIRGenerator { - public static class HSAILSpillMoveFactory implements LIR.SpillMoveFactory { - - @Override - public LIRInstruction createMove(AllocatableValue dst, Value src) { - if (src instanceof HSAILAddressValue) { - return new LeaOp(dst, (HSAILAddressValue) src); - } else if (isRegister(src) || isStackSlot(dst)) { - return new MoveFromRegOp(dst, src); - } else { - return new MoveToRegOp(dst, src); - } - } - } - public HSAILLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { super(graph, providers, frameMap, cc, lir); - lir.spillMoveFactory = new HSAILSpillMoveFactory(); } @Override @@ -145,7 +131,7 @@ } else { Value indexRegister; Value convertedIndex; - convertedIndex = this.emitConvert(Kind.Int, Kind.Long, index); + convertedIndex = this.emitSignExtend(index, 32, 64); if (scale != 1) { indexRegister = emitUMul(convertedIndex, Constant.forInt(scale)); } else { @@ -189,7 +175,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 +196,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(); } @@ -592,15 +578,92 @@ } @Override - public Variable emitConvert(Kind from, Kind to, Value inputVal) { + public Value emitFloatConvert(FloatConvert op, Value inputVal) { Variable input = load(inputVal); - Variable result = newVariable(to); + + String from; + switch (op) { + case D2F: + case D2I: + case D2L: + from = "f64"; + break; + case F2D: + case F2I: + case F2L: + from = "f32"; + break; + case I2D: + case I2F: + from = "s32"; + break; + case L2D: + case L2F: + from = "s64"; + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + + Variable result; + String to; + switch (op) { + case D2I: + case F2I: + to = "s32"; + result = newVariable(Kind.Int); + break; + case D2L: + case F2L: + to = "s64"; + result = newVariable(Kind.Long); + break; + case F2D: + case I2D: + case L2D: + to = "f64"; + result = newVariable(Kind.Double); + break; + case D2F: + case I2F: + case L2F: + to = "f32"; + result = newVariable(Kind.Float); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + append(new ConvertOp(result, input, to, from)); return result; } @Override - public Value emitReinterpret(Kind to, Value inputVal) { + public Value emitNarrow(Value inputVal, int bits) { + Variable input = load(inputVal); + Variable result = newVariable(bits > 32 ? Kind.Long : Kind.Int); + append(new ConvertOp(result, input, "s" + bits, input.getKind() == Kind.Long ? "s64" : "s32")); + return result; + } + + @Override + public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { + Variable input = load(inputVal); + Variable result = newVariable(toBits > 32 ? Kind.Long : Kind.Int); + append(new ConvertOp(result, input, "s" + toBits, "s" + fromBits)); + return result; + } + + @Override + public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { + Variable input = load(inputVal); + Variable result = newVariable(toBits > 32 ? Kind.Long : Kind.Int); + append(new ConvertOp(result, input, "u" + toBits, "u" + fromBits)); + return result; + } + + @Override + public Value emitReinterpret(PlatformKind to, Value inputVal) { Variable result = newVariable(to); emitMove(result, inputVal); return result; @@ -734,7 +797,7 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { // TODO Auto-generated method stub throw GraalInternalError.unimplemented(); } @@ -816,7 +879,7 @@ @Override public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { - assert v.kind() == Kind.Object; + assert v.stamp() instanceof ObjectStamp; Variable obj = newVariable(Kind.Object); emitMove(obj, operand(v)); append(new HSAILMove.NullCheckOp(obj, state(deopting))); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,6 +22,8 @@ */ package com.oracle.graal.compiler.ptx.test; +import static org.junit.Assert.*; + import org.junit.*; /** @@ -56,6 +58,11 @@ return p1 + p0; } + @Test + public void testGetAvailableProcessors() { + assertTrue(getPTXBackend().getAvailableProcessors() >= 0); + } + public static void main(String[] args) { compileAndPrintCode(new BasicPTXTest()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,16 +27,25 @@ public class ControlPTXTest extends PTXTest { @Test - public void testControl() { + public void testControl1() { test("testLoop", 42); test("testSwitchDefault1I", 3); test("testSwitch1I", 2); test("testIfElse1I", 222); test("testIfElse2I", 19, 64); + } - test("testIntegerTestBranch2I", 0xff00, 0x00ff); + @Test + public void testControl2() { compileKernel("testStatic"); compileKernel("testCall"); + } + + @Ignore("[CUDA] Check for malformed PTX kernel or incorrect PTX compilation options") + @Test + public void testControl3() { + // test("testIntegerTestBranch2I", 0xff00, 0x00ff); + compileKernel("testIntegerTestBranch2I"); compileKernel("testLookupSwitch1I"); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -63,7 +63,6 @@ return 32.0 + a; } - @Ignore @Test public void testSub() { compileKernel("testSub2F"); @@ -98,7 +97,7 @@ return 32.0 - a; } - @Ignore + @Ignore("[CUDA] *** Error (209) Failed to load module data with online compiler options for method testMul2F") @Test public void testMul() { compileKernel("testMul2F"); @@ -133,7 +132,7 @@ return 32.0 * a; } - @Ignore + @Ignore("[CUDA] *** Error (209) Failed to load module data with online compiler options for method testDiv2F") @Test public void testDiv() { compileKernel("testDiv2F"); @@ -168,7 +167,6 @@ return 32.0 / a; } - @Ignore @Test public void testNeg() { compileKernel("testNeg2F"); @@ -183,12 +181,11 @@ return -a; } - @Ignore + @Ignore("need linkage to PTX remainder") @Test public void testRem() { - // need linkage to PTX remainder() - // compileKernel("testRem2F"); - // compileKernel("testRem2D"); + compileKernel("testRem2F"); + compileKernel("testRem2D"); } public static float testRem2F(float a, float b) { @@ -199,7 +196,7 @@ return a % b; } - @Ignore + @Ignore("[CUDA] *** Error (209) Failed to load module data with online compiler options for method testF2I") @Test public void testFloatConversion() { compileKernel("testF2I"); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ObjectPTXTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,161 @@ +/* + * 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.ptx.test; + +import java.util.*; + +import org.junit.*; + +public class ObjectPTXTest extends PTXTest { + + static class A { + boolean z = true; + byte b = 17; + char c = 'D'; + short s = 12345; + int i = 0x1234565; + long l; + Object o; + float f; + double d; + } + + @Test + public void test0() { + for (long l : new long[]{Long.MIN_VALUE, -10, 0, 1, 2, 10, Long.MAX_VALUE}) { + A a = new A(); + a.l = l; + test("testLong", l * 2, a); + } + } + + public static long testLong(long l, A a) { + return a.l + l; + } + + @Test + public void test1() { + for (int i : new int[]{Integer.MIN_VALUE, -10, 0, 1, 2, 10, Integer.MAX_VALUE}) { + A a = new A(); + a.i = i; + test("testInt", i * 2, a); + } + } + + public static int testInt(int i, A a) { + return a.i + i; + } + + @Test + public void test2() { + A a = new A(); + a.z = true; + test("testBoolean", a); + a.z = false; + test("testBoolean", a); + } + + public static boolean testBoolean(A a) { + return a.z; + } + + @Test + public void test3() { + for (byte b : new byte[]{Byte.MIN_VALUE, -10, 0, 1, 2, 10, Byte.MAX_VALUE}) { + A a = new A(); + a.b = b; + test("testByte", b, a); + } + } + + public static int testByte(byte b, A a) { + return a.b + b; + } + + @Test + public void test4() { + for (short s : new short[]{Short.MIN_VALUE, -10, 0, 1, 2, 10, Short.MAX_VALUE}) { + A a = new A(); + a.s = s; + test("testShort", s, a); + } + } + + public static int testShort(short s, A a) { + return a.s + s; + } + + @Ignore("java.lang.AssertionError: expected:<65531> but was:<809107451>") + @Test + public void test5() { + for (char c : new char[]{Character.MIN_VALUE, 1, 2, 10, Character.MAX_VALUE}) { + A a = new A(); + a.c = c; + test("testChar", (char) (c - 5), a); + } + } + + public static int testChar(char c, A a) { + return a.c + c; + } + + @Test + public void test6() { + for (float f : new float[]{Float.MIN_VALUE, Float.MIN_NORMAL, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN, -11.45F, -0.0F, 0.0F, 2, 10, Float.MAX_VALUE}) { + A a = new A(); + a.f = f; + test("testFloat", f * 2, a); + } + } + + public static float testFloat(float f, A a) { + return a.f + f; + } + + @Test + public void test7() { + for (double d : new double[]{Double.MIN_VALUE, Double.MIN_NORMAL, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, -11.45D, -0.0D, 0.0D, 2, 10, Double.MAX_VALUE}) { + A a = new A(); + a.d = d; + test("testDouble", d * 2, a); + } + } + + public static double testDouble(double d, A a) { + return a.d + d; + } + + @Ignore("Object return values not yet supported") + @Test + public void test9() { + for (Object o : new Object[]{null, "object", new Object(), new HashMap()}) { + A a = new A(); + a.o = o; + test("testObject", a); + } + } + + public static Object testObject(A a) { + return a.o; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXPhase.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXPhase.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +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.compiler.ptx.test; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; - -public class PTXPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - /* - * Assume that null checks would be done on the CPU caller side prior to copying data onto - * the GPU. - */ - for (ParameterNode param : graph.getNodes(ParameterNode.class)) { - if (param.stamp() instanceof ObjectStamp) { - param.setStamp(StampFactory.declaredNonNull(((ObjectStamp) param.stamp()).type())); - } - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -43,7 +43,7 @@ */ public abstract class PTXTest extends GraalCompilerTest { - private static PTXHotSpotBackend getPTXBackend() { + public static PTXHotSpotBackend getPTXBackend() { Backend backend = runtime().getBackend(PTX.class); Assume.assumeTrue(backend instanceof PTXHotSpotBackend); return (PTXHotSpotBackend) backend; @@ -69,7 +69,15 @@ Assume.assumeTrue(ptxBackend.isDeviceInitialized()); HotSpotNmethod installedPTXCode = installKernel(method, ptxCode); StructuredGraph wrapper = new PTXWrapperBuilder(method, installedPTXCode, (HotSpotProviders) getProviders()).getGraph(); - return super.getCode(method, wrapper); + + // The PTX C++ layer expects a 1:1 relationship between kernel compilation + // and kernel execution as it creates a cuContext in the former and + // destroys it in the latter. So, each kernel installed requires a unique + // wrapper. + // TODO: do cuContext management properly + boolean forceCompile = true; + + return getCode(method, wrapper, forceCompile); } protected static void compileAndPrintCode(PTXTest test) { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -62,8 +62,10 @@ import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.util.*; /** @@ -79,17 +81,8 @@ public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class); public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class); - public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory { - - @Override - public LIRInstruction createMove(AllocatableValue result, Value input) { - throw GraalInternalError.unimplemented("PTXSpillMoveFactory.createMove()"); - } - } - public PTXLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { super(graph, providers, frameMap, cc, lir); - lir.spillMoveFactory = new PTXSpillMoveFactory(); int callVariables = cc.getArgumentCount() + (cc.getReturn().equals(Value.ILLEGAL) ? 0 : 1); lir.setFirstVariableNumber(callVariables); nextPredRegNum = 0; @@ -162,9 +155,9 @@ } Warp warpAnnotation = parameterIndex >= 0 ? MetaUtil.getParameterAnnotation(Warp.class, parameterIndex, graph.method()) : null; if (warpAnnotation != null) { - setResult(param, emitWarpParam(paramValue.getKind(), warpAnnotation)); + setResult(param, emitWarpParam(paramValue.getKind().getStackKind(), warpAnnotation)); } else { - setResult(param, emitLoadParam(paramValue.getKind(), paramValue, null)); + setResult(param, emitLoadParam(paramValue.getKind().getStackKind(), paramValue, null)); } } } @@ -232,7 +225,7 @@ Value convertedIndex; Value indexRegister; - convertedIndex = emitConvert(Kind.Int, Kind.Long, index); + convertedIndex = emitSignExtend(index, 32, 64); if (scale != 1) { if (CodeUtil.isPowerOf2(scale)) { indexRegister = emitShl(convertedIndex, Constant.forInt(CodeUtil.log2(scale))); @@ -299,7 +292,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 +320,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()"); @@ -681,15 +674,112 @@ return result; } - @Override - public Variable emitConvert(Kind from, Kind to, Value inputVal) { + public Variable emitConvertOp(Kind from, Kind to, Value inputVal) { Variable input = load(inputVal); Variable result = newVariable(to); append(new ConvertOp(result, input, to, from)); return result; } - public Value emitReinterpret(Kind to, Value inputVal) { + @Override + public Value emitFloatConvert(FloatConvert op, Value inputVal) { + switch (op) { + case D2F: + return emitConvertOp(Kind.Double, Kind.Float, inputVal); + case D2I: + return emitConvertOp(Kind.Double, Kind.Int, inputVal); + case D2L: + return emitConvertOp(Kind.Double, Kind.Long, inputVal); + case F2D: + return emitConvertOp(Kind.Float, Kind.Double, inputVal); + case F2I: + return emitConvertOp(Kind.Float, Kind.Int, inputVal); + case F2L: + return emitConvertOp(Kind.Float, Kind.Long, inputVal); + case I2D: + return emitConvertOp(Kind.Int, Kind.Double, inputVal); + case I2F: + return emitConvertOp(Kind.Int, Kind.Float, inputVal); + case L2D: + return emitConvertOp(Kind.Long, Kind.Double, inputVal); + case L2F: + return emitConvertOp(Kind.Long, Kind.Float, inputVal); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public Value emitNarrow(Value inputVal, int bits) { + if (inputVal.getKind() == Kind.Long && bits <= 32) { + return emitConvertOp(Kind.Long, Kind.Int, inputVal); + } else { + return inputVal; + } + } + + @Override + public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (toBits > 32) { + // sign extend to 64 bits + switch (fromBits) { + case 8: + return emitConvertOp(Kind.Byte, Kind.Long, inputVal); + case 16: + return emitConvertOp(Kind.Short, Kind.Long, inputVal); + case 32: + return emitConvertOp(Kind.Int, Kind.Long, inputVal); + case 64: + return inputVal; + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } else { + // sign extend to 32 bits (smaller values are internally represented as 32 bit values) + switch (fromBits) { + case 8: + return emitConvertOp(Kind.Byte, Kind.Int, inputVal); + case 16: + return emitConvertOp(Kind.Short, Kind.Int, inputVal); + case 32: + return inputVal; + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } + } + + @Override + public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (fromBits > 32) { + assert inputVal.getKind() == Kind.Long; + Variable result = newVariable(Kind.Long); + long mask = IntegerStamp.defaultMask(fromBits); + append(new Op2Stack(LAND, result, inputVal, Constant.forLong(mask))); + return result; + } else { + assert inputVal.getKind() == Kind.Int; + Variable result = newVariable(Kind.Int); + int mask = (int) IntegerStamp.defaultMask(fromBits); + append(new Op2Stack(IAND, result, inputVal, Constant.forInt(mask))); + if (toBits > 32) { + Variable longResult = newVariable(Kind.Long); + emitMove(longResult, result); + return longResult; + } else { + return result; + } + } + } + + @Override + public Value emitReinterpret(PlatformKind to, Value inputVal) { Variable result = newVariable(to); emitMove(result, inputVal); return result; @@ -775,7 +865,7 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { // TODO Auto-generated method stub throw GraalInternalError.unimplemented(); } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -52,15 +52,14 @@ import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp; -import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp; import com.oracle.graal.lir.sparc.SPARCMove.MembarOp; -import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp; -import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp; import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp; import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.util.*; /** @@ -68,17 +67,8 @@ */ public abstract class SPARCLIRGenerator extends LIRGenerator { - private class SPARCSpillMoveFactory implements LIR.SpillMoveFactory { - - @Override - public LIRInstruction createMove(AllocatableValue result, Value input) { - return SPARCLIRGenerator.this.createMove(result, input); - } - } - public SPARCLIRGenerator(StructuredGraph graph, Providers providers, FrameMap frameMap, CallingConvention cc, LIR lir) { super(graph, providers, frameMap, cc, lir); - lir.spillMoveFactory = new SPARCSpillMoveFactory(); } @Override @@ -114,19 +104,9 @@ return result; } - protected SPARCLIRInstruction createMove(AllocatableValue dst, Value src) { - if (src instanceof SPARCAddressValue) { - return new LoadAddressOp(dst, (SPARCAddressValue) src); - } else if (isRegister(src) || isStackSlot(dst)) { - return new MoveFromRegOp(dst, src); - } else { - return new MoveToRegOp(dst, src); - } - } - @Override public void emitMove(AllocatableValue dst, Value src) { - append(createMove(dst, src)); + append(SPARCMove.createMove(dst, src)); } @Override @@ -153,8 +133,7 @@ indexRegister = Value.ILLEGAL; } else { if (scale != 1) { - // Variable longIndex = newVariable(Kind.Long); - AllocatableValue longIndex = emitConvert(Kind.Int, Kind.Long, index); + Value longIndex = emitSignExtend(index, 32, 64); if (CodeUtil.isPowerOf2(scale)) { indexRegister = emitShl(longIndex, Constant.forLong(CodeUtil.log2(scale))); } else { @@ -230,7 +209,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 +233,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) { @@ -443,7 +422,7 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { // TODO Auto-generated method stub throw GraalInternalError.unimplemented(); } @@ -753,129 +732,120 @@ } } - private AllocatableValue emitConvertMove(Kind kind, AllocatableValue input) { + private AllocatableValue emitConvertMove(PlatformKind kind, AllocatableValue input) { Variable result = newVariable(kind); emitMove(result, input); return result; } - private AllocatableValue emitConvert2Op(Kind kind, SPARCArithmetic op, AllocatableValue input) { + private AllocatableValue emitConvert2Op(PlatformKind kind, SPARCArithmetic op, AllocatableValue input) { Variable result = newVariable(kind); append(new Unary2Op(op, result, input)); return result; } @Override - public AllocatableValue emitConvert(Kind from, Kind to, Value inputVal) { - assert inputVal.getKind() == from.getStackKind(); - + public Value emitFloatConvert(FloatConvert op, Value inputVal) { AllocatableValue input = asAllocatable(inputVal); - if (from == to) { - return input; + switch (op) { + case D2F: + return emitConvert2Op(Kind.Float, D2F, input); + case D2I: + return emitConvert2Op(Kind.Int, D2I, input); + case D2L: + return emitConvert2Op(Kind.Long, D2L, input); + case F2D: + return emitConvert2Op(Kind.Double, F2D, input); + case F2I: + return emitConvert2Op(Kind.Int, F2I, input); + case F2L: + return emitConvert2Op(Kind.Long, F2L, input); + case I2D: + return emitConvert2Op(Kind.Double, I2D, input); + case I2F: + return emitConvert2Op(Kind.Float, I2F, input); + case L2D: + return emitConvert2Op(Kind.Double, L2D, input); + case L2F: + return emitConvert2Op(Kind.Float, L2F, input); + default: + throw GraalInternalError.shouldNotReachHere(); } - switch (to) { - case Byte: - switch (from) { - case Short: - case Char: - case Int: - case Long: - return emitConvert2Op(to, I2B, input); - case Float: - case Double: - AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal); - return emitConvert(Kind.Int, to, intVal); - } - break; - case Char: - switch (from) { - case Byte: - case Short: - case Int: - case Long: - return emitConvert2Op(to, I2C, input); - case Float: - case Double: - AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal); - return emitConvert(Kind.Int, to, intVal); - } - break; - case Short: - switch (from) { - case Byte: - case Char: - case Int: - case Long: - return emitConvert2Op(to, I2S, input); - case Float: - case Double: - AllocatableValue intVal = emitConvert(from, Kind.Int, inputVal); - return emitConvert(Kind.Int, to, intVal); - } - break; - case Int: - switch (from) { - case Byte: - case Short: - case Char: - return emitConvertMove(to, input); - case Long: - return emitConvert2Op(to, L2I, input); - case Float: - return emitConvert2Op(to, F2I, input); - case Double: - return emitConvert2Op(to, D2I, input); - } - break; - case Long: - switch (from) { - case Byte: - case Short: - case Char: - case Int: - return emitConvert2Op(to, I2L, input); - case Float: - return emitConvert2Op(to, F2L, input); - case Double: - return emitConvert2Op(to, D2L, input); - } - break; - case Float: - switch (from) { - case Byte: - case Short: - case Char: - case Int: - return emitConvert2Op(to, I2F, input); - case Long: - return emitConvert2Op(to, L2F, input); - case Double: - return emitConvert2Op(to, D2F, input); - } - break; - case Double: - switch (from) { - case Byte: - case Short: - case Char: - case Int: - return emitConvert2Op(to, I2D, input); - case Long: - return emitConvert2Op(to, L2D, input); - case Float: - return emitConvert2Op(to, F2D, input); - } - break; + } + + @Override + public Value emitNarrow(Value inputVal, int bits) { + if (inputVal.getKind() == Kind.Long && bits <= 32) { + return emitConvert2Op(Kind.Int, L2I, asAllocatable(inputVal)); + } else { + return inputVal; } - throw GraalInternalError.shouldNotReachHere(); } - public AllocatableValue emitReinterpret(Kind to, Value inputVal) { + @Override + public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (toBits > 32) { + // sign extend to 64 bits + if (fromBits == 32) { + return emitConvert2Op(Kind.Long, I2L, asAllocatable(inputVal)); + } else if (fromBits < 32) { + // TODO implement direct x2L sign extension conversions + Value intVal = emitSignExtend(inputVal, fromBits, 32); + return emitSignExtend(intVal, 32, toBits); + } else { + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } else { + // sign extend to 32 bits (smaller values are internally represented as 32 bit values) + switch (fromBits) { + case 8: + return emitConvert2Op(Kind.Int, I2B, asAllocatable(inputVal)); + case 16: + return emitConvert2Op(Kind.Int, I2S, asAllocatable(inputVal)); + case 32: + return inputVal; + default: + throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); + } + } + } + + @Override + public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { + assert fromBits <= toBits && toBits <= 64; + if (fromBits == toBits) { + return inputVal; + } else if (fromBits > 32) { + assert inputVal.getKind() == Kind.Long; + Variable result = newVariable(Kind.Long); + long mask = IntegerStamp.defaultMask(fromBits); + append(new BinaryRegConst(SPARCArithmetic.LAND, result, asAllocatable(inputVal), Constant.forLong(mask))); + return result; + } else { + assert inputVal.getKind() == Kind.Int; + Variable result = newVariable(Kind.Int); + int mask = (int) IntegerStamp.defaultMask(fromBits); + append(new BinaryRegConst(SPARCArithmetic.IAND, result, asAllocatable(inputVal), Constant.forInt(mask))); + if (toBits > 32) { + Variable longResult = newVariable(Kind.Long); + emitMove(longResult, result); + return longResult; + } else { + return result; + } + } + } + + @Override + public AllocatableValue emitReinterpret(PlatformKind to, Value inputVal) { Kind from = inputVal.getKind(); AllocatableValue input = asAllocatable(inputVal); // These cases require a move between CPU and FPU registers: - switch (to) { + switch ((Kind) to) { case Int: switch (from) { case Float: diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -39,6 +39,7 @@ import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.baseline.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -83,10 +84,20 @@ private final Backend backend; private final Suites suites; + private static boolean substitutionsInstalled; + + private void installSubstitutions() { + if (!substitutionsInstalled) { + this.providers.getReplacements().registerSubstitutions(InjectProfileDataSubstitutions.class); + substitutionsInstalled = true; + } + } + public GraalCompilerTest() { this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); this.providers = getBackend().getProviders(); this.suites = backend.getSuites().createSuites(); + installSubstitutions(); } /** @@ -106,6 +117,7 @@ } this.providers = backend.getProviders(); this.suites = backend.getSuites().createSuites(); + installSubstitutions(); } @BeforeClass @@ -413,7 +425,12 @@ ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method); checkArgs(javaMethod, executeArgs); - InstalledCode compiledMethod = getCode(javaMethod, parse(method)); + InstalledCode compiledMethod = null; + if (UseBaselineCompiler.getValue()) { + compiledMethod = getCodeBaseline(javaMethod, method); + } else { + compiledMethod = getCode(javaMethod, parse(method)); + } try { return new Result(compiledMethod.executeVarargs(executeArgs), null); } catch (Throwable e) { @@ -423,6 +440,73 @@ } } + protected InstalledCode getCodeBaseline(ResolvedJavaMethod javaMethod, Method method) { + return getCodeBaseline(javaMethod, method, false); + } + + protected InstalledCode getCodeBaseline(ResolvedJavaMethod javaMethod, Method method, boolean forceCompile) { + assert method.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + method; + + try (Scope bds = Debug.scope("Baseline")) { + Debug.log("getCodeBaseline()"); + } catch (Throwable e) { + throw Debug.handle(e); + } + + if (!forceCompile) { + InstalledCode cached = cache.get(javaMethod); + if (cached != null) { + if (cached.isValid()) { + return cached; + } + } + } + + final int id = compilationId.incrementAndGet(); + + InstalledCode installedCode = null; + try (Scope ds = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) { + final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); + + if (printCompilation) { + TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s ...", id, javaMethod.getDeclaringClass().getName(), javaMethod.getName(), javaMethod.getSignature())); + } + long start = System.currentTimeMillis(); + + CompilationResult compResult = compileBaseline(javaMethod); + + if (printCompilation) { + TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize())); + } + + try (Scope s = Debug.scope("CodeInstall", getCodeCache(), javaMethod)) { + installedCode = addMethod(javaMethod, compResult); + if (installedCode == null) { + throw new GraalInternalError("Could not install code for " + MetaUtil.format("%H.%n(%p)", javaMethod)); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + + if (!forceCompile) { + cache.put(javaMethod, installedCode); + } + return installedCode; + } + + private CompilationResult compileBaseline(ResolvedJavaMethod javaMethod) { + try (Scope bds = Debug.scope("compileBaseline")) { + BaslineCompiler baselineCompiler = new BaslineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess()); + baselineCompiler.generate(javaMethod, -1); + return null; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + protected void checkArgs(ResolvedJavaMethod method, Object[] args) { JavaType[] sig = MetaUtil.signatureToTypes(method); Assert.assertEquals(sig.length, args.length); @@ -578,7 +662,11 @@ protected CompilationResult compile(ResolvedJavaMethod method, final StructuredGraph graph) { CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); return compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), - new SpeculationLog(), getSuites(), true, new CompilationResult(), CompilationResultBuilderFactory.Default); + getSpeculationLog(), getSuites(), true, new CompilationResult(), CompilationResultBuilderFactory.Default); + } + + protected SpeculationLog getSpeculationLog() { + return null; } protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compResult) { @@ -639,4 +727,27 @@ protected Replacements getReplacements() { return getProviders().getReplacements(); } + + /** + * Inject a probability for a branch condition into the profiling information of this test case. + * + * @param p the probability that cond is true + * @param cond the condition of the branch + * @return cond + */ + protected static boolean branchProbability(double p, boolean cond) { + return cond; + } + + /** + * Inject an iteration count for a loop condition into the profiling information of this test + * case. + * + * @param i the iteration count of the loop + * @param cond the condition of the loop + * @return cond + */ + protected static boolean iterationCount(double i, boolean cond) { + return cond; + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -63,7 +63,7 @@ final StructuredGraph graph = parse(method); CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), - OptimisticOptimizations.ALL, getProfilingInfo(graph), new SpeculationLog(), getSuites(), true, new CompilationResult(), CompilationResultBuilderFactory.Default); + OptimisticOptimizations.ALL, getProfilingInfo(graph), null, getSuites(), true, new CompilationResult(), CompilationResultBuilderFactory.Default); for (Infopoint sp : cr.getInfopoints()) { assertNotNull(sp.reason); if (sp instanceof Call) { @@ -86,7 +86,7 @@ CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); PhaseSuite graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerInfopointDefault()); final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, - getProfilingInfo(graph), new SpeculationLog(), getSuites(), true, new CompilationResult(), CompilationResultBuilderFactory.Default); + getProfilingInfo(graph), getSpeculationLog(), getSuites(), true, new CompilationResult(), CompilationResultBuilderFactory.Default); int lineSPs = 0; for (Infopoint sp : cr.getInfopoints()) { assertNotNull(sp.reason); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InjectProfileDataSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InjectProfileDataSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,40 @@ +/* + * 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.compiler.test; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.extended.*; + +@ClassSubstitution(GraalCompilerTest.class) +class InjectProfileDataSubstitutions { + + @MethodSubstitution + public static boolean branchProbability(double p, boolean cond) { + return BranchProbabilityNode.probability(p, cond); + } + + @MethodSubstitution + public static boolean iterationCount(double i, boolean cond) { + return BranchProbabilityNode.probability(1. - 1. / i, cond); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -323,7 +323,10 @@ } } - return javaMethod.getProfilingInfo(); + ProfilingInfo info = javaMethod.getProfilingInfo(); + // The execution counts are low so force maturity + info.setMature(); + return info; } private void resetProfile(String methodName) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ShortCircuitNodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ShortCircuitNodeTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.ea.EATestBase.TestClassInt; + +public class ShortCircuitNodeTest extends GraalCompilerTest { + + @Test + public void test1() { + // only executeActual, to avoid creating profiling information + executeActual(getMethod("test1Snippet"), 1, 2); + } + + public static final TestClassInt field = null; + public static TestClassInt field2 = null; + + @SuppressWarnings("unused") + public static void test1Snippet(int a, int b) { + /* + * if a ShortCircuitOrNode is created for the check inside test2, then faulty handling of + * guards can create a cycle in the graph. + */ + int v; + if (a == 1) { + if (b != 1) { + int i = field.x; + } + field2 = null; + v = 0; + } else { + v = 1; + } + + if (test2(v, b)) { + int i = field.x; + } + } + + public static boolean test2(int a, int b) { + return a != 0 || b != 1; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,52 +22,29 @@ */ package com.oracle.graal.compiler.test.deopt; -import java.lang.reflect.*; - import org.junit.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; +import com.oracle.graal.compiler.test.ea.EATestBase.TestClassObject; /** * In the following tests, we try to deoptimize out of synchronized methods. */ public class SynchronizedMethodDeoptimizationTest extends GraalCompilerTest { - public static final int N = 15000; + public static final TestClassObject testObject = null; public static synchronized Object testMethodSynchronized(Object o) { if (o == null) { - return null; + // this branch will always deoptimize + return testObject.x; } return o; } @Test public void test1() { - Method method = getMethod("testMethodSynchronized"); - String testString = "test"; - for (int i = 0; i < N; ++i) { - Assert.assertEquals(testString, testMethodSynchronized(testString)); - } - final StructuredGraph graph = parseProfiled(method); - final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method); - InstalledCode compiledMethod = getCode(javaMethod, graph); - try { - Object result = compiledMethod.executeVarargs(testString); - Assert.assertEquals(testString, result); - } catch (InvalidInstalledCodeException t) { - Assert.fail("method invalidated"); - } - - try { - Object result = compiledMethod.executeVarargs(new Object[]{null}); - Assert.assertEquals(null, result); - Assert.assertFalse(compiledMethod.isValid()); - } catch (InvalidInstalledCodeException t) { - Assert.fail("method invalidated"); - } + test("testMethodSynchronized", "test"); + test("testMethodSynchronized", (Object) null); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.schedule.*; @@ -158,6 +159,103 @@ } @Test + public void testMergeAllocationsInt() { + testEscapeAnalysis("testMergeAllocationsIntSnippet", Constant.forInt(1), false); + } + + public int testMergeAllocationsIntSnippet(int a) { + TestClassInt obj; + if (a < 0) { + obj = new TestClassInt(1, 2); + notInlineable(); + } else { + obj = new TestClassInt(1, 2); + notInlineable(); + } + return obj.x <= 3 ? 1 : 0; + } + + @Test + public void testMergeAllocationsObj() { + testEscapeAnalysis("testMergeAllocationsObjSnippet", Constant.forInt(1), false); + } + + public int testMergeAllocationsObjSnippet(int a) { + TestClassObject obj; + Integer one = 1; + Integer two = 2; + Integer three = 3; + if (a < 0) { + obj = new TestClassObject(one, two); + notInlineable(); + } else { + obj = new TestClassObject(one, three); + notInlineable(); + } + return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; + } + + @Test + public void testMergeAllocationsObjCirc() { + testEscapeAnalysis("testMergeAllocationsObjCircSnippet", Constant.forInt(1), false); + } + + public int testMergeAllocationsObjCircSnippet(int a) { + TestClassObject obj; + Integer one = 1; + Integer two = 2; + Integer three = 3; + if (a < 0) { + obj = new TestClassObject(one); + obj.y = obj; + obj.y = two; + notInlineable(); + } else { + obj = new TestClassObject(one); + obj.y = obj; + obj.y = three; + notInlineable(); + } + return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; + } + + static class MyException extends RuntimeException { + + private static final long serialVersionUID = 0L; + + protected Integer value; + + public MyException(Integer value) { + super((Throwable) null); + this.value = value; + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return null; + } + } + + @Test + public void testMergeAllocationsException() { + testEscapeAnalysis("testMergeAllocationsExceptionSnippet", Constant.forInt(1), false); + } + + public int testMergeAllocationsExceptionSnippet(int a) { + MyException obj; + Integer one = 1; + if (a < 0) { + obj = new MyException(one); + notInlineable(); + } else { + obj = new MyException(one); + notInlineable(); + } + return obj.value <= 3 ? 1 : 0; + } + + @Test public void testCheckCast() { testEscapeAnalysis("testCheckCastSnippet", Constant.forObject(TestClassObject.class), false); } @@ -181,7 +279,7 @@ @SuppressWarnings("unused") public static void testNewNodeSnippet() { - new IntegerAddNode(Kind.Int, null, null); + new IntegerAddNode(new IntegerStamp(32, false, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0xFFFFFFFF), null, null); } /** diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Mar 05 19:40:15 2014 -0800 @@ -138,6 +138,7 @@ public static T compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target, GraphCache cache, PhaseSuite graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, boolean withScope, T compilationResult, CompilationResultBuilderFactory factory) { + assert !graph.isFrozen(); try (Scope s0 = withScope ? Debug.scope("GraalCompiler", graph, providers.getCodeCache()) : null) { Assumptions assumptions = new Assumptions(OptAssumptions.getValue()); LIR lir = null; @@ -268,20 +269,33 @@ throw Debug.handle(e); } - try (Scope s = Debug.scope("Allocator")) { + try (Scope s = Debug.scope("Allocator", lirGen)) { if (backend.shouldAllocateRegisters()) { - new LinearScan(target, lir, lirGen, frameMap).allocate(); + new LinearScan(target, lir, frameMap).allocate(); } } catch (Throwable e) { throw Debug.handle(e); } + + try (Scope s = Debug.scope("ControlFlowOptimizations")) { + EdgeMoveOptimizer.optimize(lir); + ControlFlowOptimizer.optimize(lir); + if (lirGen.canEliminateRedundantMoves()) { + RedundantMoveElimination.optimize(lir, frameMap, lirGen.getGraph().method()); + } + NullCheckOptimizer.optimize(lir, target.implicitNullCheckLimit); + + Debug.dump(lir, "After control flow optimization"); + } catch (Throwable e) { + throw Debug.handle(e); + } return lirGen; } public static void emitCode(Backend backend, long[] leafGraphIds, Assumptions assumptions, LIRGenerator lirGen, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) { CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGen, compilationResult, factory); - backend.emitCode(crb, lirGen, installedCodeOwner); + backend.emitCode(crb, lirGen.lir, installedCodeOwner); crb.finish(); if (!assumptions.isEmpty()) { compilationResult.setAssumptions(assumptions); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Mar 05 19:40:15 2014 -0800 @@ -45,6 +45,7 @@ import com.oracle.graal.lir.LIRInstruction.StateProcedure; import com.oracle.graal.lir.LIRInstruction.ValueProcedure; import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.phases.util.*; @@ -58,7 +59,6 @@ final TargetDescription target; final LIR ir; - final LIRGenerator gen; final FrameMap frameMap; final RegisterAttributes[] registerAttributes; final Register[] registers; @@ -158,10 +158,9 @@ */ private final int firstVariableNumber; - public LinearScan(TargetDescription target, LIR ir, LIRGenerator gen, FrameMap frameMap) { + public LinearScan(TargetDescription target, LIR ir, FrameMap frameMap) { this.target = target; this.ir = ir; - this.gen = gen; this.frameMap = frameMap; this.sortedBlocks = ir.linearScanOrder(); this.registerAttributes = frameMap.registerConfig.getAttributesMap(); @@ -563,7 +562,7 @@ assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); assert isStackSlot(toLocation) : "to operand must be a stack slot"; - insertionBuffer.append(j + 1, ir.spillMoveFactory.createMove(toLocation, fromLocation)); + insertionBuffer.append(j + 1, frameMap.createSpillMove(toLocation, fromLocation)); Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId); } @@ -881,21 +880,54 @@ indent.outdent(); } + private static LIRGenerator getLIRGeneratorFromDebugContext() { + if (Debug.isEnabled()) { + LIRGenerator lirGen = Debug.contextLookup(LIRGenerator.class); + assert lirGen != null; + return lirGen; + } + return null; + } + + private static ValueNode getValueForOperandFromDebugContext(Value value) { + LIRGenerator gen = getLIRGeneratorFromDebugContext(); + if (gen != null) { + return gen.valueForOperand(value); + } + return null; + } + + private static StructuredGraph getGraphFromDebugContext() { + LIRGenerator gen = getLIRGeneratorFromDebugContext(); + if (gen != null) { + return gen.getGraph(); + } + return null; + } + + private static ResolvedJavaMethod getMethodFromDebugContext() { + StructuredGraph graph = getGraphFromDebugContext(); + if (graph != null) { + return graph.method(); + } + return null; + } + private void reportFailure(int numBlocks) { - Indent indent = Debug.logAndIndent("report failure, graph: %s", gen.getGraph()); + Indent indent = Debug.logAndIndent("report failure, graph: %s", getGraphFromDebugContext()); BitSet startBlockLiveIn = blockData.get(ir.cfg.getStartBlock()).liveIn; try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { Value operand = operandFor(operandNum); - Debug.log("var %d; operand=%s; node=%s", operandNum, operand, gen.valueForOperand(operand)); + Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand)); } } // print some additional information to simplify debugging for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { Value operand = operandFor(operandNum); - final Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, gen.valueForOperand(operand)); + final Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand)); Deque definedIn = new ArrayDeque<>(); HashSet usedIn = new HashSet<>(); @@ -1036,7 +1068,7 @@ // detection of method-parameters and roundfp-results interval.setSpillState(SpillState.StartInMemory); } - interval.addMaterializationValue(gen.getMaterializedValue(op, operand, interval)); + interval.addMaterializationValue(LinearScan.getMaterializedValue(op, operand, interval)); Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name()); } @@ -1839,7 +1871,7 @@ /* * This is the point to enable debug logging for the whole register allocation. */ - Indent indent = Debug.logAndIndent("LinearScan allocate %s", gen.getGraph().method()); + Indent indent = Debug.logAndIndent("LinearScan allocate %s", getMethodFromDebugContext()); try (Scope s = Debug.scope("LifetimeAnalysis")) { numberInstructions(); @@ -1887,16 +1919,7 @@ throw Debug.handle(e); } - try (Scope s = Debug.scope("ControlFlowOptimizations")) { - printLir("After register number assignment", true); - EdgeMoveOptimizer.optimize(ir); - ControlFlowOptimizer.optimize(ir); - RedundantMoveElimination.optimize(ir, frameMap, gen.getGraph().method()); - NullCheckOptimizer.optimize(ir, target.implicitNullCheckLimit); - printLir("After control flow optimization", false); - } catch (Throwable e) { - throw Debug.handle(e); - } + printLir("After register number assignment", true); indent.outdent(); } @@ -2102,4 +2125,38 @@ } } } + + /** + * Returns a value for a interval definition, which can be used for re-materialization. + * + * @param op An instruction which defines a value + * @param operand The destination operand of the instruction + * @param interval The interval for this defined value. + * @return Returns the value which is moved to the instruction and which can be reused at all + * reload-locations in case the interval of this instruction is spilled. Currently this + * can only be a {@link Constant}. + */ + public static Constant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) { + if (op instanceof MoveOp) { + MoveOp move = (MoveOp) op; + if (move.getInput() instanceof Constant) { + /* + * Check if the interval has any uses which would accept an stack location (priority + * == ShouldHaveRegister). Rematerialization of such intervals can result in a + * degradation, because rematerialization always inserts a constant load, even if + * the value is not needed in a register. + */ + Interval.UsePosList usePosList = interval.usePosList(); + int numUsePos = usePosList.size(); + for (int useIdx = 0; useIdx < numUsePos; useIdx++) { + Interval.RegisterPriority priority = usePosList.registerPriority(useIdx); + if (priority == Interval.RegisterPriority.ShouldHaveRegister) { + return null; + } + } + return (Constant) move.getInput(); + } + } + return null; + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Wed Mar 05 19:40:15 2014 -0800 @@ -202,7 +202,7 @@ AllocatableValue fromOpr = fromInterval.operand; AllocatableValue toOpr = toInterval.operand; - insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr)); + insertionBuffer.append(insertIdx, allocator.frameMap.createSpillMove(toOpr, fromOpr)); Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx); } @@ -212,7 +212,7 @@ assert insertIdx != -1 : "must setup insert position first"; AllocatableValue toOpr = toInterval.operand; - insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr)); + insertionBuffer.append(insertIdx, allocator.frameMap.createSpillMove(toOpr, fromOpr)); Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Wed Mar 05 19:40:15 2014 -0800 @@ -165,6 +165,11 @@ return toValue(state.lockAt(i)); } + private static final DebugMetric STATE_VIRTUAL_OBJECTS = Debug.metric("StateVirtualObjects"); + private static final DebugMetric STATE_ILLEGALS = Debug.metric("StateIllegals"); + private static final DebugMetric STATE_VARIABLES = Debug.metric("StateVariables"); + private static final DebugMetric STATE_CONSTANTS = Debug.metric("StateConstants"); + protected Value toValue(ValueNode value) { if (value instanceof VirtualObjectNode) { VirtualObjectNode obj = (VirtualObjectNode) value; @@ -182,22 +187,22 @@ vobject = VirtualObject.get(obj.type(), null, virtualObjects.size()); virtualObjects.put(obj, vobject); } - Debug.metric("StateVirtualObjects").increment(); + STATE_VIRTUAL_OBJECTS.increment(); return vobject; } } else if (value instanceof ConstantNode) { - Debug.metric("StateConstants").increment(); + STATE_CONSTANTS.increment(); return ((ConstantNode) value).getValue(); } else if (value != null) { - Debug.metric("StateVariables").increment(); + STATE_VARIABLES.increment(); Value operand = nodeOperands.get(value); assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value; return operand; } else { // return a dummy value because real value not needed - Debug.metric("StateIllegals").increment(); + STATE_ILLEGALS.increment(); return Value.ILLEGAL; } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -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.*; @@ -36,12 +35,14 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; -import com.oracle.graal.compiler.alloc.*; import com.oracle.graal.compiler.target.*; 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.NoOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; @@ -56,7 +57,7 @@ /** * This class traverses the HIR instructions and generates LIR instructions from them. */ -public abstract class LIRGenerator implements LIRGeneratorTool { +public abstract class LIRGenerator implements LIRGeneratorTool, LIRTypeTool { public static class Options { // @formatter:off @@ -174,13 +175,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); @@ -189,37 +184,11 @@ } /** - * Returns a value for a interval definition, which can be used for re-materialization. - * - * @param op An instruction which defines a value - * @param operand The destination operand of the instruction - * @param interval The interval for this defined value. - * @return Returns the value which is moved to the instruction and which can be reused at all - * reload-locations in case the interval of this instruction is spilled. Currently this - * can only be a {@link Constant}. + * Returns true if the redundant move elimination optimization should be done after register + * allocation. */ - public Constant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) { - if (op instanceof MoveOp) { - MoveOp move = (MoveOp) op; - if (move.getInput() instanceof Constant) { - /* - * Check if the interval has any uses which would accept an stack location (priority - * == ShouldHaveRegister). Rematerialization of such intervals can result in a - * degradation, because rematerialization always inserts a constant load, even if - * the value is not needed in a register. - */ - Interval.UsePosList usePosList = interval.usePosList(); - int numUsePos = usePosList.size(); - for (int useIdx = 0; useIdx < numUsePos; useIdx++) { - Interval.RegisterPriority priority = usePosList.registerPriority(useIdx); - if (priority == Interval.RegisterPriority.ShouldHaveRegister) { - return null; - } - } - return (Constant) move.getInput(); - } - } - return null; + public boolean canEliminateRedundantMoves() { + return true; } @SuppressWarnings("hiding") @@ -333,13 +302,7 @@ */ @Override public Variable newVariable(PlatformKind platformKind) { - PlatformKind stackKind; - if (platformKind instanceof Kind) { - stackKind = ((Kind) platformKind).getStackKind(); - } else { - stackKind = platformKind; - } - return new Variable(stackKind, lir.nextVariable()); + return new Variable(platformKind, lir.nextVariable()); } @Override @@ -655,37 +618,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 +678,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 +810,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]; @@ -1016,6 +976,36 @@ } } + /** + * Default implementation: Return the Java stack kind for each stamp. + */ + public PlatformKind getPlatformKind(Stamp stamp) { + return stamp.getPlatformKind(this); + } + + public PlatformKind getIntegerKind(int bits, boolean unsigned) { + if (bits > 32) { + return Kind.Long; + } else { + return Kind.Int; + } + } + + public PlatformKind getFloatingKind(int bits) { + switch (bits) { + case 32: + return Kind.Float; + case 64: + return Kind.Double; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + public PlatformKind getObjectKind() { + return Kind.Object; + } + public abstract void emitBitCount(Variable result, Value operand); public abstract void emitBitScanForward(Variable result, Value operand); @@ -1024,5 +1014,5 @@ public abstract void emitByteSwap(Variable result, Value operand); - public abstract void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length); + public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Wed Mar 05 19:40:15 2014 -0800 @@ -70,7 +70,7 @@ /** * Creates the assembler used to emit the machine code. */ - protected abstract AbstractAssembler createAssembler(FrameMap frameMap); + protected abstract Assembler createAssembler(FrameMap frameMap); /** * Creates the object used to fill in the details of a given compilation result. @@ -86,5 +86,5 @@ * {@linkplain InstalledCode#getMethod() associated} with once installed. This * argument can be null. */ - public abstract void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner); + public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/HostBackend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/HostBackend.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,32 @@ +/* + * 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.compiler.target; + +import com.oracle.graal.api.code.*; + +/** + * Common functionality of host backends. + */ +public interface HostBackend { + NativeFunctionInterface getNativeFunctionInterface(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Wed Mar 05 19:40:15 2014 -0800 @@ -87,10 +87,10 @@ } } - private static ThreadLocal instanceTL = new ThreadLocal<>(); - private static ThreadLocal lastClosedTL = new ThreadLocal<>(); - private static ThreadLocal configTL = new ThreadLocal<>(); - private static ThreadLocal lastExceptionThrownTL = new ThreadLocal<>(); + private static final ThreadLocal instanceTL = new ThreadLocal<>(); + private static final ThreadLocal lastClosedTL = new ThreadLocal<>(); + private static final ThreadLocal configTL = new ThreadLocal<>(); + private static final ThreadLocal lastExceptionThrownTL = new ThreadLocal<>(); private final DebugScope parent; private final DebugConfig parentConfig; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java Wed Mar 05 19:40:15 2014 -0800 @@ -41,7 +41,7 @@ /** * Records the most recent active timer. */ - private static ThreadLocal currentTimer = new ThreadLocal<>(); + private static final ThreadLocal currentTimer = new ThreadLocal<>(); private final DebugValue flat; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Wed Mar 05 19:40:15 2014 -0800 @@ -75,6 +75,12 @@ NodeChangedListener usagesDroppedToZeroListener; private final HashMap cachedNodes = new HashMap<>(); + /* + * Indicates that the graph should no longer be modified. Frozen graphs can be used my multiple + * threads so it's only safe to read them. + */ + private boolean isFrozen = false; + private static final class CacheEntry { private final Node node; @@ -761,6 +767,7 @@ } void register(Node node) { + assert !isFrozen(); assert node.id() == Node.INITIAL_ID; if (nodes.length == nodesSize) { nodes = Arrays.copyOf(nodes, (nodesSize * 2) + 1); @@ -812,6 +819,7 @@ } void unregister(Node node) { + assert !isFrozen(); assert !node.isDeleted() : "cannot delete a node twice! node=" + node; logNodeDeleted(node); nodes[node.id] = null; @@ -896,4 +904,12 @@ public Map addDuplicates(Iterable newNodes, final Graph oldGraph, int estimatedNodeCount, DuplicationReplacement replacements) { return NodeClass.addGraphDuplicate(this, oldGraph, estimatedNodeCount, newNodes, replacements); } + + public boolean isFrozen() { + return isFrozen; + } + + public void freeze() { + this.isFrozen = true; + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Wed Mar 05 19:40:15 2014 -0800 @@ -467,17 +467,11 @@ } if (newInput != null) { if (newInput.recordsUsages()) { - NodeChangedListener listener = graph.inputChangedListener; - if (listener != null) { - listener.nodeChanged(this); - } + maybeNotifyChanged(this); newInput.addUsage(this); } } else if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) { - NodeChangedListener listener = graph.usagesDroppedToZeroListener; - if (listener != null) { - listener.nodeChanged(oldInput); - } + maybeNotifyZeroInputs(oldInput); } } } @@ -488,6 +482,7 @@ * this node to newSuccessor's predecessors. */ protected void updatePredecessor(Node oldSuccessor, Node newSuccessor) { + assert graph == null || !graph.isFrozen(); if (oldSuccessor != newSuccessor) { if (oldSuccessor != null) { assert assertTrue(oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s", oldSuccessor, oldSuccessor.predecessor); @@ -517,6 +512,7 @@ } private boolean checkReplaceWith(Node other) { + assert assertTrue(graph == null || !graph.isFrozen(), "cannot modify frozen graph"); assert assertFalse(other == this, "cannot replace a node with itself"); assert assertFalse(isDeleted(), "cannot replace deleted node"); assert assertTrue(other == null || !other.isDeleted(), "cannot replace with deleted node %s", other); @@ -529,10 +525,7 @@ boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); assert assertTrue(result, "not found in inputs, usage: %s", usage); if (other != null) { - NodeChangedListener listener = graph.inputChangedListener; - if (listener != null) { - listener.nodeChanged(usage); - } + maybeNotifyChanged(usage); if (other.recordsUsages()) { other.addUsage(usage); } @@ -541,6 +534,22 @@ clearUsages(); } + private void maybeNotifyChanged(Node usage) { + assert graph == null || !graph.isFrozen(); + NodeChangedListener listener = graph.inputChangedListener; + if (listener != null) { + listener.nodeChanged(usage); + } + } + + private void maybeNotifyZeroInputs(Node oldInput) { + assert graph == null || !graph.isFrozen(); + NodeChangedListener listener = graph.usagesDroppedToZeroListener; + if (listener != null) { + listener.nodeChanged(oldInput); + } + } + public void replaceAtPredecessor(Node other) { assert checkReplaceWith(other); if (predecessor != null) { @@ -579,10 +588,7 @@ if (input.recordsUsages()) { removeThisFromUsages(input); if (input.usages().isEmpty()) { - NodeChangedListener listener = graph.usagesDroppedToZeroListener; - if (listener != null) { - listener.nodeChanged(input); - } + maybeNotifyZeroInputs(input); } } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Wed Mar 05 19:40:15 2014 -0800 @@ -101,7 +101,7 @@ if (autogrow && isNew(node)) { grow(); } - assert node.graph() == graph : "this node is not part of the graph"; + assert node.graph() == graph : String.format("%s is not part of the graph", node); assert !isNew(node) : "this node was added to the graph after creating the node map : " + node; } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/UnsafeAccess.java Wed Mar 05 19:40:15 2014 -0800 @@ -49,4 +49,54 @@ 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)); + } + + /** + * Reads a {@code '\0'} terminated C string from native memory and converts it to a + * {@link String}. + * + * @return a Java string + */ + public static String readCString(long address) { + if (address == 0) { + return null; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0;; i++) { + char c = (char) unsafe.getByte(address + i); + if (c == 0) { + break; + } + sb.append(c); + } + return sb.toString(); + } + + /** + * 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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java --- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -48,6 +48,7 @@ return; } + @Ignore @Test public void test1() { testHelper("test1snippet", new CodeGenerator() { @@ -64,6 +65,7 @@ return x + 5; } + @Ignore @Test public void test2() { testHelper("test2snippet", new CodeGenerator() { @@ -83,6 +85,7 @@ return 1 + x; } + @Ignore @Test public void test3() { testHelper("test3snippet", new CodeGenerator() { @@ -108,7 +111,7 @@ AMD64Assembler asm = new AMD64Assembler(target, registerConfig); gen.generateCode(asm); - byte[] expectedCode = asm.codeBuffer.close(true); + byte[] expectedCode = asm.close(true); // Only compare up to expectedCode.length bytes to ignore // padding instructions adding during code installation diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Wed Mar 05 19:40:15 2014 -0800 @@ -43,6 +43,7 @@ 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.*; @@ -97,9 +98,9 @@ disp -= frameSize; } crb.blockComment("[stack overflow check]"); - int pos = asm.codeBuffer.position(); + int pos = asm.position(); asm.movq(new AMD64Address(rsp, -disp), AMD64.rax); - assert i > 0 || !isVerifiedEntryPoint || asm.codeBuffer.position() - pos >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; + assert i > 0 || !isVerifiedEntryPoint || asm.position() - pos >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; } } } @@ -140,14 +141,14 @@ asm.nop(PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE); } } else { - int verifiedEntryPointOffset = asm.codeBuffer.position(); + int verifiedEntryPointOffset = asm.position(); if (!isStub && pagesToBang > 0) { emitStackOverflowCheck(crb, pagesToBang, false, true); - assert asm.codeBuffer.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; + assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; } - if (!isStub && asm.codeBuffer.position() == verifiedEntryPointOffset) { + if (!isStub && asm.position() == verifiedEntryPointOffset) { asm.subqWide(rsp, frameSize); - assert asm.codeBuffer.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; + assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; } else { asm.decrementq(rsp, frameSize); } @@ -173,7 +174,7 @@ CalleeSaveLayout csl = crb.frameMap.registerConfig.getCalleeSaveLayout(); if (csl != null && csl.size != 0) { - crb.compilationResult.setRegisterRestoreEpilogueOffset(asm.codeBuffer.position()); + crb.compilationResult.setRegisterRestoreEpilogueOffset(asm.position()); // saved all registers, restore all registers int frameToCSA = crb.frameMap.offsetToCalleeSaveArea(); asm.restore(csl, frameToCSA); @@ -186,7 +187,7 @@ } @Override - protected AbstractAssembler createAssembler(FrameMap frameMap) { + protected Assembler createAssembler(FrameMap frameMap) { return new AMD64MacroAssembler(getTarget(), frameMap.registerConfig); } @@ -205,7 +206,7 @@ boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall(); Stub stub = gen.getStub(); - AbstractAssembler masm = createAssembler(frameMap); + Assembler masm = createAssembler(frameMap); HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null, omitFrame); CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult); crb.setFrameSize(frameMap.frameSize()); @@ -223,7 +224,7 @@ } @Override - public void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner) { + public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; FrameMap frameMap = crb.frameMap; RegisterConfig regConfig = frameMap.registerConfig; @@ -234,10 +235,10 @@ emitCodePrefix(installedCodeOwner, crb, asm, regConfig, config, verifiedEntry); // Emit code for the LIR - emitCodeBody(installedCodeOwner, crb, lirGen); + emitCodeBody(installedCodeOwner, crb, lir); // Emit the suffix - emitCodeSuffix(installedCodeOwner, crb, lirGen, asm, frameMap); + emitCodeSuffix(installedCodeOwner, crb, asm, frameMap); } /** @@ -280,14 +281,14 @@ * * @param installedCodeOwner see {@link Backend#emitCode} */ - public void emitCodeBody(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, LIRGenerator lirGen) { - crb.emit(lirGen.lir); + public void emitCodeBody(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, LIR lir) { + crb.emit(lir); } /** * @param installedCodeOwner see {@link Backend#emitCode} */ - public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, LIRGenerator lirGen, AMD64MacroAssembler asm, FrameMap frameMap) { + public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, FrameMap frameMap) { HotSpotProviders providers = getProviders(); HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; if (!frameContext.isStub) { @@ -299,7 +300,22 @@ } else { // No need to emit the stubs for entries back into the method since // it has no calls that can cause such "return" entries - assert !frameMap.accessesCallerFrame() : lirGen.getGraph(); + + if (frameContext.omitFrame) { + // Cannot access slots in caller's frame if my frame is omitted + assert !frameMap.accessesCallerFrame(); + } } } + + @Override + public NativeFunctionInterface getNativeFunctionInterface() { + 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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -67,8 +67,8 @@ // replace a non-existing method anyway. try { // These stubs do callee saving - registerForeignCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION); - registerForeignCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION); + registerForeignCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte)); + registerForeignCall(DECRYPT_BLOCK, config.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte)); } catch (GraalInternalError e) { if (!(e.getCause() instanceof ClassNotFoundException)) { throw e; @@ -76,8 +76,8 @@ } try { // These stubs do callee saving - registerForeignCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION); - registerForeignCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION); + registerForeignCall(ENCRYPT, config.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte)); + registerForeignCall(DECRYPT, config.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte)); } catch (GraalInternalError e) { if (!(e.getCause() instanceof ClassNotFoundException)) { throw e; diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -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); @@ -350,6 +349,24 @@ } @Override + public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) { + Value[] argLocations = new Value[args.length]; + frameMap.callsMethod(nativeCallingConvention); + // TODO(mg): in case a native function uses floating point varargs, the ABI requires that + // RAX contains the length of the varargs + AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue(); + emitMove(numberOfFloatingPointArgumentsRegister, Constant.forInt(numberOfFloatingPointArguments)); + for (int i = 0; i < args.length; i++) { + Value arg = args[i]; + AllocatableValue loc = nativeCallingConvention.getArgument(i); + emitMove(loc, arg); + argLocations[i] = loc; + } + Value ptr = emitMove(Constant.forLong(address)); + append(new AMD64CCall(nativeCallingConvention.getReturn(), ptr, numberOfFloatingPointArgumentsRegister, argLocations)); + } + + @Override protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { @@ -467,7 +484,7 @@ @Override public Variable emitLoad(Kind kind, Value address, Access access) { AMD64AddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(kind); + Variable result = newVariable(kind.getStackKind()); LIRFrameState state = null; if (access instanceof DeoptimizingNode) { state = state((DeoptimizingNode) access); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLoweringProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -47,8 +47,8 @@ @Override public void lower(Node n, LoweringTool tool) { - if (n instanceof ConvertNode) { - convertSnippets.lower((ConvertNode) n, tool); + if (n instanceof FloatConvertNode) { + convertSnippets.lower((FloatConvertNode) n, tool); } else { super.lower(n, tool); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java Wed Mar 05 19:40:15 2014 -0800 @@ -133,12 +133,12 @@ encodeKlassPointer(masm, asRegister(scratch), heapBaseReg, encoding); } if (state != null) { - crb.recordImplicitException(masm.codeBuffer.position(), state); + crb.recordImplicitException(masm.position(), state); } masm.movl(address.toAddress(), asRegister(scratch)); } if (state != null) { - crb.recordImplicitException(masm.codeBuffer.position(), state); + crb.recordImplicitException(masm.position(), state); } masm.movl(address.toAddress(), asRegister(scratch)); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Wed Mar 05 19:40:15 2014 -0800 @@ -216,7 +216,7 @@ } Kind returnKind = returnType == null ? Kind.Void : returnType.getKind(); - AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind); + AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(returnKind.getStackKind()); return new CallingConvention(currentStackOffset, returnLocation, locations); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,7 +24,6 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import static com.oracle.graal.phases.GraalOptions.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -51,7 +50,8 @@ @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { leaveFrameAndRestoreRbp(crb, masm); - if (!isStub && (crb.frameContext.hasFrame() || !OptEliminateSafepoints.getValue())) { + if (!isStub) { + // Every non-stub compile method must have a poll before the return. AMD64HotSpotSafepointOp.emitCode(crb, masm, runtime().getConfig(), true, null, scratchForSafepointOnReturn); } masm.ret(0); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -73,6 +73,7 @@ } public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm, HotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) { + assert !atReturn || state == null : "state is unneeded at return"; if (ImmutableCode.getValue()) { Kind hostWordKind = HotSpotGraalRuntime.getHostWordKind(); int alignment = hostWordKind.getBitCount() / Byte.SIZE; @@ -80,7 +81,7 @@ // This move will be patched to load the safepoint page from a data segment // co-located with the immutable code. asm.movq(scratch, (AMD64Address) crb.recordDataReferenceInCode(pollingPageAddress, alignment)); - final int pos = asm.codeBuffer.position(); + final int pos = asm.position(); crb.recordMark(atReturn ? MARK_POLL_RETURN_FAR : MARK_POLL_FAR); if (state != null) { crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); @@ -89,14 +90,14 @@ } else if (isPollingPageFar(config)) { asm.movq(scratch, config.safepointPollingAddress); crb.recordMark(atReturn ? MARK_POLL_RETURN_FAR : MARK_POLL_FAR); - final int pos = asm.codeBuffer.position(); + final int pos = asm.position(); if (state != null) { crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); } asm.testl(rax, new AMD64Address(scratch)); } else { crb.recordMark(atReturn ? MARK_POLL_RETURN_NEAR : MARK_POLL_NEAR); - final int pos = asm.codeBuffer.position(); + final int pos = asm.position(); if (state != null) { crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64PrefetchOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64PrefetchOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64PrefetchOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,7 +32,7 @@ public class AMD64PrefetchOp extends AMD64LIRInstruction { - private final int instr; // AllocatePrefecthInstr + private final int instr; // AllocatePrefetchInstr @Alive({COMPOSITE}) protected AMD64AddressValue address; public AMD64PrefetchOp(AMD64AddressValue address, int instr) { diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/ForEachToGraal.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,10 +23,25 @@ package com.oracle.graal.hotspot.hsail; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import java.lang.reflect.*; + import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.hsail.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; +import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.iterators.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hsail.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.printer.*; /** * Implements compile and dispatch of Java code containing lambda constructs. Currently only used by @@ -34,18 +49,58 @@ */ public class ForEachToGraal implements CompileAndDispatch { - private static HSAILCompilationResult getCompiledLambda(Class consumerClass) { - return HSAILCompilationResult.getCompiledLambda(consumerClass); + private static HSAILHotSpotBackend getHSAILBackend() { + Backend backend = runtime().getBackend(HSAIL.class); + return (HSAILHotSpotBackend) backend; } - // Implementations of the CompileAndDispatch interface. + /** + * Gets a compiled and installed kernel for the lambda called by the {@code accept(int value)} + * method in a class implementing {@code java.util.function.IntConsumer}. + * + * @param intConsumerClass a class implementing {@code java.util.function.IntConsumer} + * @return a {@link HotSpotNmethod} handle to the compiled and installed kernel + */ + private static HotSpotNmethod getCompiledLambda(Class intConsumerClass) { + Method acceptMethod = null; + for (Method m : intConsumerClass.getMethods()) { + if (m.getName().equals("accept")) { + assert acceptMethod == null : "found more than one implementation of accept(int) in " + intConsumerClass; + acceptMethod = m; + } + } + + // Ensure a debug configuration for this thread is initialized + if (DebugScope.getConfig() == null) { + DebugEnvironment.initialize(System.out); + } + + HSAILHotSpotBackend backend = getHSAILBackend(); + Providers providers = backend.getProviders(); + StructuredGraph graph = new StructuredGraph(((HotSpotMetaAccessProvider) providers.getMetaAccess()).lookupJavaMethod(acceptMethod)); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL).apply(graph); + NodeIterable calls = graph.getNodes(MethodCallTargetNode.class); + assert calls.count() == 1; + ResolvedJavaMethod lambdaMethod = calls.first().targetMethod(); + assert lambdaMethod.getName().startsWith("lambda$"); + Debug.log("target ... " + lambdaMethod); + + if (lambdaMethod == null) { + Debug.log("Did not find call in accept()"); + return null; + } + + ExternalCompilationResult hsailCode = backend.compileKernel(lambdaMethod, true); + return backend.installKernel(lambdaMethod, hsailCode); + } + @Override public Object createKernel(Class consumerClass) { try { return getCompiledLambda(consumerClass); } catch (Throwable e) { - // Note: Graal throws Errors. We want to revert to regular Java in these cases. - Debug.log("WARNING:Graal compilation failed."); + // If Graal compilation throws an exception, we want to revert to regular Java + Debug.log("WARNING: Graal compilation failed"); e.printStackTrace(); return null; } @@ -53,16 +108,14 @@ @Override public boolean dispatchKernel(Object kernel, int jobSize, Object[] args) { - // kernel is an HSAILCompilationResult - HotSpotNmethod code = (HotSpotNmethod) ((HSAILCompilationResult) kernel).getInstalledCode(); - + HotSpotNmethod code = (HotSpotNmethod) kernel; if (code != null) { try { // No return value from HSAIL kernels - code.executeParallel(jobSize, 0, 0, args); + getHSAILBackend().executeKernel(code, jobSize, args); return true; } catch (InvalidInstalledCodeException iice) { - Debug.log("WARNING:Invalid installed code at exec time." + iice); + Debug.log("WARNING: Invalid installed code at exec time." + iice); iice.printStackTrace(); return false; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILCompilationResult.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILCompilationResult.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * 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.hotspot.hsail; - -import static com.oracle.graal.compiler.GraalCompiler.*; -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; - -import java.lang.reflect.*; - -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.runtime.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.bridge.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hsail.*; -import com.oracle.graal.java.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.runtime.*; - -/** - * Class that represents a HSAIL compilation result. Includes the compiled HSAIL code. - */ -public class HSAILCompilationResult extends ExternalCompilationResult { - - private static final long serialVersionUID = -4178700465275724625L; - - private static CompilerToGPU toGPU = HotSpotGraalRuntime.runtime().getCompilerToGPU(); - private static boolean validDevice = toGPU.deviceInit(); - - // The installedCode is the executable representation of the kernel in the code cache - private InstalledCode installedCode; - - public void setInstalledCode(InstalledCode newCode) { - installedCode = newCode; - } - - public InstalledCode getInstalledCode() { - return installedCode; - } - - static final HSAILHotSpotBackend backend; - static { - // Look for installed HSAIL backend - RuntimeProvider runtime = Graal.getRequiredCapability(RuntimeProvider.class); - HSAILHotSpotBackend b = (HSAILHotSpotBackend) runtime.getBackend(HSAIL.class); - if (b == null) { - // Fall back to a new instance - b = new HSAILHotSpotBackendFactory().createBackend(runtime(), runtime().getHostBackend()); - b.completeInitialization(); - } - backend = b; - } - - public static HSAILCompilationResult getHSAILCompilationResult(Method meth) { - HotSpotMetaAccessProvider metaAccess = backend.getProviders().getMetaAccess(); - ResolvedJavaMethod javaMethod = metaAccess.lookupJavaMethod(meth); - return getHSAILCompilationResult(javaMethod); - } - - public static HSAILCompilationResult getHSAILCompilationResult(ResolvedJavaMethod javaMethod) { - HotSpotMetaAccessProvider metaAccess = backend.getProviders().getMetaAccess(); - StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); - return getHSAILCompilationResult(graph); - } - - /** - * HSAIL doesn't have a calling convention as such. Function arguments are actually passed in - * memory but then loaded into registers in the function body. This routine makes sure that - * arguments to a kernel or function are loaded (by the kernel or function body) into registers - * of the appropriate sizes. For example, int and float parameters should appear in S registers, - * whereas double and long parameters should appear in d registers. - */ - public static CallingConvention getHSAILCallingConvention(CallingConvention.Type type, TargetDescription target, ResolvedJavaMethod method, boolean stackOnly) { - Signature sig = method.getSignature(); - JavaType retType = sig.getReturnType(null); - int sigCount = sig.getParameterCount(false); - JavaType[] argTypes; - int argIndex = 0; - if (!Modifier.isStatic(method.getModifiers())) { - argTypes = new JavaType[sigCount + 1]; - argTypes[argIndex++] = method.getDeclaringClass(); - } else { - argTypes = new JavaType[sigCount]; - } - for (int i = 0; i < sigCount; i++) { - argTypes[argIndex++] = sig.getParameterType(i, null); - } - - RegisterConfig registerConfig = backend.getProviders().getCodeCache().getRegisterConfig(); - return registerConfig.getCallingConvention(type, retType, argTypes, target, stackOnly); - } - - public static HSAILCompilationResult getCompiledLambda(Class consumerClass) { - /** - * Find the accept() method in the IntConsumer, then use Graal API to find the target lambda - * that accept will call. - */ - Method[] icMethods = consumerClass.getMethods(); - Method acceptMethod = null; - for (Method m : icMethods) { - if (m.getName().equals("accept") && acceptMethod == null) { - acceptMethod = m; - break; - } - } - - Providers providers = backend.getProviders(); - HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) providers.getMetaAccess(); - ResolvedJavaMethod rm = metaAccess.lookupJavaMethod(acceptMethod); - StructuredGraph graph = new StructuredGraph(rm); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL).apply(graph); - NodeIterable nin = graph.getNodes(); - ResolvedJavaMethod lambdaMethod = null; - for (Node n : nin) { - if (n instanceof MethodCallTargetNode) { - lambdaMethod = ((MethodCallTargetNode) n).targetMethod(); - Debug.log("target ... " + lambdaMethod); - break; - } - } - if (lambdaMethod == null) { - // Did not find call in Consumer.accept. - Debug.log("Should not Reach here, did not find call in accept()"); - return null; - } - // Now that we have the target lambda, compile it. - HSAILCompilationResult hsailCompResult = HSAILCompilationResult.getHSAILCompilationResult(lambdaMethod); - return hsailCompResult; - } - - public static HSAILCompilationResult getHSAILCompilationResult(StructuredGraph graph) { - Debug.dump(graph, "Graph"); - Providers providers = backend.getProviders(); - TargetDescription target = providers.getCodeCache().getTarget(); - PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); - graphBuilderSuite.appendPhase(new HSAILPhase()); - new HSAILPhase().apply(graph); - CallingConvention cc = getHSAILCallingConvention(Type.JavaCallee, target, graph.method(), false); - SuitesProvider suitesProvider = backend.getSuites(); - try { - HSAILCompilationResult compResult = compileGraph(graph, cc, graph.method(), providers, backend, target, null, graphBuilderSuite, OptimisticOptimizations.NONE, getProfilingInfo(graph), - new SpeculationLog(), suitesProvider.getDefaultSuites(), true, new HSAILCompilationResult(), CompilationResultBuilderFactory.Default); - if ((validDevice) && (compResult.getTargetCode() != null)) { - long kernel = toGPU.generateKernel(compResult.getTargetCode(), graph.method().getName()); - - if (kernel == 0) { - throw new GraalInternalError("Failed to compile kernel."); - } - - ((ExternalCompilationResult) compResult).setEntryPoint(kernel); - HotSpotResolvedJavaMethod compiledMethod = (HotSpotResolvedJavaMethod) graph.method(); - InstalledCode installedCode = ((HotSpotCodeCacheProvider) providers.getCodeCache()).addExternalMethod(compiledMethod, compResult); - compResult.setInstalledCode(installedCode); - } - return compResult; - } catch (InvalidInstalledCodeException e) { - e.printStackTrace(); - return null; - } catch (GraalInternalError e) { - String partialCode = backend.getPartialCodeString(); - if (partialCode != null && !partialCode.equals("")) { - Debug.log("-------------------\nPartial Code Generation:\n--------------------"); - Debug.log(partialCode); - Debug.log("-------------------\nEnd of Partial Code Generation\n--------------------"); - } - throw e; - } - } - - private static class HSAILPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - for (ParameterNode param : graph.getNodes(ParameterNode.class)) { - if (param.stamp() instanceof ObjectStamp) { - param.setStamp(StampFactory.declaredNonNull(((ObjectStamp) param.stamp()).type())); - } - } - } - } - - protected HSAILCompilationResult() { - } - - public String getHSAILCode() { - return new String(getTargetCode(), 0, getTargetCodeSize()); - } - -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,26 +23,34 @@ package com.oracle.graal.hotspot.hsail; import static com.oracle.graal.api.code.CallingConvention.Type.*; +import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.compiler.GraalCompiler.*; import java.lang.reflect.*; import java.util.*; +import com.amd.okra.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.hsail.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hsail.*; +import com.oracle.graal.java.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.hsail.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.Replacements; -import com.oracle.graal.replacements.hsail.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; /** * HSAIL specific backend. @@ -50,7 +58,7 @@ public class HSAILHotSpotBackend extends HotSpotBackend { private Map paramTypeMap = new HashMap<>(); - private Buffer codeBuffer; + private final boolean deviceInitialized; public HSAILHotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) { super(runtime, providers); @@ -58,6 +66,10 @@ paramTypeMap.put("HotSpotResolvedPrimitiveType", "f32"); paramTypeMap.put("HotSpotResolvedPrimitiveType", "f64"); paramTypeMap.put("HotSpotResolvedPrimitiveType", "s64"); + + // The order of the conjunction below is important: the OkraUtil + // call may provision the native library required by the initialize() call + deviceInitialized = OkraUtil.okraLibExists() && initialize(); } @Override @@ -66,6 +78,20 @@ } /** + * Initializes the GPU device. + * + * @return whether or not initialization was successful + */ + private static native boolean initialize(); + + /** + * Determines if the GPU device (or simulator) is available and initialized. + */ + public boolean isDeviceInitialized() { + return deviceInitialized; + } + + /** * Completes the initialization of the HSAIL backend. This includes initializing the providers * and registering any method substitutions specified by the HSAIL backend. */ @@ -78,13 +104,82 @@ lowerer.initialize(providers, config); // Register the replacements used by the HSAIL backend. - Replacements replacements = providers.getReplacements(); + HSAILHotSpotReplacementsImpl replacements = (HSAILHotSpotReplacementsImpl) providers.getReplacements(); + replacements.completeInitialization(); + } + + /** + * Compiles and installs a given method to a GPU binary. + */ + public HotSpotNmethod compileAndInstallKernel(Method method) { + ResolvedJavaMethod javaMethod = getProviders().getMetaAccess().lookupJavaMethod(method); + return installKernel(javaMethod, compileKernel(javaMethod, true)); + } + + /** + * Compiles a given method to HSAIL code. + * + * @param makeBinary specifies whether a GPU binary should also be generated for the HSAIL code. + * If true, the returned value is guaranteed to have a non-zero + * {@linkplain ExternalCompilationResult#getEntryPoint() entry point}. + * @return the HSAIL code compiled from {@code method}'s bytecode + */ + public ExternalCompilationResult compileKernel(ResolvedJavaMethod method, boolean makeBinary) { + StructuredGraph graph = new StructuredGraph(method); + HotSpotProviders providers = getProviders(); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + PhaseSuite graphBuilderSuite = providers.getSuites().getDefaultGraphBuilderSuite(); + graphBuilderSuite.appendPhase(new NonNullParametersPhase()); + CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); + Suites suites = providers.getSuites().getDefaultSuites(); + ExternalCompilationResult hsailCode = compileGraph(graph, cc, method, providers, this, this.getTarget(), null, graphBuilderSuite, OptimisticOptimizations.NONE, getProfilingInfo(graph), null, + suites, true, new ExternalCompilationResult(), CompilationResultBuilderFactory.Default); - // Register the substitutions for java.lang.Math routines. - replacements.registerSubstitutions(HSAILMathSubstitutions.class); + if (makeBinary) { + if (!deviceInitialized) { + throw new GraalInternalError("Cannot generate GPU kernel if device is not initialized"); + } + try (Scope ds = Debug.scope("GeneratingKernelBinary")) { + long kernel = generateKernel(hsailCode.getTargetCode(), method.getName()); + if (kernel == 0) { + throw new GraalInternalError("Failed to compile HSAIL kernel"); + } + hsailCode.setEntryPoint(kernel); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + return hsailCode; } /** + * Generates a GPU binary from HSAIL code. + */ + private static native long generateKernel(byte[] hsailCode, String name); + + /** + * Installs the {@linkplain ExternalCompilationResult#getEntryPoint() GPU binary} associated + * with some given HSAIL code in the code cache and returns a {@link HotSpotNmethod} handle to + * the installed code. + * + * @param hsailCode HSAIL compilation result for which a GPU binary has been generated + * @return a handle to the binary as installed in the HotSpot code cache + */ + public final HotSpotNmethod installKernel(ResolvedJavaMethod method, ExternalCompilationResult hsailCode) { + assert hsailCode.getEntryPoint() != 0L; + return getProviders().getCodeCache().addExternalMethod(method, hsailCode); + } + + public boolean executeKernel(HotSpotInstalledCode kernel, int jobSize, Object[] args) throws InvalidInstalledCodeException { + if (!deviceInitialized) { + throw new GraalInternalError("Cannot execute GPU kernel if device is not initialized"); + } + return executeKernel0(kernel, jobSize, args); + } + + private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args) throws InvalidInstalledCodeException; + + /** * Use the HSAIL register set when the compilation target is HSAIL. */ @Override @@ -97,14 +192,6 @@ return new HSAILHotSpotLIRGenerator(graph, getProviders(), getRuntime().getConfig(), frameMap, cc, lir); } - public String getPartialCodeString() { - if (codeBuffer == null) { - return ""; - } - byte[] data = codeBuffer.copyData(0, codeBuffer.position()); - return (data == null ? "" : new String(data)); - } - class HotSpotFrameContext implements FrameContext { public boolean hasFrame() { @@ -123,14 +210,14 @@ } @Override - protected AbstractAssembler createAssembler(FrameMap frameMap) { + protected Assembler createAssembler(FrameMap frameMap) { return new HSAILAssembler(getTarget()); } @Override public CompilationResultBuilder newCompilationResultBuilder(LIRGenerator lirGen, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { FrameMap frameMap = lirGen.frameMap; - AbstractAssembler masm = createAssembler(frameMap); + Assembler masm = createAssembler(frameMap); HotSpotFrameContext frameContext = new HotSpotFrameContext(); CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult); crb.setFrameSize(frameMap.frameSize()); @@ -138,12 +225,12 @@ } @Override - public void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod method) { - assert method != null : lirGen.getGraph() + " is not associated with a method"; + public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod method) { + assert method != null : lir + " is not associated with a method"; // Emit the prologue. - codeBuffer = crb.asm.codeBuffer; - codeBuffer.emitString0("version 0:95: $full : $large;"); - codeBuffer.emitString(""); + Assembler asm = crb.asm; + asm.emitString0("version 0:95: $full : $large;"); + asm.emitString(""); Signature signature = method.getSignature(); int sigParamCount = signature.getParameterCount(false); @@ -188,10 +275,10 @@ } } - codeBuffer.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method); - codeBuffer.emitString(""); - codeBuffer.emitString0("kernel &run ("); - codeBuffer.emitString(""); + asm.emitString0("// " + (isStatic ? "static" : "instance") + " method " + method); + asm.emitString(""); + asm.emitString0("kernel &run ("); + asm.emitString(""); FrameMap frameMap = crb.frameMap; RegisterConfig regConfig = frameMap.registerConfig; @@ -221,14 +308,14 @@ } // 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 += ","; } - codeBuffer.emitString(str); + asm.emitString(str); } - codeBuffer.emitString(") {"); + asm.emitString(") {"); /* * End of parameters start of prolog code. Emit the load instructions for loading of the @@ -236,7 +323,7 @@ * loaded up front but will be loaded as needed. */ for (int i = 0; i < nonConstantParamCount; i++) { - codeBuffer.emitString("ld_kernarg_" + paramHsailSizes[i] + " " + HSAIL.mapRegister(cc.getArgument(i)) + ", [" + paramNames[i] + "];"); + asm.emitString("ld_kernarg_" + paramHsailSizes[i] + " " + HSAIL.mapRegister(cc.getArgument(i)) + ", [" + paramNames[i] + "];"); } /* @@ -244,16 +331,16 @@ * the register as if it were the last of the nonConstant parameters. */ String workItemReg = "$s" + Integer.toString(asRegister(cc.getArgument(nonConstantParamCount)).encoding()); - codeBuffer.emitString("workitemabsid_u32 " + workItemReg + ", 0;"); + asm.emitString("workitemabsid_u32 " + workItemReg + ", 0;"); /* * Note the logic used for this spillseg size is to leave space and then go back and patch * in the correct size once we have generated all the instructions. This should probably be * done in a more robust way by implementing something like codeBuffer.insertString. */ - int spillsegDeclarationPosition = codeBuffer.position() + 1; + int spillsegDeclarationPosition = asm.position() + 1; String spillsegTemplate = "align 4 spill_u8 %spillseg[123456];"; - codeBuffer.emitString(spillsegTemplate); + asm.emitString(spillsegTemplate); // Emit object array load prologue here. if (isObjectLambda) { boolean useCompressedOops = getRuntime().getConfig().useCompressedOops; @@ -263,41 +350,41 @@ // so tempReg can be the next higher $d register String tmpReg = "$d" + (asRegister(cc.getArgument(nonConstantParamCount - 1)).encoding() + 1); // Convert gid to long. - codeBuffer.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long"); + asm.emitString("cvt_u64_s32 " + tmpReg + ", " + workItemReg + "; // Convert gid to long"); // Adjust index for sizeof ref. Where to pull this size from? - codeBuffer.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + (useCompressedOops ? 4 : 8) + "; // Adjust index for sizeof ref"); + asm.emitString("mul_u64 " + tmpReg + ", " + tmpReg + ", " + (useCompressedOops ? 4 : 8) + "; // Adjust index for sizeof ref"); // Adjust for actual data start. - codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start"); + asm.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + arrayElementsOffset + "; // Adjust for actual elements data start"); // Add to array ref ptr. - codeBuffer.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr"); + asm.emitString("add_u64 " + tmpReg + ", " + tmpReg + ", " + iterationObjArgReg + "; // Add to array ref ptr"); // Load the object into the parameter reg. if (useCompressedOops) { // Load u32 into the d 64 reg since it will become an object address - codeBuffer.emitString("ld_global_u32 " + tmpReg + ", " + "[" + tmpReg + "]" + "; // Load compressed ptr from array"); + asm.emitString("ld_global_u32 " + tmpReg + ", " + "[" + tmpReg + "]" + "; // Load compressed ptr from array"); long narrowOopBase = getRuntime().getConfig().narrowOopBase; long narrowOopShift = getRuntime().getConfig().narrowOopShift; if (narrowOopBase == 0 && narrowOopShift == 0) { // No more calculation to do, mov to target register - codeBuffer.emitString("mov_b64 " + iterationObjArgReg + ", " + tmpReg + "; // no shift or base addition"); + asm.emitString("mov_b64 " + iterationObjArgReg + ", " + tmpReg + "; // no shift or base addition"); } else { if (narrowOopBase == 0) { - codeBuffer.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift"); + asm.emitString("shl_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopShift + "; // do narrowOopShift"); } else if (narrowOopShift == 0) { - codeBuffer.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase"); + asm.emitString("add_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + narrowOopBase + "; // add narrowOopBase"); } else { - codeBuffer.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase"); + asm.emitString("mad_u64 " + iterationObjArgReg + ", " + tmpReg + ", " + (1 << narrowOopShift) + ", " + narrowOopBase + "; // shift and add narrowOopBase"); } } } else { - codeBuffer.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg"); + asm.emitString("ld_global_u64 " + iterationObjArgReg + ", " + "[" + tmpReg + "]" + "; // Load from array element into parameter reg"); } } // Prologue done, Emit code for the LIR. - crb.emit(lirGen.lir); + crb.emit(lir); // Now that code is emitted go back and figure out what the upper Bound stack size was. long maxStackSize = ((HSAILAssembler) crb.asm).upperBoundStackSize(); String spillsegStringFinal; @@ -309,9 +396,10 @@ } else { spillsegStringFinal = spillsegTemplate.replace("123456", String.format("%6d", maxStackSize)); } - codeBuffer.emitString(spillsegStringFinal, spillsegDeclarationPosition); + asm.emitString(spillsegStringFinal, spillsegDeclarationPosition); + // Emit the epilogue. - codeBuffer.emitString0("};"); - codeBuffer.emitString(""); + asm.emitString0("};"); + asm.emitString(""); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hsail.*; +import com.oracle.graal.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.util.*; @@ -51,7 +52,7 @@ Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null); Replacements replacements = new HSAILHotSpotReplacementsImpl(p, assumptions, codeCache.getTarget(), host.getReplacements()); HotSpotDisassemblerProvider disassembler = host.getDisassembler(); - SuitesProvider suites = host.getSuites(); + SuitesProvider suites = new DefaultSuitesProvider(); HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers); return new HSAILHotSpotBackend(runtime, providers); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -26,6 +26,8 @@ import sun.misc.*; import com.oracle.graal.api.code.*; +import static com.oracle.graal.api.code.ValueUtil.asConstant; +import static com.oracle.graal.api.code.ValueUtil.isConstant; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.hsail.*; import com.oracle.graal.hotspot.*; @@ -33,11 +35,12 @@ import com.oracle.graal.lir.hsail.*; import com.oracle.graal.lir.hsail.HSAILControlFlow.*; import com.oracle.graal.lir.hsail.HSAILMove.*; +import com.oracle.graal.phases.util.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.util.*; +import com.oracle.graal.graph.*; /** * The HotSpot specific portion of the HSAIL LIR generator. @@ -79,6 +82,11 @@ return access != null && access.isCompressible(); } + @Override + public boolean canStoreConstant(Constant c, boolean isCompressed) { + return true; + } + /** * Appends either a {@link CompareAndSwapOp} or a {@link CompareAndSwapCompressedOp} depending * on whether the memory location of a given {@link LoweredCompareAndSwapNode} contains a @@ -114,10 +122,17 @@ setResult(node, nodeResult); } + /** + * Returns whether or not the input access should be (de)compressed. + */ + private boolean isCompressedOperation(Kind kind, Access access) { + return access != null && access.isCompressible() && ((kind == Kind.Long && config.useCompressedClassPointers) || (kind == Kind.Object && config.useCompressedOops)); + } + @Override public Variable emitLoad(Kind kind, Value address, Access access) { HSAILAddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(kind); + Variable result = newVariable(kind.getStackKind()); LIRFrameState state = null; if (access instanceof DeoptimizingNode) { state = state((DeoptimizingNode) access); @@ -141,6 +156,23 @@ if (access instanceof DeoptimizingNode) { state = state((DeoptimizingNode) access); } + boolean isCompressed = isCompressedOperation(kind, access); + if (isConstant(inputVal)) { + Constant c = asConstant(inputVal); + if (canStoreConstant(c, isCompressed)) { + if (isCompressed) { + if ((c.getKind() == Kind.Object) && c.isNull()) { + append(new StoreConstantOp(Kind.NarrowOop, storeAddress, c, state)); + } else { + throw GraalInternalError.shouldNotReachHere("can't handle: " + access); + } + return; + } else { + append(new StoreConstantOp(kind, storeAddress, c, state)); + return; + } + } + } Variable input = load(inputVal); if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) { Variable scratch = newVariable(Kind.Long); diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotReplacementsImpl.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,11 +22,9 @@ */ package com.oracle.graal.hotspot.ptx; -import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.compiler.GraalCompiler.*; -import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*; import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*; import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*; import static com.oracle.graal.lir.LIRValueUtil.*; @@ -34,18 +32,16 @@ import java.util.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CallingConvention.*; +import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.ptx.*; import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.ptx.*; import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.*; +import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.HotSpotReplacementsImpl.GraphProducer; -import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.LIRInstruction.OperandFlag; @@ -58,6 +54,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.word.*; @@ -66,8 +63,10 @@ */ public class PTXHotSpotBackend extends HotSpotBackend { + private final boolean deviceInitialized; + /** - * Descriptor for the PTX runtime method for launching a kernel. The C++ signature is: + * Descriptor for the PTX runtime method for calling a kernel. The C++ signature is: * *

      *     jlong (JavaThread* thread,
@@ -77,11 +76,14 @@
      *            jint dimZ,
      *            jlong parametersAndReturnValueBuffer,
      *            jint parametersAndReturnValueBufferSize,
+     *            jint objectParametersCount,
+     *            jlong objectParametersOffsets,
+     *            jlong pinnedObjects,
      *            jint encodedReturnTypeSize)
      * 
*/ // @formatter:off - public static final ForeignCallDescriptor LAUNCH_KERNEL = new ForeignCallDescriptor("execute_kernel_from_vm", long.class, + public static final ForeignCallDescriptor CALL_KERNEL = new ForeignCallDescriptor("execute_kernel_from_vm", long.class, Word.class, // thread long.class, // kernel int.class, // dimX @@ -89,43 +91,76 @@ int.class, // dimZ long.class, // parametersAndReturnValueBuffer int.class, // parametersAndReturnValueBufferSize + int.class, // objectParameterCount + long.class, // objectParameterOffsets + long.class, // pinnedObjects int.class); // encodedReturnTypeSize // @formatter:on public PTXHotSpotBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) { super(runtime, providers); - CompilerToGPU compilerToGPU = getRuntime().getCompilerToGPU(); - deviceInitialized = OmitDeviceInit || compilerToGPU.deviceInit(); + if (OmitDeviceInit) { + deviceInitialized = true; + } else { + boolean init = false; + try { + init = initialize(); + } catch (UnsatisfiedLinkError e) { + } + deviceInitialized = init; + } } + /** + * Initializes the GPU device. + * + * @return whether or not initialization was successful + */ + private static native boolean initialize(); + @Override public boolean shouldAllocateRegisters() { return false; } /** - * Used to omit {@linkplain CompilerToGPU#deviceInit() device initialization}. + * Used to omit {@linkplain #initialize() device initialization}. */ private static final boolean OmitDeviceInit = Boolean.getBoolean("graal.ptx.omitDeviceInit"); @Override public void completeInitialization() { - HotSpotHostForeignCallsProvider hostForeignCalls = (HotSpotHostForeignCallsProvider) getRuntime().getHostProviders().getForeignCalls(); - CompilerToGPU compilerToGPU = getRuntime().getCompilerToGPU(); + HotSpotProviders hostProviders = getRuntime().getHostProviders(); + HotSpotHostForeignCallsProvider hostForeignCalls = (HotSpotHostForeignCallsProvider) hostProviders.getForeignCalls(); if (deviceInitialized) { - long launchKernel = compilerToGPU.getLaunchKernelAddress(); - hostForeignCalls.registerForeignCall(LAUNCH_KERNEL, launchKernel, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); + 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 boolean deviceInitialized; + private static native void destroyContext(); + + /** + * Gets the address of {@code Ptx::execute_kernel_from_vm()}. + */ + private static native long getLaunchKernelAddress(); @Override public FrameMap newFrameMap() { return new PTXFrameMap(getCodeCache()); } + /** + * Determines if the GPU device (or simulator) is available and initialized. + */ public boolean isDeviceInitialized() { return deviceInitialized; } @@ -148,7 +183,8 @@ } private boolean canOffloadToGPU(ResolvedJavaMethod method) { - return method.getName().contains("lambda$") & method.isSynthetic(); + HotSpotVMConfig config = getRuntime().getConfig(); + return config.gpuOffload && method.getName().contains("lambda$") & method.isSynthetic(); } }; } @@ -166,20 +202,26 @@ HotSpotProviders providers = getProviders(); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, method, false); PhaseSuite graphBuilderSuite = providers.getSuites().getDefaultGraphBuilderSuite(); + graphBuilderSuite.appendPhase(new NonNullParametersPhase()); Suites suites = providers.getSuites().getDefaultSuites(); - ExternalCompilationResult ptxCode = compileGraph(graph, cc, method, providers, this, this.getTarget(), null, graphBuilderSuite, OptimisticOptimizations.NONE, getProfilingInfo(graph), - new SpeculationLog(), suites, true, new ExternalCompilationResult(), CompilationResultBuilderFactory.Default); + ExternalCompilationResult ptxCode = compileGraph(graph, cc, method, providers, this, this.getTarget(), null, graphBuilderSuite, OptimisticOptimizations.NONE, getProfilingInfo(graph), null, + suites, true, new ExternalCompilationResult(), CompilationResultBuilderFactory.Default); if (makeBinary) { try (Scope ds = Debug.scope("GeneratingKernelBinary")) { - long kernel = getRuntime().getCompilerToGPU().generateKernel(ptxCode.getTargetCode(), method.getName()); + assert ptxCode.getTargetCode() != null; + long kernel = generateKernel(ptxCode.getTargetCode(), method.getName()); ptxCode.setEntryPoint(kernel); } catch (Throwable e) { throw Debug.handle(e); } } return ptxCode; + } - } + /** + * Generates a GPU binary from PTX code. + */ + private static native long generateKernel(byte[] targetCode, String name); /** * A list of the {@linkplain #installKernel(ResolvedJavaMethod, ExternalCompilationResult) @@ -218,24 +260,24 @@ LIRInstruction op; - void emitDeclarations(Buffer codeBuffer) { + void emitDeclarations(Assembler asm) { for (Integer i : unsigned8) { - codeBuffer.emitString(".reg .u8 %r" + i.intValue() + ";"); + asm.emitString(".reg .u8 %r" + i.intValue() + ";"); } for (Integer i : signed32) { - codeBuffer.emitString(".reg .s32 %r" + i.intValue() + ";"); + asm.emitString(".reg .s32 %r" + i.intValue() + ";"); } for (Integer i : signed64) { - codeBuffer.emitString(".reg .s64 %r" + i.intValue() + ";"); + asm.emitString(".reg .s64 %r" + i.intValue() + ";"); } for (Integer i : unsigned64) { - codeBuffer.emitString(".reg .u64 %r" + i.intValue() + ";"); + asm.emitString(".reg .u64 %r" + i.intValue() + ";"); } for (Integer i : float32) { - codeBuffer.emitString(".reg .f32 %r" + i.intValue() + ";"); + asm.emitString(".reg .f32 %r" + i.intValue() + ";"); } for (Integer i : float64) { - codeBuffer.emitString(".reg .f64 %r" + i.intValue() + ";"); + asm.emitString(".reg .f64 %r" + i.intValue() + ";"); } } @@ -317,7 +359,7 @@ // - has no incoming arguments passed on the stack // - has no instructions with debug info FrameMap frameMap = lirGen.frameMap; - AbstractAssembler masm = createAssembler(frameMap); + Assembler masm = createAssembler(frameMap); PTXFrameContext frameContext = new PTXFrameContext(); CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult); crb.setFrameSize(0); @@ -325,39 +367,39 @@ } @Override - protected AbstractAssembler createAssembler(FrameMap frameMap) { + protected Assembler createAssembler(FrameMap frameMap) { return new PTXMacroAssembler(getTarget(), frameMap.registerConfig); } @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) { + private static void emitKernelEntry(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod codeCacheOwner) { // Emit PTX kernel entry text based on PTXParameterOp // instructions in the start block. Remove the instructions // once kernel entry text and directives are emitted to // facilitate seemless PTX code generation subsequently. - assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method"; + assert codeCacheOwner != null : lir + " is not associated with a method"; final String name = codeCacheOwner.getName(); - Buffer codeBuffer = crb.asm.codeBuffer; + Assembler asm = crb.asm; // Emit initial boiler-plate directives. - codeBuffer.emitString(".version 3.0"); - codeBuffer.emitString(".target sm_30"); - codeBuffer.emitString0(".entry " + name + " ("); - codeBuffer.emitString(""); + asm.emitString(".version 3.0"); + asm.emitString(".target sm_30"); + asm.emitString0(".entry " + name + " ("); + asm.emitString(""); // Get the start block - Block startBlock = lirGen.lir.cfg.getStartBlock(); + Block startBlock = lir.cfg.getStartBlock(); // Keep a list of ParameterOp instructions to delete from the // list of instructions in the block. ArrayList deleteOps = new ArrayList<>(); // Emit .param arguments to kernel entry based on ParameterOp // instruction. - for (LIRInstruction op : lirGen.lir.lir(startBlock)) { + for (LIRInstruction op : lir.lir(startBlock)) { if (op instanceof PTXParameterOp) { op.emitCode(crb); deleteOps.add(op); @@ -366,24 +408,23 @@ // Delete ParameterOp instructions. for (LIRInstruction op : deleteOps) { - lirGen.lir.lir(startBlock).remove(op); + lir.lir(startBlock).remove(op); } // Start emiting body of the PTX kernel. - codeBuffer.emitString0(") {"); - codeBuffer.emitString(""); + asm.emitString0(") {"); + asm.emitString(""); } // Emit .reg space declarations - private static void emitRegisterDecl(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) { + private static void emitRegisterDecl(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod codeCacheOwner) { - assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method"; + assert codeCacheOwner != null : lir + " is not associated with a method"; - Buffer codeBuffer = crb.asm.codeBuffer; RegisterAnalysis registerAnalysis = new RegisterAnalysis(); - for (Block b : lirGen.lir.codeEmittingOrder()) { - for (LIRInstruction op : lirGen.lir.lir(b)) { + for (Block b : lir.codeEmittingOrder()) { + for (LIRInstruction op : lir.lir(b)) { if (op instanceof LabelOp) { // Don't consider this as a definition } else { @@ -394,47 +435,60 @@ } } - registerAnalysis.emitDeclarations(codeBuffer); + Assembler asm = crb.asm; + registerAnalysis.emitDeclarations(asm); // emit predicate register declaration - int maxPredRegNum = ((PTXLIRGenerator) lirGen).getNextPredRegNumber(); + int maxPredRegNum = lir.numVariables(); if (maxPredRegNum > 0) { - codeBuffer.emitString(".reg .pred %p<" + maxPredRegNum + ">;"); + asm.emitString(".reg .pred %p<" + maxPredRegNum + ">;"); } } @Override - public void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) { - assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method"; - Buffer codeBuffer = crb.asm.codeBuffer; + public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod codeCacheOwner) { + assert codeCacheOwner != null : lir + " is not associated with a method"; + Assembler asm = crb.asm; + // Emit the prologue - emitKernelEntry(crb, lirGen, codeCacheOwner); + emitKernelEntry(crb, lir, codeCacheOwner); // Emit register declarations try { - emitRegisterDecl(crb, lirGen, codeCacheOwner); + emitRegisterDecl(crb, lir, codeCacheOwner); } catch (GraalInternalError e) { e.printStackTrace(); // TODO : Better error handling needs to be done once // all types of parameters are handled. - codeBuffer.setPosition(0); - codeBuffer.close(false); + asm.close(false); return; } // Emit code for the LIR try { - crb.emit(lirGen.lir); + crb.emit(lir); } catch (GraalInternalError e) { e.printStackTrace(); // TODO : Better error handling needs to be done once // all types of parameters are handled. - codeBuffer.setPosition(0); - codeBuffer.close(false); + asm.close(false); return; } // Emit the epilogue - codeBuffer.emitString0("}"); - codeBuffer.emitString(""); + asm.emitString0("}"); + asm.emitString(""); } + + /** + * Gets the total number of available CUDA cores. + */ + public int getAvailableProcessors() { + if (!deviceInitialized) { + return 0; + } + return getAvailableProcessors0(); + } + + private static native int getAvailableProcessors0(); + } diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotSuitesProvider.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotSuitesProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.ptx; - -import com.oracle.graal.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.tiers.*; - -public class PTXHotSpotSuitesProvider implements SuitesProvider { - - private final Suites defaultSuites; - private final PhaseSuite defaultGraphBuilderSuite; - - public PTXHotSpotSuitesProvider() { - this.defaultGraphBuilderSuite = createGraphBuilderSuite(); - this.defaultSuites = createSuites(); - } - - public Suites getDefaultSuites() { - return defaultSuites; - } - - public Suites createSuites() { - return Suites.createDefaultSuites(); - } - - public PhaseSuite getDefaultGraphBuilderSuite() { - return defaultGraphBuilderSuite; - } - - protected PhaseSuite createGraphBuilderSuite() { - PhaseSuite suite = new PhaseSuite<>(); - suite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault())); - return suite; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java Wed Mar 05 19:40:15 2014 -0800 @@ -40,7 +40,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.java.*; import com.oracle.graal.lir.ptx.*; import com.oracle.graal.nodes.*; @@ -55,21 +54,62 @@ /** * Utility for building a graph that "wraps" a compiled PTX kernel. Such a wrapper handles the - * transition from the host CPU to the GPU and back. The graph created is something like the - * following pseudo code with UPPER CASE denoting compile-time constants: + * transition from the host CPU to the GPU and back. The wrapper allocate 3 on-stack buffers: + *
    + *
  • PARAMS: a buffer for the kernel parameters and one word for the on-device address of the + * return value (if any).
  • + *
  • PINNED: a buffer into which the address of pinned objects is saved.
  • + *
  • OBJECT_OFFSETS: the offsets of the object values in PARAMS.
  • + *
+ * + * + * The PARAMS buffer is the {@code CU_LAUNCH_PARAM_BUFFER_POINTER} buffer passed in the + * {@code extra} argument to the {@code cuLaunchKernel} function. This buffer contains the + * parameters to the call. The buffer is word aligned and each parameter is aligned in the buffer + * according to its data size. The wrapper copies the incoming arguments into the buffer as is. The + * native {@link PTXHotSpotBackend#CALL_KERNEL callKernel} function will pin the memory for each + * object parameter (using {@code cuMemHostRegister}) and then replace the object pointer in PARAMS + * with an on-device pointer to the object's memory (see {@code cuMemHostGetDevicePointer}). The + * function saves pinned object pointer into PINNED so that it can unpinned once the kernel returns. + * The object pointers in PARAMS are specified by OBJECT_OFFSETS. + *

+ * As a concrete example, for a kernel whose Java method signature is: * *

- *     T kernel(p0, p1, ..., pN) {
- *         jint bufSize = SIZE_OF_ALIGNED_PARAMS_AND_RETURN_VALUE_WITH_PADDING(p0, p1, ..., pN);
- *         jbyte buf[bufSize] = {p0, PAD(p1), p1, ..., PAD(pN), pN};
- *         jlong result = PTX_LAUNCH_KERNEL(THREAD_REGISTER, KERNEL_ENTRY_POINT, dimX, dimY, dimZ, buf, bufSize, encodedReturnTypeSize);
- *         return convert(result);
+ *     static int kernel(int p1, short p2, Object p3, long p4)
+ * 
+ * + * the graph created is shown below as psuedo-code: + * + *
+ *     int kernel_wrapper(int p1, short p2, oop p3, long p4) {
+ *         address kernelAddr = kernel.start;
+ *         if (kernelAddr == 0) {
+ *             deopt(InvalidateRecompile, RuntimeConstraint);
+ *         }
+ *         byte PARAMS[32];
+ *         word PINNED[1]; // note: no refmap
+ *         int OBJECT_OFFSETS[1] = {8};
+ *         ((int*) PARAMS)[0] = p1;
+ *         ((short*) PARAMS)[2] = p2;
+ *         ((word*) PARAMS)[1] = p3;
+ *         ((long*) PARAMS)[2] = p4;
+ *         int result = CALL_KERNEL(THREAD_REGISTER, KERNEL_ENTRY_POINT, 1, 1, 1, PARAMS, 32, 1, OBJECT_OFFSETS, PINNED, 4);
+ *         if (clearPendingException(thread)) {
+ *             deopt(None, RuntimeConstraint);
+ *         }
+ *         return result;
  *     }
  * 
*

* The generated graph includes a reference to the {@link HotSpotNmethod} for the kernel. There must * be another reference to the same {@link HotSpotNmethod} object to ensure that the nmethod is not - * unloaded by the next full GC. + * unloaded by the next full GC. Currently, these extra "keep-alive" references are maintained by + * {@link PTXHotSpotBackend}. + *

+ * The PTX runtime code called by the wrapper blocks GC while the kernel is executing (cf + * GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical JNI functions). This ensures objects can + * be safely passed to kernels but should be replaced with a lighter weight mechanism at some point. */ public class PTXWrapperBuilder extends GraphKit { @@ -92,11 +132,23 @@ int[] javaParameterOffsetsInKernelParametersBuffer; /** - * Constants denoting the arguments to {@link PTXHotSpotBackend#LAUNCH_KERNEL}. + * Constants denoting the arguments to {@link PTXHotSpotBackend#CALL_KERNEL}. */ + // @formatter:off enum LaunchArg { - Thread, Kernel, DimX, DimY, DimZ, ParametersAndReturnValueBuffer, ParametersAndReturnValueBufferSize, EncodedReturnTypeSize + Thread, + Kernel, + DimX, + DimY, + DimZ, + ParametersAndReturnValueBuffer, + ParametersAndReturnValueBufferSize, + ObjectParametersCount, + ObjectParametersOffsets, + PinnedObjects, + EncodedReturnTypeSize } + // @formatter:on /** * Creates the graph implementing the CPU to GPU transition. @@ -108,6 +160,7 @@ public PTXWrapperBuilder(ResolvedJavaMethod method, HotSpotNmethod kernel, HotSpotProviders providers) { super(new StructuredGraph(method), providers); int wordSize = providers.getCodeCache().getTarget().wordSize; + int intSize = Integer.SIZE / Byte.SIZE; Kind wordKind = providers.getCodeCache().getTarget().wordKind; Signature sig = method.getSignature(); boolean isStatic = isStatic(method.getModifiers()); @@ -117,17 +170,18 @@ int javaParametersIndex = 0; Kind returnKind = sig.getReturnKind(); - BitSet objects = new BitSet(); + List objectSlots = new ArrayList<>(javaParameters.length); if (!isStatic) { - allocateParameter(Kind.Object, javaParametersIndex++, objects, wordSize); + allocateParameter(Kind.Object, javaParametersIndex++, objectSlots, wordSize); } for (int sigIndex = 0; sigIndex < sigCount; sigIndex++) { Kind kind = sig.getParameterKind(sigIndex); - allocateParameter(kind, javaParametersIndex++, objects, wordSize); + allocateParameter(kind, javaParametersIndex++, objectSlots, wordSize); } bufSize = roundUp(bufSize, wordSize); - // Add slot for holding pointer to device memory storing return value + // Add slot for the device memory pointer. The kernel writes a + // pointer in this slot that points to the return value. int encodedReturnTypeSize = 0; if (returnKind != Kind.Void) { bufSize += wordSize; @@ -140,7 +194,29 @@ InvokeNode kernelStart = createInvoke(getClass(), "getKernelStart", ConstantNode.forObject(kernel, providers.getMetaAccess(), getGraph())); - AllocaNode buf = append(new AllocaNode(bufSize / wordSize, objects)); + AllocaNode buf = append(new AllocaNode(bufSize / wordSize, new BitSet())); + ValueNode objectParametersOffsets; + ValueNode pinnedObjects; + ConstantNode nullWord = ConstantNode.forIntegerKind(wordKind, 0L, getGraph()); + if (objectSlots.isEmpty()) { + objectParametersOffsets = ConstantNode.forLong(0, getGraph()); + pinnedObjects = ConstantNode.forLong(0, getGraph()); + } else { + int intsPerWord = wordSize / intSize; + int slots = roundUp(objectSlots.size(), intsPerWord); + objectParametersOffsets = append(new AllocaNode(slots, new BitSet())); + // No refmap for pinned objects list since kernel execution is (currently) GC unsafe + pinnedObjects = append(new AllocaNode(objectSlots.size(), new BitSet())); + + // Initialize the object parameter offsets array + int index = 0; + for (int slot : objectSlots) { + int offset = slot * wordSize; + LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, index * intSize, getGraph()); + append(new WriteNode(objectParametersOffsets, ConstantNode.forInt(offset, getGraph()), location, BarrierType.NONE, false, false)); + index++; + } + } Map args = new EnumMap<>(LaunchArg.class); args.put(Thread, append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), true, false))); @@ -150,6 +226,9 @@ args.put(DimZ, forInt(1, getGraph())); args.put(ParametersAndReturnValueBuffer, buf); args.put(ParametersAndReturnValueBufferSize, forInt(bufSize, getGraph())); + args.put(ObjectParametersCount, forInt(objectSlots.size(), getGraph())); + args.put(ObjectParametersOffsets, objectParametersOffsets); + args.put(PinnedObjects, pinnedObjects); args.put(EncodedReturnTypeSize, forInt(encodedReturnTypeSize, getGraph())); int sigIndex = isStatic ? 0 : -1; @@ -158,11 +237,11 @@ int javaParameterOffset = javaParameterOffsetsInKernelParametersBuffer[javaParametersIndex]; LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.kind(), javaParameterOffset, getGraph()); append(new WriteNode(buf, javaParameter, location, BarrierType.NONE, false, false)); - updateDimArg(method, providers, sig, sigIndex++, args, javaParameter); + updateDimArg(method, sig, sigIndex++, args, javaParameter); } if (returnKind != Kind.Void) { LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, bufSize - wordSize, getGraph()); - append(new WriteNode(buf, ConstantNode.forIntegerKind(wordKind, 0L, getGraph()), location, BarrierType.NONE, false, false)); + append(new WriteNode(buf, nullWord, location, BarrierType.NONE, false, false)); } FrameStateBuilder fsb = new FrameStateBuilder(method, getGraph(), true); @@ -170,14 +249,10 @@ getGraph().start().setStateAfter(fs); ValueNode[] launchArgsArray = args.values().toArray(new ValueNode[args.size()]); - ForeignCallNode result = append(new ForeignCallNode(providers.getForeignCalls(), LAUNCH_KERNEL, launchArgsArray)); + ForeignCallNode result = append(new ForeignCallNode(providers.getForeignCalls(), CALL_KERNEL, launchArgsArray)); result.setDeoptimizationState(fs); - ConstantNode isObjectResultArg = ConstantNode.forBoolean(returnKind == Kind.Object, getGraph()); - InvokeNode handlePendingException = createInvoke(getClass(), "handlePendingException", args.get(Thread), isObjectResultArg); - handlePendingException.setStateAfter(fs); InvokeNode getObjectResult = null; - ValueNode returnValue; switch (returnKind) { case Void: @@ -188,14 +263,18 @@ case Short: case Char: case Int: - returnValue = unique(new ConvertNode(Kind.Long, Kind.Int, result)); + returnValue = unique(new NarrowNode(result, 32)); break; case Long: returnValue = result; break; - case Float: + case Float: { + ValueNode asInt = unique(new NarrowNode(result, 32)); + returnValue = ReinterpretNode.reinterpret(Kind.Float, asInt); + break; + } case Double: - returnValue = unique(new ReinterpretNode(returnKind, result)); + returnValue = ReinterpretNode.reinterpret(Kind.Double, result); break; case Object: getObjectResult = createInvoke(getClass(), "getObjectResult", args.get(Thread)); @@ -220,12 +299,12 @@ } /** - * Allocates a slot in the kernel parameters' buffer for a Java parameter. + * Computes offset and size of space in PARAMS for a Java parameter. * * @param kind the kind of the parameter * @param javaParametersIndex the index of the Java parameter */ - private void allocateParameter(Kind kind, int javaParametersIndex, BitSet objects, int wordSize) { + private void allocateParameter(Kind kind, int javaParametersIndex, List objectSlots, int wordSize) { int kindByteSize = kind == Kind.Object ? wordSize : kind.getBitCount() / Byte.SIZE; bufSize = roundUp(bufSize, kindByteSize); javaParameterOffsetsInKernelParametersBuffer[javaParametersIndex] = bufSize; @@ -233,7 +312,7 @@ if (kind == Kind.Object) { stamp = StampFactory.object(); int slot = bufSize / wordSize; - objects.set(slot); + objectSlots.add(slot); } else { stamp = StampFactory.forKind(kind); } @@ -245,7 +324,7 @@ * Updates the {@code dimX}, {@code dimY} or {@code dimZ} argument passed to the kernel if * {@code javaParameter} is annotated with {@link ParallelOver}. */ - private void updateDimArg(ResolvedJavaMethod method, HotSpotProviders providers, Signature sig, int sigIndex, Map launchArgs, ParameterNode javaParameter) { + private void updateDimArg(ResolvedJavaMethod method, Signature sig, int sigIndex, Map launchArgs, ParameterNode javaParameter) { if (sigIndex >= 0) { ParallelOver parallelOver = getParameterAnnotation(ParallelOver.class, sigIndex, method); if (parallelOver != null && sig.getParameterType(sigIndex, method.getDeclaringClass()).equals(providers.getMetaAccess().lookupJavaType(int[].class))) { @@ -273,19 +352,6 @@ } /** - * Snippet invoked upon return from the kernel to handle any pending exceptions. - */ - @Snippet - private static void handlePendingException(Word thread, boolean isObjectResult) { - if (clearPendingException(thread)) { - if (isObjectResult) { - getAndClearObjectResult(thread); - } - DeoptimizeNode.deopt(DeoptimizationAction.None, RuntimeConstraint); - } - } - - /** * Snippet invoked upon return from the kernel to retrieve an object return value from the * thread local used for communicating object return values from VM calls. */ diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -26,11 +26,12 @@ import com.oracle.graal.asm.sparc.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.sparc.*; @Opcode("DEOPT") -final class SPARCDeoptimizeOp extends SPARCLIRInstruction { +final class SPARCDeoptimizeOp extends SPARCLIRInstruction implements BlockEndOp { @State private LIRFrameState info; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,6 +32,7 @@ import com.oracle.graal.asm.sparc.*; import com.oracle.graal.asm.sparc.SPARCAssembler.*; import com.oracle.graal.compiler.gen.LIRGenerator; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; @@ -146,7 +147,7 @@ } @Override - protected AbstractAssembler createAssembler(FrameMap frameMap) { + protected Assembler createAssembler(FrameMap frameMap) { return new SPARCMacroAssembler(getTarget(), frameMap.registerConfig); } @@ -157,7 +158,7 @@ assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; Stub stub = gen.getStub(); - AbstractAssembler masm = createAssembler(frameMap); + Assembler masm = createAssembler(frameMap); // On SPARC we always use stack frames. HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, frameContext, compilationResult); @@ -178,7 +179,7 @@ } @Override - public void emitCode(CompilationResultBuilder crb, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner) { + public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; FrameMap frameMap = crb.frameMap; RegisterConfig regConfig = frameMap.registerConfig; @@ -207,7 +208,7 @@ crb.recordMark(Marks.MARK_VERIFIED_ENTRY); // Emit code for the LIR - crb.emit(lirGen.lir); + crb.emit(lir); HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); @@ -219,7 +220,6 @@ } else { // No need to emit the stubs for entries back into the method since // it has no calls that can cause such "return" entries - assert !frameMap.accessesCallerFrame() : lirGen.getGraph(); } if (unverifiedStub != null) { @@ -228,4 +228,9 @@ SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER)); } } + + @Override + public NativeFunctionInterface getNativeFunctionInterface() { + throw GraalInternalError.unimplemented("No NativeFunctionInterface of SPARC"); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Wed Mar 05 19:40:15 2014 -0800 @@ -49,7 +49,7 @@ assert host == null; TargetDescription target = createTarget(); - HotSpotRegistersProvider registers = new HotSpotRegisters(Register.None, Register.None, Register.None); // FIXME + HotSpotRegistersProvider registers = createRegisters(); HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime); HotSpotCodeCacheProvider codeCache = new SPARCHotSpotCodeCacheProvider(runtime, target); HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime); @@ -68,6 +68,10 @@ return new SPARCHotSpotBackend(runtime, providers); } + protected HotSpotRegistersProvider createRegisters() { + return new HotSpotRegisters(SPARC.g2, SPARC.g6, SPARC.sp); + } + @SuppressWarnings("unused") private static Value[] createNativeABICallerSaveRegisters(HotSpotVMConfig config, RegisterConfig regConfig) { CalleeSaveLayout csl = regConfig.getCalleeSaveLayout(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEpilogueOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEpilogueOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEpilogueOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,12 +23,13 @@ package com.oracle.graal.hotspot.sparc; import com.oracle.graal.lir.sparc.*; +import com.oracle.graal.lir.StandardOp.*; import com.oracle.graal.lir.asm.*; /** * Superclass for operations that leave a method's frame. */ -abstract class SPARCHotSpotEpilogueOp extends SPARCLIRInstruction { +abstract class SPARCHotSpotEpilogueOp extends SPARCLIRInstruction implements BlockEndOp { protected void leaveFrame(CompilationResultBuilder crb) { crb.frameContext.leave(crb); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -72,7 +72,6 @@ @SuppressWarnings("hiding") @Override protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { - assert config.basicLockSize == 8; HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long); return new HotSpotDebugInfoBuilder(nodeOperands, lockStack); } @@ -97,10 +96,11 @@ @Override public Variable emitForeignCall(ForeignCallLinkage linkage, DeoptimizingNode info, Value... args) { + Stub stub = getStub(); Variable result; if (linkage.canDeoptimize()) { - assert info != null; + assert info != null || stub != null; HotSpotRegistersProvider registers = getProviders().getRegisters(); Register thread = registers.getThreadRegister(); Register stackPointer = registers.getStackPointerRegister(); @@ -243,7 +243,7 @@ @Override public Variable emitLoad(Kind kind, Value address, Access access) { SPARCAddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(kind); + Variable result = newVariable(kind.getStackKind()); LIRFrameState state = null; if (access instanceof DeoptimizingNode) { state = state((DeoptimizingNode) access); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java Wed Mar 05 19:40:15 2014 -0800 @@ -208,7 +208,7 @@ } Kind returnKind = returnType == null ? Kind.Void : returnType.getKind(); - AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(returnKind); + AllocatableValue returnLocation = returnKind == Kind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(returnKind.getStackKind()); return new CallingConvention(currentStackOffset, returnLocation, locations); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,7 +24,6 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import static com.oracle.graal.phases.GraalOptions.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; @@ -49,7 +48,8 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - if (!isStub && (crb.frameContext.hasFrame() || !OptEliminateSafepoints.getValue())) { + if (!isStub) { + // Every non-stub compile method must have a poll before the return. // Using the same scratch register as LIR_Assembler::return_op // in c1_LIRAssembler_sparc.cpp SPARCHotSpotSafepointOp.emitCode(crb, masm, runtime().getConfig(), true, null, SPARC.l0); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -59,9 +59,9 @@ } public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, HotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) { - final int pos = masm.codeBuffer.position(); + final int pos = masm.position(); new Setx(config.safepointPollingAddress, scratch).emit(masm); - crb.recordMark(atReturn ? MARK_POLL_RETURN_NEAR : MARK_POLL_NEAR); + crb.recordMark(atReturn ? MARK_POLL_RETURN_FAR : MARK_POLL_FAR); if (state != null) { crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCPrefetchOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCPrefetchOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCPrefetchOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,16 +23,16 @@ package com.oracle.graal.hotspot.sparc; +import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.graph.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.sparc.*; public class SPARCPrefetchOp extends SPARCLIRInstruction { - private final int instr; // AllocatePrefecthInstr + private final int instr; // AllocatePrefetchInstr @Alive({COMPOSITE}) protected SPARCAddressValue address; public SPARCPrefetchOp(SPARCAddressValue address, int instr) { @@ -43,8 +43,6 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { assert instr == 0 : "only supported value is 0"; - // masm.prefetch(address.toAddress(), 2); - throw GraalInternalError.unimplemented("prefetch instruction"); + new Prefetch(address.toAddress(), Prefetch.Fcn.SeveralWritesAndPossiblyReads).emit(masm); } - } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -172,6 +172,7 @@ return Boolean.valueOf(true); } + @Ignore("ImmutableCode override may not work reliably in non-hosted mode") @Test public void testBoxedBooleanAOT() { StructuredGraph result = compile("getBoxedBoolean", true); @@ -204,7 +205,7 @@ // create suites everytime, as we modify options for the compiler final Suites suitesLocal = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().createSuites(); final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(), - OptimisticOptimizations.ALL, getProfilingInfo(graph), new SpeculationLog(), suitesLocal, true, new CompilationResult(), CompilationResultBuilderFactory.Default); + OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, true, new CompilationResult(), CompilationResultBuilderFactory.Default); addMethod(method, compResult); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -198,6 +198,10 @@ } int j = 0; while (j < objects.length) { + if (!installedBenchmarkCode.isValid()) { + // This can get invalidated due to lack of MDO update + installedBenchmarkCode = getInstalledCode("queueTest"); + } installedBenchmarkCode.execute(q, objects[j], null); j++; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -115,6 +115,7 @@ ResolvedJavaMethod installedCodeOwner = getMetaAccess().lookupJavaMethod(method); StructuredGraph graph = getReplacements().getMethodSubstitution(installedCodeOwner); if (graph != null) { + graph = graph.copy(); Assert.assertNotNull(getCode(installedCodeOwner, graph, true)); atLeastOneCompiled = true; } else { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedJavaFieldTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedJavaFieldTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,85 @@ +/* + * 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.hotspot.test; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType.*; +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; + +/** + * Tests {@link HotSpotResolvedJavaField} functionality. + */ +public class HotSpotResolvedJavaFieldTest { + + private static final Class[] classesWithInternalFields = {Class.class, ClassLoader.class}; + + /** + * Tests that {@link HotSpotResolvedJavaField#getModifiers()} only includes the modifiers + * returned by {@link Field#getModifiers()}. Namely, it must not include + * {@code HotSpotResolvedJavaField#FIELD_INTERNAL_FLAG}. + */ + @Test + public void testModifiersForInternal() { + for (Class c : classesWithInternalFields) { + ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(c); + for (ResolvedJavaField field : type.getInstanceFields(false)) { + if (field.isInternal()) { + Assert.assertEquals(0, ~getReflectionFieldModifiers() & field.getModifiers()); + } + } + } + } + + /** + * Tests that {@link HotSpotResolvedObjectType#createField(String, JavaType, long, int)} always + * returns the same object for an internal field. + */ + @Test + public void testCachingForInternalFields() { + for (Class c : classesWithInternalFields) { + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c); + for (ResolvedJavaField field : type.getInstanceFields(false)) { + if (field.isInternal()) { + HotSpotResolvedJavaField expected = (HotSpotResolvedJavaField) field; + ResolvedJavaField actual = type.createField(expected.getName(), expected.getType(), expected.offset(), expected.getModifiers()); + Assert.assertEquals(expected, actual); + } + } + } + } + + @Test + public void testIsInObject() { + for (Field f : String.class.getDeclaredFields()) { + HotSpotResolvedJavaField rf = (HotSpotResolvedJavaField) runtime().getHostProviders().getMetaAccess().lookupJavaField(f); + Assert.assertEquals(rf.toString(), rf.isInObject("a string"), !isStatic(rf.getModifiers())); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedObjectTypeTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedObjectTypeTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotResolvedObjectTypeTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,13 +24,12 @@ import org.junit.*; -import com.oracle.graal.compiler.test.*; import com.oracle.graal.hotspot.meta.*; /** * Tests {@link HotSpotResolvedObjectType} functionality. */ -public class HotSpotResolvedObjectTypeTest extends GraalCompilerTest { +public class HotSpotResolvedObjectTypeTest { @Test public void testGetSourceFileName() throws Throwable { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Mar 05 19:40:15 2014 -0800 @@ -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.*; @@ -29,6 +30,7 @@ import static com.oracle.graal.phases.GraalOptions.*; import static com.oracle.graal.phases.common.InliningUtil.*; +import java.io.*; import java.lang.reflect.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -49,9 +51,16 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; -public class CompilationTask implements Runnable { +public class CompilationTask implements Runnable, Comparable { - public static final ThreadLocal withinEnqueue = new ThreadLocal() { + // Keep static finals in a group with withinEnqueue as the last one. CompilationTask can be + // called from within it's own clinit so it needs to be careful about accessing state. Once + // withinEnqueue is non-null we assume that CompilationTask is fully initialized. + private static final AtomicLong uniqueTaskIds = new AtomicLong(); + + private static final DebugMetric BAILOUTS = Debug.metric("Bailouts"); + + private static final ThreadLocal withinEnqueue = new ThreadLocal() { @Override protected Boolean initialValue() { @@ -59,8 +68,24 @@ } }; + public static final boolean isWithinEnqueue() { + // It's possible this can be called before the has completed so check for null + return withinEnqueue == null || withinEnqueue.get(); + } + + public static class BeginEnqueue implements Closeable { + public BeginEnqueue() { + assert !withinEnqueue.get(); + withinEnqueue.set(Boolean.TRUE); + } + + public void close() { + withinEnqueue.set(Boolean.FALSE); + } + } + private enum CompilationStatus { - Queued, Running + Queued, Running, Finished } private final HotSpotBackend backend; @@ -71,12 +96,20 @@ private StructuredGraph graph; - public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, int id) { - assert id >= 0; + /** + * A long representing the sequence number of this task. Used for sorting the compile queue. + */ + private long taskId; + + private boolean blocking; + + public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) { this.backend = backend; this.method = method; this.entryBCI = entryBCI; - this.id = id; + this.id = backend.getRuntime().getCompilerToVM().allocateCompileId(method, entryBCI); + this.blocking = blocking; + this.taskId = uniqueTaskIds.incrementAndGet(); this.status = new AtomicReference<>(CompilationStatus.Queued); } @@ -101,10 +134,43 @@ method.setCurrentTask(null); } withinEnqueue.set(Boolean.TRUE); + status.set(CompilationStatus.Finished); + synchronized (this) { + notifyAll(); + } } } /** + * Block waiting till the compilation completes. + */ + public synchronized void block() { + while (status.get() != CompilationStatus.Finished) { + try { + wait(); + } catch (InterruptedException e) { + // Ignore and retry + } + } + } + + /** + * Sort blocking tasks before non-blocking ones and then by lowest taskId within the group. + */ + public int compareTo(Object o) { + if (!(o instanceof CompilationTask)) { + return 1; + } + CompilationTask task2 = (CompilationTask) o; + if (this.blocking != task2.blocking) { + // Blocking CompilationTasks are always higher than CompilationTasks + return task2.blocking ? 1 : -1; + } + // Within the two groups sort by sequence id, so they are processed in insertion order. + return this.taskId > task2.taskId ? 1 : -1; + } + + /** * Time spent in compilation. */ public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); @@ -179,6 +245,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); @@ -203,7 +276,7 @@ } stats.finish(method); } catch (BailoutException bailout) { - Debug.metric("Bailouts").increment(); + BAILOUTS.increment(); if (ExitVMOnBailout.getValue()) { TTY.cachedOut.println(MetaUtil.format("Bailout in %H.%n(%p)", method)); bailout.printStackTrace(TTY.cachedOut); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Wed Mar 05 19:40:15 2014 -0800 @@ -39,9 +39,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.HotSpotOptions.OptionConsumer; -import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.options.*; import com.oracle.graal.options.OptionValue.OverrideScope; import com.oracle.graal.phases.tiers.*; @@ -147,7 +145,6 @@ // Some runtime instances we need. private final HotSpotGraalRuntime runtime = runtime(); - private final VMToCompilerImpl vmToCompiler = (VMToCompilerImpl) runtime.getVMToCompiler(); /** List of Zip/Jar files to compile (see {@link #CompileTheWorldClasspath}. */ private final String files; @@ -320,8 +317,8 @@ class CTWCompilationTask extends CompilationTask { - CTWCompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int id) { - super(backend, method, INVOCATION_ENTRY_BCI, id); + CTWCompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method) { + super(backend, method, INVOCATION_ENTRY_BCI, false); } /** @@ -351,9 +348,8 @@ try { long start = System.currentTimeMillis(); - int id = vmToCompiler.allocateCompileTaskId(method, StructuredGraph.INVOCATION_ENTRY_BCI); HotSpotBackend backend = runtime.getHostBackend(); - CompilationTask task = new CTWCompilationTask(backend, method, id); + CompilationTask task = new CTWCompilationTask(backend, method); task.runCompilation(false); compileTime += (System.currentTimeMillis() - start); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java Wed Mar 05 19:40:15 2014 -0800 @@ -31,6 +31,7 @@ import com.oracle.graal.api.code.CompilationResult.Data; import com.oracle.graal.api.code.CompilationResult.DataPatch; import com.oracle.graal.api.code.CompilationResult.ExceptionHandler; +import com.oracle.graal.api.code.CompilationResult.Infopoint; import com.oracle.graal.api.code.CompilationResult.JumpTable; import com.oracle.graal.api.code.CompilationResult.Mark; import com.oracle.graal.api.code.CompilationResult.Site; @@ -195,6 +196,24 @@ comments[i] = new Comment(annotation.position, text); } } + assert validateFrames(); + } + + /** + * Ensure that all the frames passed into HotSpot are properly formatted with an empty or + * illegal slot following double word slots. + */ + private boolean validateFrames() { + for (Site site : sites) { + if (site instanceof Infopoint) { + Infopoint info = (Infopoint) site; + if (info.debugInfo != null) { + BytecodeFrame frame = info.debugInfo.frame(); + assert frame == null || frame.validateFormat(); + } + } + } + return true; } static class SiteComparator implements Comparator { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Wed Mar 05 19:40:15 2014 -0800 @@ -181,10 +181,8 @@ } protected/* final */CompilerToVM compilerToVm; - protected/* final */CompilerToGPU compilerToGpu; protected/* final */VMToCompiler vmToCompiler; - private HotSpotRuntimeInterpreterInterface runtimeInterpreterInterface; private volatile HotSpotGraphCache cache; protected final HotSpotVMConfig config; @@ -211,11 +209,9 @@ private HotSpotGraalRuntime() { CompilerToVM toVM = new CompilerToVMImpl(); - CompilerToGPU toGPU = new CompilerToGPUImpl(); VMToCompiler toCompiler = new VMToCompilerImpl(this); compilerToVm = toVM; - compilerToGpu = toGPU; vmToCompiler = toCompiler; config = new HotSpotVMConfig(compilerToVm); @@ -237,7 +233,7 @@ String hostArchitecture = config.getHostArchitectureName(); hostBackend = registerBackend(findFactory(hostArchitecture).createBackend(this, null)); - String[] gpuArchitectures = getGPUArchitectureNames(); + String[] gpuArchitectures = getGPUArchitectureNames(compilerToVm); for (String arch : gpuArchitectures) { HotSpotBackendFactory factory = findFactory(arch); if (factory == null) { @@ -271,15 +267,12 @@ /** * Gets the names of the supported GPU architectures for the purpose of finding the - * corresponding {@linkplain HotSpotBackendFactory backend} objects. This method first looks for - * a comma or {@link java.io.File#pathSeparatorChar} separated list of names in the - * {@value #GRAAL_GPU_ISALIST_PROPERTY_NAME} system property. If this property is not set, then - * the GPU native support code is queried. + * corresponding {@linkplain HotSpotBackendFactory backend} objects. */ - private static String[] getGPUArchitectureNames() { - String gpuList = System.getProperty(GRAAL_GPU_ISALIST_PROPERTY_NAME); - if (gpuList != null && !gpuList.isEmpty()) { - String[] gpus = gpuList.split("[,:]"); + private static String[] getGPUArchitectureNames(CompilerToVM c2vm) { + String gpuList = c2vm.getGPUs(); + if (!gpuList.isEmpty()) { + String[] gpus = gpuList.split(","); return gpus; } return new String[0]; @@ -320,10 +313,6 @@ return vmToCompiler; } - public CompilerToGPU getCompilerToGPU() { - return compilerToGpu; - } - /** * Converts a name to a Java type. * @@ -351,18 +340,11 @@ // Resolve the type in the VM. final long metaspaceKlass = compilerToVm.lookupType(name, accessingClass, eagerResolve); if (metaspaceKlass == 0) { - return vmToCompiler.createUnresolvedJavaType(name); + return HotSpotUnresolvedJavaType.create(name); } return HotSpotResolvedObjectType.fromMetaspaceKlass(metaspaceKlass); } - public HotSpotRuntimeInterpreterInterface getRuntimeInterpreterInterface() { - if (runtimeInterpreterInterface == null) { - runtimeInterpreterInterface = new HotSpotRuntimeInterpreterInterface(getHostProviders().getMetaAccess()); - } - return runtimeInterpreterInterface; - } - public HotSpotProviders getHostProviders() { return getHostBackend().getProviders(); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.hotspot.HotSpotReplacementsImpl.*; @@ -37,7 +38,7 @@ /** * Common functionality of HotSpot host backends. */ -public abstract class HotSpotHostBackend extends HotSpotBackend { +public abstract class HotSpotHostBackend extends HotSpotBackend implements HostBackend { /** * This will be 0 if stack banging is disabled. diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Wed Mar 05 19:40:15 2014 -0800 @@ -58,6 +58,11 @@ if (!config.usePopCountInstruction) { return null; } + } else if (substituteMethod.getName().equals("numberOfLeadingZeros")) { + if (config.useCountLeadingZerosInstruction) { + // bsr is lzcnt + return null; + } } } else if (substituteClass == CRC32Substitutions.class) { if (!config.useCRC32Intrinsics) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeInterpreterInterface.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeInterpreterInterface.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot; - -import static com.oracle.graal.graph.FieldIntrospection.*; - -import java.lang.reflect.*; - -import sun.misc.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.meta.*; - -public class HotSpotRuntimeInterpreterInterface { - - private final MetaAccessProvider metaAccess; - - public HotSpotRuntimeInterpreterInterface(MetaAccessProvider metaProvider) { - this.metaAccess = metaProvider; - } - - public Class getMirror(ResolvedJavaType type) { - return ((HotSpotResolvedJavaType) type).mirror(); - } - - public native Object invoke(ResolvedJavaMethod method, Object... args); - - public void monitorEnter(Object value) { - nullCheck(value); - unsafe.monitorEnter(value); - } - - public void monitorExit(Object value) { - nullCheck(value); - unsafe.monitorExit(value); - } - - public Object newObject(ResolvedJavaType type) throws InstantiationException { - return unsafe.allocateInstance(getMirror(type)); - } - - public Object getFieldObject(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getObjectVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getObject(resolveBase(base, field), offset); - } - } - - public boolean getFieldBoolean(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getBooleanVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getBoolean(resolveBase(base, field), offset); - } - } - - public byte getFieldByte(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getByteVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getByte(resolveBase(base, field), offset); - } - } - - public char getFieldChar(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getCharVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getChar(resolveBase(base, field), offset); - } - } - - public short getFieldShort(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getShortVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getShort(resolveBase(base, field), offset); - } - } - - public int getFieldInt(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getIntVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getInt(resolveBase(base, field), offset); - } - } - - public long getFieldLong(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getLongVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getLong(resolveBase(base, field), offset); - } - } - - public double getFieldDouble(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getDoubleVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getDouble(resolveBase(base, field), offset); - } - } - - public float getFieldFloat(Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - return unsafe.getFloatVolatile(resolveBase(base, field), offset); - } else { - return unsafe.getFloat(resolveBase(base, field), offset); - } - } - - public void setFieldObject(Object value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putObjectVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putObject(resolveBase(base, field), offset, value); - } - } - - public void setFieldInt(int value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putIntVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putInt(resolveBase(base, field), offset, value); - } - } - - public void setFieldFloat(float value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putFloatVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putFloat(resolveBase(base, field), offset, value); - } - } - - public void setFieldDouble(double value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putDouble(resolveBase(base, field), offset, value); - } - } - - public void setFieldLong(long value, Object base, ResolvedJavaField field) { - long offset = resolveOffset(field); - if (isVolatile(field)) { - unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); - } else { - unsafe.putDouble(resolveBase(base, field), offset, value); - } - } - - public byte getArrayByte(long index, Object array) { - checkArray(array, index); - return unsafe.getByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index); - } - - public char getArrayChar(long index, Object array) { - checkArray(array, index); - return unsafe.getChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index); - } - - public short getArrayShort(long index, Object array) { - checkArray(array, index); - return unsafe.getShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index); - } - - public int getArrayInt(long index, Object array) { - checkArray(array, index); - return unsafe.getInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index); - } - - public long getArrayLong(long index, Object array) { - checkArray(array, index); - return unsafe.getLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index); - } - - public double getArrayDouble(long index, Object array) { - checkArray(array, index); - return unsafe.getDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index); - } - - public float getArrayFloat(long index, Object array) { - checkArray(array, index); - return unsafe.getFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index); - } - - public Object getArrayObject(long index, Object array) { - checkArray(array, index); - return unsafe.getObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index); - } - - public void setArrayByte(byte value, long index, Object array) { - checkArray(array, index); - if (array instanceof boolean[]) { - checkArrayType(array, boolean.class); - } else { - checkArrayType(array, byte.class); - } - unsafe.putByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index, value); - } - - public void setArrayChar(char value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, char.class); - unsafe.putChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index, value); - } - - public void setArrayShort(short value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, short.class); - unsafe.putShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index, value); - } - - public void setArrayInt(int value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, int.class); - unsafe.putInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index, value); - } - - public void setArrayLong(long value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, long.class); - unsafe.putLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index, value); - } - - public void setArrayFloat(float value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, float.class); - unsafe.putFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index, value); - } - - public void setArrayDouble(double value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, double.class); - unsafe.putDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index, value); - } - - public void setArrayObject(Object value, long index, Object array) { - checkArray(array, index); - checkArrayType(array, value != null ? value.getClass() : null); - unsafe.putObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index, value); - } - - private static void nullCheck(Object value) { - if (value == null) { - throw new NullPointerException(); - } - } - - private void checkArrayType(Object array, Class arrayType) { - if (arrayType == null) { - return; - } - ResolvedJavaType type = metaAccess.lookupJavaType(array.getClass()).getComponentType(); - if (!getMirror(type).isAssignableFrom(arrayType)) { - throw new ArrayStoreException(arrayType.getName()); - } - } - - private void checkArray(Object array, long index) { - nullCheck(array); - ResolvedJavaType type = metaAccess.lookupJavaType(array.getClass()); - if (!type.isArray()) { - throw new ArrayStoreException(array.getClass().getName()); - } - if (index < 0 || index >= arrayLength(array)) { - throw new ArrayIndexOutOfBoundsException((int) index); - } - } - - private static int arrayLength(Object array) { - assert array != null; - return Array.getLength(array); - } - - private static boolean isVolatile(ResolvedJavaField field) { - return Modifier.isVolatile(field.getModifiers()); - } - - private static long resolveOffset(ResolvedJavaField field) { - return ((HotSpotResolvedJavaField) field).offset(); - } - - private Object resolveBase(Object base, ResolvedJavaField field) { - Object accessorBase = base; - if (accessorBase == null) { - accessorBase = getMirror(field.getDeclaringClass()); - } - return accessorBase; - } -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Mar 05 19:40:15 2014 -0800 @@ -29,6 +29,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.meta.*; /** * Used to access native configuration details. @@ -39,12 +40,19 @@ private static final long serialVersionUID = -4744897993263044184L; - private static boolean containsString(String[] array, String item) { - if (array == null) { - return false; + /** + * Determines if the current architecture is included in a given architecture set specification. + * + * @param currentArch + * @param archsSpecification specifies a set of architectures. A zero length value implies all + * architectures. + */ + private static boolean isRequired(String currentArch, String[] archsSpecification) { + if (archsSpecification.length == 0) { + return true; } - for (String arch : array) { - if (arch.equals(item)) { + for (String arch : archsSpecification) { + if (arch.equals(currentArch)) { return true; } } @@ -90,7 +98,7 @@ String type = annotation.type(); VMFields.Field entry = vmFields.get(name); if (entry == null) { - if (annotation.optional() || !containsString(annotation.archs(), currentArch)) { + if (annotation.optional() || !isRequired(currentArch, annotation.archs())) { continue; } throw new IllegalArgumentException("field not found: " + name); @@ -135,11 +143,10 @@ String name = annotation.name(); AbstractConstant entry = vmConstants.get(name); if (entry == null) { - if (!containsString(annotation.archs(), currentArch)) { + if (!isRequired(currentArch, annotation.archs())) { continue; - } else { - throw new IllegalArgumentException("constant not found: " + name); } + throw new IllegalArgumentException("constant not found: " + name); } setField(f, entry.getValue()); } else if (f.isAnnotationPresent(HotSpotVMFlag.class)) { @@ -147,11 +154,11 @@ String name = annotation.name(); Flags.Flag entry = flags.get(name); if (entry == null) { - if (annotation.optional() || !containsString(annotation.archs(), currentArch)) { + if (!isRequired(currentArch, annotation.archs())) { continue; - } else { - throw new IllegalArgumentException("flag not found: " + name); } + throw new IllegalArgumentException("flag not found: " + name); + } setField(f, entry.getValue()); } @@ -282,17 +289,17 @@ public String getTypeName() { long typeNameAddress = unsafe.getAddress(entryAddress + gHotSpotVMStructEntryTypeNameOffset); - return readCStringAsString(typeNameAddress); + return readCString(typeNameAddress); } public String getFieldName() { long fieldNameAddress = unsafe.getAddress(entryAddress + gHotSpotVMStructEntryFieldNameOffset); - return readCStringAsString(fieldNameAddress); + return readCString(fieldNameAddress); } public String getTypeString() { long typeStringAddress = unsafe.getAddress(entryAddress + gHotSpotVMStructEntryTypeStringOffset); - return readCStringAsString(typeStringAddress); + return readCString(typeStringAddress); } public boolean isStatic() { @@ -398,12 +405,12 @@ public String getTypeName() { long typeNameAddress = unsafe.getAddress(entryAddress + gHotSpotVMTypeEntryTypeNameOffset); - return readCStringAsString(typeNameAddress); + return readCString(typeNameAddress); } public String getSuperclassName() { long superclassNameAddress = unsafe.getAddress(entryAddress + gHotSpotVMTypeEntrySuperclassNameOffset); - return readCStringAsString(superclassNameAddress); + return readCString(superclassNameAddress); } public boolean isOopType() { @@ -444,7 +451,7 @@ public String getName() { long nameAddress = unsafe.getAddress(address + nameOffset); - return readCStringAsString(nameAddress); + return readCString(nameAddress); } public abstract long getValue(); @@ -639,12 +646,12 @@ public String getType() { long typeAddress = unsafe.getAddress(entryAddress + typeOffset); - return readCStringAsString(typeAddress); + return readCString(typeAddress); } public String getName() { long nameAddress = unsafe.getAddress(entryAddress + nameOffset); - return readCStringAsString(nameAddress); + return readCString(nameAddress); } public long getAddr() { @@ -663,7 +670,7 @@ return Double.valueOf(unsafe.getDouble(getAddr())); case "ccstr": case "ccstrlist": - return readCStringAsString(getAddr()); + return readCString(getAddr()); default: throw GraalInternalError.shouldNotReachHere(getType()); } @@ -676,24 +683,6 @@ } } - /** - * Read a null-terminated C string from memory and convert it to a Java String. - */ - private static String readCStringAsString(long address) { - if (address == 0) { - return null; - } - StringBuffer sb = new StringBuffer(); - for (int i = 0;; i++) { - char c = (char) unsafe.getByte(address + i); - if (c == 0) { - break; - } - sb.append(c); - } - return sb.toString(); - } - // os information, register layout, code generation, ... @HotSpotVMConstant(name = "ASSERT") @Stable public boolean cAssertions; public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); @@ -701,7 +690,7 @@ @HotSpotVMFlag(name = "CodeEntryAlignment") @Stable public int codeEntryAlignment; @HotSpotVMFlag(name = "VerifyOops") @Stable public boolean verifyOops; @HotSpotVMFlag(name = "CITime") @Stable public boolean ciTime; - @HotSpotVMFlag(name = "CITimeEach", optional = true) @Stable public boolean ciTimeEach; + @HotSpotVMFlag(name = "CITimeEach") @Stable public boolean ciTimeEach; @HotSpotVMFlag(name = "CompileThreshold") @Stable public long compileThreshold; @HotSpotVMFlag(name = "CompileTheWorld") @Stable public boolean compileTheWorld; @HotSpotVMFlag(name = "CompileTheWorldStartAt") @Stable public int compileTheWorldStartAt; @@ -712,11 +701,12 @@ @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining; @HotSpotVMFlag(name = "GraalUseFastLocking") @Stable public boolean useFastLocking; @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable; + @HotSpotVMFlag(name = "GPUOffload") @Stable public boolean gpuOffload; @HotSpotVMFlag(name = "UseTLAB") @Stable public boolean useTLAB; @HotSpotVMFlag(name = "UseBiasedLocking") @Stable public boolean useBiasedLocking; @HotSpotVMFlag(name = "UsePopCountInstruction") @Stable public boolean usePopCountInstruction; - @HotSpotVMFlag(name = "UseCountLeadingZerosInstruction", optional = true) @Stable public boolean useCountLeadingZerosInstruction; + @HotSpotVMFlag(name = "UseCountLeadingZerosInstruction", archs = {"amd64"}) @Stable public boolean useCountLeadingZerosInstruction; @HotSpotVMFlag(name = "UseAESIntrinsics") @Stable public boolean useAESIntrinsics; @HotSpotVMFlag(name = "UseCRC32Intrinsics") @Stable public boolean useCRC32Intrinsics; @HotSpotVMFlag(name = "UseG1GC") @Stable public boolean useG1GC; @@ -798,6 +788,43 @@ @HotSpotVMField(name = "Klass::_secondary_super_cache", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySuperCacheOffset; @HotSpotVMField(name = "Klass::_secondary_supers", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySupersOffset; + /** + * The offset of the _java_mirror field (of type {@link Class}) in a Klass. + */ + @HotSpotVMField(name = "Klass::_java_mirror", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int classMirrorOffset; + + @HotSpotVMField(name = "Klass::_super", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int klassSuperKlassOffset; + @HotSpotVMField(name = "Klass::_modifier_flags", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassModifierFlagsOffset; + @HotSpotVMField(name = "Klass::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int klassAccessFlagsOffset; + @HotSpotVMField(name = "Klass::_layout_helper", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassLayoutHelperOffset; + @HotSpotVMField(name = "Klass::_layout_helper", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassInstanceSizeOffset; + + @HotSpotVMConstant(name = "Klass::_lh_neutral_value") @Stable public int klassLayoutHelperNeutralValue; + @HotSpotVMConstant(name = "Klass::_lh_instance_slow_path_bit") @Stable public int klassLayoutHelperInstanceSlowPathBit; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_shift") @Stable public int layoutHelperLog2ElementSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_mask") @Stable public int layoutHelperLog2ElementSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_element_type_shift") @Stable public int layoutHelperElementTypeShift; + @HotSpotVMConstant(name = "Klass::_lh_element_type_mask") @Stable public int layoutHelperElementTypeMask; + @HotSpotVMConstant(name = "Klass::_lh_header_size_shift") @Stable public int layoutHelperHeaderSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_header_size_mask") @Stable public int layoutHelperHeaderSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_shift") @Stable public int layoutHelperArrayTagShift; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_type_value") @Stable public int layoutHelperArrayTagTypeValue; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_obj_value") @Stable public int layoutHelperArrayTagObjectValue; + + /** + * This filters out the bit that differentiates a type array from an object array. + */ + public int layoutHelperElementTypePrimitiveInPlace() { + return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift; + } + + /** + * Bit pattern in the klass layout helper that can be used to identify arrays. + */ + public final int arrayKlassLayoutHelperIdentifier = 0x80000000; + + @HotSpotVMField(name = "ArrayKlass::_component_mirror", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayKlassComponentMirrorOffset; + @HotSpotVMType(name = "vtableEntry", get = HotSpotVMType.Type.SIZE) @Stable public int vtableEntrySize; @HotSpotVMField(name = "vtableEntry::_method", type = "Method*", get = HotSpotVMField.Type.OFFSET) @Stable public int vtableEntryMethodOffset; @Stable public int instanceKlassVtableStartOffset; @@ -809,18 +836,34 @@ @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1LengthOffset; @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1DataOffset; + @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU2DataOffset; @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayLengthOffset; @HotSpotVMField(name = "Array::_data[0]", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayBaseOffset; @HotSpotVMField(name = "InstanceKlass::_source_file_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int klassSourceFileNameIndexOffset; @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int klassStateOffset; @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset; + @HotSpotVMField(name = "InstanceKlass::_fields", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset; @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int klassStateLinked; @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int klassStateFullyInitialized; @HotSpotVMField(name = "ObjArrayKlass::_element_klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayClassElementOffset; + @HotSpotVMConstant(name = "FieldInfo::access_flags_offset") @Stable public int fieldInfoAccessFlagsOffset; + @HotSpotVMConstant(name = "FieldInfo::name_index_offset") @Stable public int fieldInfoNameIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::signature_index_offset") @Stable public int fieldInfoSignatureIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::initval_index_offset") @Stable public int fieldInfoInitvalIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::low_packed_offset") @Stable public int fieldInfoLowPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::high_packed_offset") @Stable public int fieldInfoHighPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::field_slots") @Stable public int fieldInfoFieldSlots; + + @HotSpotVMConstant(name = "FIELDINFO_TAG_SIZE") @Stable public int fieldInfoTagSize; + + @HotSpotVMConstant(name = "JVM_ACC_FIELD_INTERNAL") @Stable public int jvmAccFieldInternal; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_STABLE") @Stable public int jvmAccFieldStable; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE") @Stable public int jvmAccFieldHasGenericSignature; + @HotSpotVMField(name = "Thread::_tlab", type = "ThreadLocalAllocBuffer", get = HotSpotVMField.Type.OFFSET) @Stable public int threadTlabOffset; @HotSpotVMField(name = "JavaThread::_anchor", type = "JavaFrameAnchor", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadAnchorOffset; @@ -832,7 +875,36 @@ @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; - @HotSpotVMConstant(name = "GRAAL_COUNTERS_SIZE") @Stable public int graalCountersSize; + /** + * An invalid value for {@link #rtldDefault}. + */ + public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE; + + /** + * 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; /** * This field is used to pass exception objects into and out of the runtime system during @@ -872,6 +944,8 @@ return javaThreadAnchorOffset + javaFrameAnchorFlagsOffset; } + @HotSpotVMConstant(name = "frame::arg_reg_save_area_bytes", archs = {"amd64"}) @Stable public int runtimeCallStackSize; + @HotSpotVMField(name = "PtrQueue::_active", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueActiveOffset; @HotSpotVMField(name = "PtrQueue::_buf", type = "void**", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueBufferOffset; @HotSpotVMField(name = "PtrQueue::_index", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueIndexOffset; @@ -971,6 +1045,8 @@ @HotSpotVMField(name = "ConstantPool::_pool_holder", type = "InstanceKlass*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolHolderOffset; @HotSpotVMField(name = "ConstantPool::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolLengthOffset; + @HotSpotVMConstant(name = "ConstantPool::CPCACHE_INDEX_TAG") @Stable public int constantPoolCpCacheIndexTag; + @HotSpotVMConstant(name = "JVM_CONSTANT_Utf8") @Stable public int jvmConstantUtf8; @HotSpotVMConstant(name = "JVM_CONSTANT_Integer") @Stable public int jvmConstantInteger; @HotSpotVMConstant(name = "JVM_CONSTANT_Long") @Stable public int jvmConstantLong; @@ -989,11 +1065,26 @@ @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; + + @HotSpotVMType(name = "Symbol*", get = HotSpotVMType.Type.SIZE) @Stable public int symbolPointerSize; @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; + @HotSpotVMField(name = "vmSymbols::_symbols[0]", type = "Symbol*", get = HotSpotVMField.Type.ADDRESS) @Stable public long vmSymbolsSymbols; + @HotSpotVMConstant(name = "vmSymbols::FIRST_SID") @Stable public int vmSymbolsFirstSID; + @HotSpotVMConstant(name = "vmSymbols::SID_LIMIT") @Stable public int vmSymbolsSIDLimit; + @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int klassHasFinalizerFlag; + // Modifier.SYNTHETIC is not public so we get it via vmStructs. + @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int syntheticFlag; + + /** + * @see HotSpotResolvedObjectType#createField + */ + @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; + /** * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value * are allowed to look like (respectively) the high or low bits of a real oop. @@ -1071,40 +1162,6 @@ return javaThreadSatbMarkQueueOffset + ptrQueueBufferOffset; } - /** - * The offset of the _java_mirror field (of type {@link Class}) in a Klass. - */ - @HotSpotVMField(name = "Klass::_java_mirror", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int classMirrorOffset; - - @HotSpotVMConstant(name = "frame::arg_reg_save_area_bytes", archs = {"amd64"}) @Stable public int runtimeCallStackSize; - - @HotSpotVMField(name = "Klass::_super", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int klassSuperKlassOffset; - @HotSpotVMField(name = "Klass::_modifier_flags", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassModifierFlagsOffset; - @HotSpotVMField(name = "Klass::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int klassAccessFlagsOffset; - @HotSpotVMField(name = "Klass::_layout_helper", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassLayoutHelperOffset; - @HotSpotVMField(name = "Klass::_layout_helper", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassInstanceSizeOffset; - - @HotSpotVMConstant(name = "Klass::_lh_neutral_value") @Stable public int klassLayoutHelperNeutralValue; - @HotSpotVMConstant(name = "Klass::_lh_instance_slow_path_bit") @Stable public int klassLayoutHelperInstanceSlowPathBit; - @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_shift") @Stable public int layoutHelperLog2ElementSizeShift; - @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_mask") @Stable public int layoutHelperLog2ElementSizeMask; - @HotSpotVMConstant(name = "Klass::_lh_element_type_shift") @Stable public int layoutHelperElementTypeShift; - @HotSpotVMConstant(name = "Klass::_lh_element_type_mask") @Stable public int layoutHelperElementTypeMask; - @HotSpotVMConstant(name = "Klass::_lh_header_size_shift") @Stable public int layoutHelperHeaderSizeShift; - @HotSpotVMConstant(name = "Klass::_lh_header_size_mask") @Stable public int layoutHelperHeaderSizeMask; - @HotSpotVMConstant(name = "Klass::_lh_array_tag_shift") @Stable public int layoutHelperArrayTagShift; - @HotSpotVMConstant(name = "Klass::_lh_array_tag_type_value") @Stable public int layoutHelperArrayTagTypeValue; - @HotSpotVMConstant(name = "Klass::_lh_array_tag_obj_value") @Stable public int layoutHelperArrayTagObjectValue; - - /** - * This filters out the bit that differentiates a type array from an object array. - */ - public int layoutHelperElementTypePrimitiveInPlace() { - return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift; - } - - @HotSpotVMField(name = "ArrayKlass::_component_mirror", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayKlassComponentMirrorOffset; - @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; @HotSpotVMField(name = "java_lang_Class::_array_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int arrayKlassOffset; @@ -1237,6 +1294,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; @@ -1267,6 +1353,8 @@ @Stable public long arithmeticTanAddress; @Stable public long loadAndClearExceptionAddress; + @Stable public int graalCountersSize; + @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone; @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck; @HotSpotVMConstant(name = "Deoptimization::Reason_range_check") @Stable public int deoptReasonRangeCheck; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConstant.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConstant.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConstant.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,7 +32,8 @@ /** * List of architectures where this constant is required. Names are derived from - * {@link HotSpotVMConfig#getHostArchitectureName()}. + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. */ String[] archs() default {}; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMField.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMField.java Wed Mar 05 19:40:15 2014 -0800 @@ -40,7 +40,8 @@ /** * List of architectures where this constant is required. Names are derived from - * {@link HotSpotVMConfig#getHostArchitectureName()}. + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. */ String[] archs() default {}; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,9 +32,8 @@ /** * List of architectures where this constant is required. Names are derived from - * {@link HotSpotVMConfig#getHostArchitectureName()}. + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. */ String[] archs() default {}; - - boolean optional() default false; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVmSymbols.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVmSymbols.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,48 @@ +/* + * 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; + +import static com.oracle.graal.graph.UnsafeAccess.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import sun.misc.*; + +/** + * Class to access the C++ {@code vmSymbols} table. + */ +public final class HotSpotVmSymbols { + + /** + * Returns the {@link HotSpotSymbol} in the {@code vmSymbols} table at position {@code index} as + * {@link String}. + * + * @param index position in the symbol table + * @return the symbol at position id + */ + public static String symbolAt(int index) { + HotSpotVMConfig config = runtime().getConfig(); + assert config.vmSymbolsFirstSID <= index && index < config.vmSymbolsSIDLimit : "index " + index + " is out of bounds"; + assert config.symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken"; + final long metaspaceSymbol = unsafe.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize); + return new HotSpotSymbol(metaspaceSymbol).asString(); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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.hotspot.bridge; - -import com.oracle.graal.api.code.InvalidInstalledCodeException; -import com.oracle.graal.hotspot.meta.HotSpotInstalledCode; - -/** - * Calls from Java into the GPU. - */ -public interface CompilerToGPU { - - /** - * Attempts to initialize and create a valid context with the GPU. - * - * @return whether the GPU context has been initialized and is valid. - */ - boolean deviceInit(); - - /** - * Attempts to detach from a valid GPU context. - * - * @return whether the GPU context has been properly disposed. - */ - boolean deviceDetach(); - - int availableProcessors(); - - /** - * Attempts to generate and return a bound function to the loaded method kernel on the GPU. - * - * @param code the text or binary values for a method kernel - * @return the value of the bound kernel in GPU space. - */ - long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException; - - Object executeExternalMethodVarargs(Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException; - - Object executeParallelMethodVarargs(int dimX, int dimY, int dimZ, Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException; - - /** - * Gets the address of the runtime function for launching a kernel function. - */ - long getLaunchKernelAddress(); -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.hotspot.bridge; - -import com.oracle.graal.api.code.InvalidInstalledCodeException; -import com.oracle.graal.hotspot.meta.HotSpotInstalledCode; - -/** - * Entries into the HotSpot GPU interface from Java code. - */ -public class CompilerToGPUImpl implements CompilerToGPU { - - public native boolean deviceInit(); - - public native long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException; - - public native boolean deviceDetach(); - - public native int availableProcessors(); - - public native Object executeExternalMethodVarargs(Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException; - - public native Object executeParallelMethodVarargs(int dimX, int dimY, int dimZ, Object[] args, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException; - - public native long getLaunchKernelAddress(); -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 CompileOracle directive may prevent compilation of methods
  • + *
  • a CompileOracle directive may prevent inlining or compilation of this methods
  • *
  • the method may have a bytecode breakpoint set
  • *
  • the method may have other bytecode features that require special handling by the VM
  • *
* - * 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: + *
    + *
  • a CompileOracle directive may forces inlining of this methods
  • + *
  • an annotation forces inlining of this method
  • + *
* * @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)}. @@ -108,15 +118,58 @@ Object lookupConstantInPool(long metaspaceConstantPool, int cpi); - JavaMethod lookupMethodInPool(long metaspaceConstantPool, int cpi, byte opcode); - - JavaType lookupTypeInPool(long metaspaceConstantPool, int cpi); + /** + * Looks up a method entry in a constant pool. If the method is resolved, then + * {@code unresolvedInfo} is unmodified. Otherwise, it contains these values: + * + *
+     *     [(Symbol*) name,
+     *      (Symbol*) signature,
+     *      (Symbol*) holderName, // only non-zero if holder == 0
+     *      (Klass*)  holder]
+     * 
+ * + * @param metaspaceConstantPool + * @param unresolvedInfo an array in which the details for an unresolved method are returned + * @return a metaspace Method for a resolved method entry otherwise 0 in which case the values + * returned in {@code unresolvedInfo} should be consulted + */ + long lookupMethodInPool(long metaspaceConstantPool, int cpi, byte opcode, long[] unresolvedInfo); - JavaField lookupFieldInPool(long metaspaceConstantPool, int cpi, byte opcode); + /** + * Looks up a class entry in a constant pool. + * + * @param metaspaceConstantPool + * @param unresolvedTypeName a 1 element array in which the name of the class is returned if + * this method returns 0 + * @return a metaspace Klass for a resolved method entry otherwise 0 in which case the value + * returned in {@code unresolvedTypeName} should be consulted + */ + long lookupTypeInPool(long metaspaceConstantPool, int cpi, long[] unresolvedTypeName); - void lookupReferencedTypeInPool(long metaspaceConstantPool, int cpi, byte opcode); + /** + * Looks up a field entry in a constant pool and attempts to resolve it. The values returned in + * {@code info} are: + * + *
+     *     [(Symbol*) name,
+     *      (Symbol*) typeName,   // only non-zero if type == 0
+     *      (Klass*)  type,
+     *      (Symbol*) holderName, // only non-zero if holder == 0
+     *      (Klass*)  holder,
+     *      (int)     flags,      // only valid if field is resolved
+     *      (int)     offset]     // only valid if field is resolved
+     * 
+ * + * @param metaspaceConstantPool + * @param info an array in which the details of the field are returned + * @return true if the field is resolved + */ + boolean lookupFieldInPool(long metaspaceConstantPool, int cpi, byte opcode, long[] info); - Object lookupAppendixInPool(long metaspaceConstantPool, int cpi, byte opcode); + void loadReferencedTypeInPool(long metaspaceConstantPool, int cpi, byte opcode); + + Object lookupAppendixInPool(long metaspaceConstantPool, int cpi); public enum CodeInstallResult { OK("ok"), DEPENDENCIES_FAILED("dependencies failed"), CACHE_FULL("code cache is full"), CODE_TOO_LARGE("code is too large"); @@ -194,8 +247,6 @@ long resolveMethod(HotSpotResolvedObjectType klass, String name, String signature); - HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedObjectType klass); - long getClassInitializer(HotSpotResolvedObjectType klass); boolean hasFinalizableSubclass(HotSpotResolvedObjectType klass); @@ -258,8 +309,17 @@ */ long[] collectCounters(); + boolean isMature(long metaspaceMethodData); + /** * Generate a unique id to identify the result of the compile. */ int allocateCompileId(HotSpotResolvedJavaMethod method, int entryBCI); + + /** + * Gets the names of the supported GPU architectures. + * + * @return a comma separated list of names + */ + String getGPUs(); } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,7 +24,6 @@ package com.oracle.graal.hotspot.bridge; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; @@ -53,9 +52,6 @@ public native boolean hasBalancedMonitors(long metaspaceMethod); @Override - public native boolean isMethodCompilable(long metaspaceMethod); - - @Override public native long findUniqueConcreteMethod(long metaspaceMethod); @Override @@ -68,19 +64,19 @@ public native Object lookupConstantInPool(long metaspaceConstantPool, int cpi); @Override - public native JavaMethod lookupMethodInPool(long metaspaceConstantPool, int cpi, byte opcode); + public native long lookupMethodInPool(long metaspaceConstantPool, int cpi, byte opcode, long[] unresolvedInfo); @Override - public native JavaType lookupTypeInPool(long metaspaceConstantPool, int cpi); + public native long lookupTypeInPool(long metaspaceConstantPool, int cpi, long[] unresolvedTypeName); @Override - public native JavaField lookupFieldInPool(long metaspaceConstantPool, int cpi, byte opcode); + public native boolean lookupFieldInPool(long metaspaceConstantPool, int cpi, byte opcode, long[] info); @Override - public native void lookupReferencedTypeInPool(long metaspaceConstantPool, int cpi, byte opcode); + public native void loadReferencedTypeInPool(long metaspaceConstantPool, int cpi, byte opcode); @Override - public native Object lookupAppendixInPool(long metaspaceConstantPool, int cpi, byte opcode); + public native Object lookupAppendixInPool(long metaspaceConstantPool, int cpi); @Override public native void initializeConfiguration(HotSpotVMConfig config); @@ -95,9 +91,6 @@ public native void initializeMethod(long metaspaceMethod, HotSpotResolvedJavaMethod method); @Override - public native HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedObjectType klass); - - @Override public native long getClassInitializer(HotSpotResolvedObjectType klass); @Override @@ -169,5 +162,13 @@ public native long[] collectCounters(); + public native boolean isMature(long method); + 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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Wed Mar 05 19:40:15 2014 -0800 @@ -25,8 +25,6 @@ import java.io.*; -import com.oracle.graal.api.meta.*; - /** * Calls from HotSpot into Java. */ @@ -47,24 +45,4 @@ void compileTheWorld() throws Throwable; PrintStream log(); - - JavaMethod createUnresolvedJavaMethod(String name, String signature, JavaType holder); - - JavaField createJavaField(JavaType holder, String name, JavaType type, int offset, int flags, boolean internal); - - ResolvedJavaMethod createResolvedJavaMethod(JavaType holder, long metaspaceMethod); - - JavaType createPrimitiveJavaType(int basicType); - - JavaType createUnresolvedJavaType(String name); - - /** - * Creates a resolved Java type. - * - * @param javaMirror the {@link Class} mirror - * @return the resolved type associated with {@code javaMirror} which may not be the type - * instantiated by this call in the case of another thread racing to create the same - * type - */ - ResolvedJavaType createResolvedJavaType(Class javaMirror); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,6 +33,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.CompilerThreadFactory.CompilerThread; import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; @@ -83,7 +84,41 @@ private final HotSpotGraalRuntime runtime; - private ThreadPoolExecutor compileQueue; + private Queue compileQueue; + + /** + * Wrap access to the thread pool to ensure that {@link CompilationTask#isWithinEnqueue} state + * is in the proper state. + */ + static class Queue { + private ThreadPoolExecutor executor; + + Queue(CompilerThreadFactory factory) { + executor = new ThreadPoolExecutor(Threads.getValue(), Threads.getValue(), 0L, TimeUnit.MILLISECONDS, new PriorityBlockingQueue(), factory); + } + + public long getCompletedTaskCount() { + try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) { + // Don't allow new enqueues while reading the state of queue. + return executor.getCompletedTaskCount(); + } + } + + public void execute(CompilationTask task) { + // The caller is expected to have set the within enqueue state. + assert CompilationTask.isWithinEnqueue(); + executor.execute(task); + } + + public void shutdown() throws InterruptedException { + assert CompilationTask.isWithinEnqueue(); + executor.shutdown(); + if (Debug.isEnabled() && Dump.getValue() != null) { + // Wait 2 seconds to flush out all graph dumps that may be of interest + executor.awaitTermination(2, TimeUnit.SECONDS); + } + } + } private volatile boolean bootstrapRunning; @@ -95,10 +130,6 @@ this.runtime = runtime; } - public int allocateCompileTaskId(HotSpotResolvedJavaMethod method, int entryBCI) { - return runtime.getCompilerToVM().allocateCompileId(method, entryBCI); - } - public void startCompiler(boolean bootstrapEnabled) throws Throwable { FastNodeClassRegistry.initialize(); @@ -157,7 +188,7 @@ return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null; } }); - compileQueue = new ThreadPoolExecutor(Threads.getValue(), Threads.getValue(), 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); + compileQueue = new Queue(factory); // Create queue status printing thread. if (PrintQueue.getValue()) { @@ -251,14 +282,8 @@ // Compile until the queue is empty. int z = 0; while (true) { - try { - assert !CompilationTask.withinEnqueue.get(); - CompilationTask.withinEnqueue.set(Boolean.TRUE); - if (compileQueue.getCompletedTaskCount() >= Math.max(3, compileQueue.getTaskCount())) { - break; - } - } finally { - CompilationTask.withinEnqueue.set(Boolean.FALSE); + if (compileQueue.getCompletedTaskCount() >= Math.max(3, compileQueue.getCompletedTaskCount())) { + break; } Thread.sleep(100); @@ -317,30 +342,18 @@ compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, false); } - private static void shutdownCompileQueue(ThreadPoolExecutor queue) throws InterruptedException { - if (queue != null) { - queue.shutdown(); - if (Debug.isEnabled() && Dump.getValue() != null) { - // Wait 2 seconds to flush out all graph dumps that may be of interest - queue.awaitTermination(2, TimeUnit.SECONDS); - } - } - } - public void shutdownCompiler() throws Exception { - try { - assert !CompilationTask.withinEnqueue.get(); - CompilationTask.withinEnqueue.set(Boolean.TRUE); + try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) { // We have to use a privileged action here because shutting down the compiler might be // called from user code which very likely contains unprivileged frames. AccessController.doPrivileged(new PrivilegedExceptionAction() { public Void run() throws Exception { - shutdownCompileQueue(compileQueue); + if (compileQueue != null) { + compileQueue.shutdown(); + } return null; } }); - } finally { - CompilationTask.withinEnqueue.set(Boolean.FALSE); } printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false); @@ -540,7 +553,7 @@ return; } - if (CompilationTask.withinEnqueue.get()) { + if (CompilationTask.isWithinEnqueue()) { // This is required to avoid deadlocking a compiler thread. The issue is that a // java.util.concurrent.BlockingQueue is used to implement the compilation worker // queues. If a compiler thread triggers a compilation, then it may be blocked trying @@ -548,112 +561,29 @@ return; } - CompilationTask.withinEnqueue.set(Boolean.TRUE); - try { + // Don't allow blocking compiles from CompilerThreads + boolean block = blocking && !(Thread.currentThread() instanceof CompilerThread); + try (CompilationTask.BeginEnqueue beginEnqueue = new CompilationTask.BeginEnqueue()) { if (method.tryToQueueForCompilation()) { assert method.isQueuedForCompilation(); - int id = allocateCompileTaskId(method, entryBCI); HotSpotBackend backend = runtime.getHostBackend(); - CompilationTask task = new CompilationTask(backend, method, entryBCI, id); + CompilationTask task = new CompilationTask(backend, method, entryBCI, block); - if (blocking) { - task.runCompilation(true); - } else { - try { - method.setCurrentTask(task); - compileQueue.execute(task); - } catch (RejectedExecutionException e) { - // The compile queue was already shut down. + try { + method.setCurrentTask(task); + compileQueue.execute(task); + if (block) { + task.block(); } + } catch (RejectedExecutionException e) { + // The compile queue was already shut down. } } - } finally { - CompilationTask.withinEnqueue.set(Boolean.FALSE); } } @Override - public JavaMethod createUnresolvedJavaMethod(String name, String signature, JavaType holder) { - return new HotSpotMethodUnresolved(name, signature, holder); - } - - @Override - public JavaField createJavaField(JavaType holder, String name, JavaType type, int offset, int flags, boolean internal) { - if (offset != -1) { - HotSpotResolvedObjectType resolved = (HotSpotResolvedObjectType) holder; - return resolved.createField(name, type, offset, flags, internal); - } - return new HotSpotUnresolvedField(holder, name, type); - } - - @Override - public ResolvedJavaMethod createResolvedJavaMethod(JavaType holder, long metaspaceMethod) { - HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) holder; - return type.createMethod(metaspaceMethod); - } - - @Override - public ResolvedJavaType createPrimitiveJavaType(int basicType) { - Class javaClass; - switch (basicType) { - case 4: - javaClass = boolean.class; - break; - case 5: - javaClass = char.class; - break; - case 6: - javaClass = float.class; - break; - case 7: - javaClass = double.class; - break; - case 8: - javaClass = byte.class; - break; - case 9: - javaClass = short.class; - break; - case 10: - javaClass = int.class; - break; - case 11: - javaClass = long.class; - break; - case 14: - javaClass = void.class; - break; - default: - throw new IllegalArgumentException("Unknown basic type: " + basicType); - } - return HotSpotResolvedPrimitiveType.fromClass(javaClass); - } - - @Override - public HotSpotUnresolvedJavaType createUnresolvedJavaType(String name) { - int dims = 0; - int startIndex = 0; - while (name.charAt(startIndex) == '[') { - startIndex++; - dims++; - } - - // Decode name if necessary. - if (name.charAt(name.length() - 1) == ';') { - assert name.charAt(startIndex) == 'L'; - return new HotSpotUnresolvedJavaType(name, name.substring(startIndex + 1, name.length() - 1), dims); - } else { - return new HotSpotUnresolvedJavaType(HotSpotUnresolvedJavaType.getFullName(name, dims), name, dims); - } - } - - @Override - public ResolvedJavaType createResolvedJavaType(Class javaMirror) { - return HotSpotResolvedObjectType.fromClass(javaMirror); - } - - @Override public PrintStream log() { return log; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Mar 05 19:40:15 2014 -0800 @@ -107,7 +107,7 @@ public static int getIndex(DynamicCounterNode counter) { if (!enabled) { - throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled"); + throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName()); } String name = counter.getName(); String group = counter.getGroup(); @@ -332,12 +332,15 @@ if (index >= config.graalCountersSize) { throw new GraalInternalError("too many counters, reduce number of counters or increase GRAAL_COUNTERS_SIZE (current value: " + config.graalCountersSize + ")"); } - ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset + Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph); - ReadNode read = graph.add(new ReadNode(thread, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); - IntegerAddNode add = graph.unique(new IntegerAddNode(Kind.Long, read, counter.getIncrement())); - WriteNode write = graph.add(new WriteNode(thread, add, location, BarrierType.NONE, false)); + ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset, graph); + ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false)); + ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph); + ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); + IntegerAddNode add = graph.unique(new IntegerAddNode(StampFactory.forKind(Kind.Long), read, counter.getIncrement())); + WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false)); graph.addBeforeFixed(counter, thread); + graph.addBeforeFixed(counter, readArray); graph.addBeforeFixed(counter, read); graph.addBeforeFixed(counter, write); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -169,6 +169,9 @@ } public HotSpotInstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) { + if (compResult.getId() == -1) { + compResult.setId(runtime.getCompilerToVM().allocateCompileId(method, compResult.getEntryBCI())); + } HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), true); runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target.arch, method, compResult), installedCode, method.getSpeculationLog()); return logOrDump(installedCode, compResult); @@ -177,6 +180,9 @@ @Override public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog log) { HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(runtime.getCompilerToVM().allocateCompileId(hotspotMethod, compResult.getEntryBCI())); + } HotSpotInstalledCode code = new HotSpotNmethod(hotspotMethod, compResult.getName(), false); CodeInstallResult result = runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target.arch, hotspotMethod, compResult), code, log); if (result != CodeInstallResult.OK) { @@ -193,6 +199,9 @@ public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) { HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(runtime.getCompilerToVM().allocateCompileId(javaMethod, compResult.getEntryBCI())); + } HotSpotNmethod code = new HotSpotNmethod(javaMethod, compResult.getName(), false, true); HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(target.arch, javaMethod, compResult); CompilerToVM vm = runtime.getCompilerToVM(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Wed Mar 05 19:40:15 2014 -0800 @@ -47,6 +47,28 @@ } /** + * Converts a raw index from the bytecodes to a constant pool index by adding a + * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. + * + * @param rawIndex index from the bytecode + * @param opcode bytecode to convert the index for + * @return constant pool index + */ + private static int toConstantPoolIndex(int rawIndex, int opcode) { + int index; + if (opcode == Bytecodes.INVOKEDYNAMIC) { + index = rawIndex; + // See: ConstantPool::is_invokedynamic_index + assert index < 0 : "not an invokedynamic constant pool index " + index; + } else { + assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || + opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + Bytecodes.nameOf(opcode); + index = rawIndex + runtime().getConfig().constantPoolCpCacheIndexTag; + } + return index; + } + + /** * Returns the constant pool tag at index {@code index}. * * @param index constant pool index @@ -254,26 +276,82 @@ @Override public Object lookupAppendix(int cpi, int opcode) { assert Bytecodes.isInvoke(opcode); - return runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, cpi, (byte) opcode); + final int index = toConstantPoolIndex(cpi, opcode); + return runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, index); + } + + /** + * Gets a {@link JavaType} corresponding a given metaspace Klass or to a given name if the + * former is null. + * + * @param metaspaceSymbol a type name + * @param metaspaceKlass a resolved type (if non-zero) + * @param mayBePrimitive specifies if the requested type may be primitive + */ + private static JavaType getType(long metaspaceSymbol, long metaspaceKlass, boolean mayBePrimitive) { + if (metaspaceKlass == 0L) { + String name = new HotSpotSymbol(metaspaceSymbol).asString(); + if (mayBePrimitive && name.length() == 1) { + Kind kind = Kind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return HotSpotResolvedPrimitiveType.fromClass(kind.toJavaClass()); + } + return HotSpotUnresolvedJavaType.create(name); + } else { + return HotSpotResolvedObjectType.fromMetaspaceKlass(metaspaceKlass); + } } @Override public JavaMethod lookupMethod(int cpi, int opcode) { - return runtime().getCompilerToVM().lookupMethodInPool(metaspaceConstantPool, cpi, (byte) opcode); + final int index = toConstantPoolIndex(cpi, opcode); + // {name, signature, unresolved_holder_name, resolved_holder} + long[] unresolvedInfo = new long[4]; + long metaspaceMethod = runtime().getCompilerToVM().lookupMethodInPool(metaspaceConstantPool, index, (byte) opcode, unresolvedInfo); + if (metaspaceMethod != 0L) { + return HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod); + } else { + String name = new HotSpotSymbol(unresolvedInfo[0]).asString(); + String signature = new HotSpotSymbol(unresolvedInfo[1]).asString(); + JavaType holder = getType(unresolvedInfo[2], unresolvedInfo[3], false); + return new HotSpotMethodUnresolved(name, signature, holder); + } } @Override public JavaType lookupType(int cpi, int opcode) { - return runtime().getCompilerToVM().lookupTypeInPool(metaspaceConstantPool, cpi); + long[] unresolvedTypeName = {0}; + long metaspaceKlass = runtime().getCompilerToVM().lookupTypeInPool(metaspaceConstantPool, cpi, unresolvedTypeName); + return getType(unresolvedTypeName[0], metaspaceKlass, false); } @Override public JavaField lookupField(int cpi, int opcode) { - return runtime().getCompilerToVM().lookupFieldInPool(metaspaceConstantPool, cpi, (byte) opcode); + final int index = toConstantPoolIndex(cpi, opcode); + long[] info = new long[7]; + boolean resolved = runtime().getCompilerToVM().lookupFieldInPool(metaspaceConstantPool, index, (byte) opcode, info); + String name = new HotSpotSymbol(info[0]).asString(); + JavaType type = getType(info[1], info[2], true); + JavaType holder = getType(info[3], info[4], false); + int flags = (int) info[5]; + int offset = (int) info[6]; + if (resolved) { + HotSpotResolvedObjectType resolvedHolder = (HotSpotResolvedObjectType) holder; + HotSpotResolvedJavaField f = resolvedHolder.createField(name, type, offset, flags); + return f; + } else { + return new HotSpotUnresolvedField(holder, name, type); + } } @Override public void loadReferencedType(int cpi, int opcode) { - runtime().getCompilerToVM().lookupReferencedTypeInPool(metaspaceConstantPool, cpi, (byte) opcode); + int index; + if (opcode != Bytecodes.CHECKCAST && opcode != Bytecodes.INSTANCEOF && opcode != Bytecodes.NEW && opcode != Bytecodes.ANEWARRAY && opcode != Bytecodes.MULTIANEWARRAY && + opcode != Bytecodes.LDC && opcode != Bytecodes.LDC_W && opcode != Bytecodes.LDC2_W) { + index = toConstantPoolIndex(cpi, opcode); + } else { + index = cpi; + } + runtime().getCompilerToVM().loadReferencedTypeInPool(metaspaceConstantPool, index, (byte) opcode); } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -48,10 +48,13 @@ import static com.oracle.graal.replacements.Log.*; import static com.oracle.graal.replacements.MathSubstitutionsX86.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.word.*; /** * HotSpot implementation of {@link ForeignCallsProvider}. @@ -66,6 +69,37 @@ stub.getLinkage().setCompiledStub(stub); } + public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint) { + return (ForeignCallDescriptor) arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind); + } + + private static final EnumMap[][] arraycopyDescriptors = new EnumMap[2][2]; + + static { + // Populate the EnumMap instances + for (int i = 0; i < arraycopyDescriptors.length; i++) { + for (int j = 0; j < arraycopyDescriptors[i].length; j++) { + arraycopyDescriptors[i][j] = new EnumMap(Kind.class); + } + } + } + + @SuppressWarnings("unchecked") + private static ForeignCallDescriptor registerArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint) { + String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + "Arraycopy"; + ForeignCallDescriptor desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class); + arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, desc); + return desc; + } + + private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) { + LocationIdentity killed = NamedLocationIdentity.getArrayLocation(kind); + registerForeignCall(registerArraycopyDescriptor(kind, false, false), routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + registerForeignCall(registerArraycopyDescriptor(kind, true, false), alignedRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + registerForeignCall(registerArraycopyDescriptor(kind, false, true), disjointRoutine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + registerForeignCall(registerArraycopyDescriptor(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 +144,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); + registerArrayCopy(Kind.Object, c.oopArraycopy, c.oopArraycopy, c.oopDisjointArraycopy, c.oopDisjointArraycopy); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,7 +27,7 @@ import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider.*; +import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; import static com.oracle.graal.nodes.java.ArrayLengthNode.*; @@ -97,325 +97,40 @@ @Override public void lower(Node n, LoweringTool tool) { - HotSpotVMConfig config = runtime.getConfig(); StructuredGraph graph = (StructuredGraph) n.graph(); - Kind wordKind = runtime.getTarget().wordKind; if (n instanceof ArrayLengthNode) { - ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; - ValueNode array = arrayLengthNode.array(); - ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(), - BarrierType.NONE, false)); - arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool)); - graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); + lowerArrayLengthNode((ArrayLengthNode) n, tool); } else if (n instanceof Invoke) { - Invoke invoke = (Invoke) n; - if (invoke.callTarget() instanceof MethodCallTargetNode) { - - MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); - NodeInputList parameters = callTarget.arguments(); - ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); - GuardingNode receiverNullCheck = null; - if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) { - receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool); - invoke.setGuard(receiverNullCheck); - } - JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); - - LoweredCallTargetNode loweredCallTarget = null; - if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) { - - HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); - if (!hsMethod.getDeclaringClass().isInterface()) { - if (hsMethod.isInVirtualMethodTable()) { - int vtableEntryOffset = hsMethod.vtableEntryOffset(); - assert vtableEntryOffset > 0; - FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck); - - ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod); - // We use LocationNode.ANY_LOCATION for the reads that access the - // compiled code entry as HotSpot does not guarantee they are final - // values. - ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), - StampFactory.forKind(wordKind), BarrierType.NONE, false)); - - loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), - CallingConvention.Type.JavaCall)); - - graph.addBeforeFixed(invoke.asNode(), metaspaceMethod); - graph.addAfterFixed(metaspaceMethod, compiledEntry); - } - } - } - - if (loweredCallTarget == null) { - loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, - callTarget.invokeKind())); - } - callTarget.replaceAndDelete(loweredCallTarget); - } + lowerInvoke((Invoke) n, tool, graph); } else if (n instanceof LoadFieldNode) { - LoadFieldNode loadField = (LoadFieldNode) n; - HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); - ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object(); - assert loadField.kind() != Kind.Illegal; - BarrierType barrierType = getFieldLoadBarrierType(field); - ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); - graph.replaceFixedWithFixed(loadField, memoryRead); - memoryRead.setGuard(createNullCheck(object, memoryRead, tool)); - - if (loadField.isVolatile()) { - MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); - graph.addBeforeFixed(memoryRead, preMembar); - MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ)); - graph.addAfterFixed(memoryRead, postMembar); - } + lowerLoadFieldNode((LoadFieldNode) n, tool); } else if (n instanceof StoreFieldNode) { - StoreFieldNode storeField = (StoreFieldNode) n; - HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); - ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object(); - BarrierType barrierType = getFieldStoreBarrierType(storeField); - WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object)); - memoryWrite.setStateAfter(storeField.stateAfter()); - graph.replaceFixedWithFixed(storeField, memoryWrite); - memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool)); - FixedWithNextNode last = memoryWrite; - FixedWithNextNode first = memoryWrite; - - if (storeField.isVolatile()) { - MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); - graph.addBeforeFixed(first, preMembar); - MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); - graph.addAfterFixed(last, postMembar); - } + lowerStoreFieldNode((StoreFieldNode) n, tool); } else if (n instanceof CompareAndSwapNode) { - // Separate out GC barrier semantics - CompareAndSwapNode cas = (CompareAndSwapNode) n; - LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); - LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas), - cas.expected().kind() == Kind.Object)); - atomicNode.setStateAfter(cas.stateAfter()); - graph.replaceFixedWithFixed(cas, atomicNode); + lowerCompareAndSwapNode((CompareAndSwapNode) n); } else if (n instanceof LoadIndexedNode) { - LoadIndexedNode loadIndexed = (LoadIndexedNode) n; - Kind elementKind = loadIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false); - ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object)); - memoryRead.setGuard(createBoundsCheck(loadIndexed, tool)); - graph.replaceFixedWithFixed(loadIndexed, memoryRead); + lowerLoadIndexedNode((LoadIndexedNode) n, tool); } else if (n instanceof StoreIndexedNode) { - StoreIndexedNode storeIndexed = (StoreIndexedNode) n; - GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool); - Kind elementKind = storeIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false); - ValueNode value = storeIndexed.value(); - ValueNode array = storeIndexed.array(); - - CheckCastNode checkcastNode = null; - CheckCastDynamicNode checkcastDynamicNode = null; - if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) { - // Store check! - ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array); - if (arrayType != null && ObjectStamp.isExactType(array)) { - ResolvedJavaType elementType = arrayType.getComponentType(); - if (!MetaUtil.isJavaLangObject(elementType)) { - checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true)); - graph.addBeforeFixed(storeIndexed, checkcastNode); - value = checkcastNode; - } - } else { - FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck); - LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph); - /* - * Anchor the read of the element klass to the cfg, because it is only valid - * when arrayClass is an object class, which might not be the case in other - * parts of the compiled method. - */ - FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed))); - checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true)); - graph.addBeforeFixed(storeIndexed, checkcastDynamicNode); - value = checkcastDynamicNode; - } - } - BarrierType barrierType = getArrayStoreBarrierType(storeIndexed); - WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object)); - memoryWrite.setGuard(boundsCheck); - memoryWrite.setStateAfter(storeIndexed.stateAfter()); - graph.replaceFixedWithFixed(storeIndexed, memoryWrite); - - // Lower the associated checkcast node. - if (checkcastNode != null) { - checkcastNode.lower(tool); - } else if (checkcastDynamicNode != null) { - checkcastDynamicSnippets.lower(checkcastDynamicNode, tool); - } + lowerStoreIndexedNode((StoreIndexedNode) n, tool); } else if (n instanceof UnsafeLoadNode) { - UnsafeLoadNode load = (UnsafeLoadNode) n; - if (load.getGuardingCondition() != null) { - boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); - ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition())); - LocationNode location = createLocation(load); - ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible)); - load.replaceAtUsages(memoryRead); - graph.replaceFixedWithFixed(load, valueAnchorNode); - graph.addAfterFixed(valueAnchorNode, memoryRead); - } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) { - assert load.kind() != Kind.Illegal; - boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); - if (addReadBarrier(load)) { - unsafeLoadSnippets.lower(load, tool); - } else { - LocationNode location = createLocation(load); - ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible)); - // An unsafe read must not float outside its block otherwise - // it may float above an explicit null check on its object. - memoryRead.setGuard(AbstractBeginNode.prevBegin(load)); - graph.replaceFixedWithFixed(load, memoryRead); - } - } + lowerUnsafeLoadNode((UnsafeLoadNode) n, tool); } else if (n instanceof UnsafeStoreNode) { - UnsafeStoreNode store = (UnsafeStoreNode) n; - LocationNode location = createLocation(store); - ValueNode object = store.object(); - BarrierType barrierType = getUnsafeStoreBarrierType(store); - WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object)); - write.setStateAfter(store.stateAfter()); - graph.replaceFixedWithFixed(store, write); + lowerUnsafeStoreNode((UnsafeStoreNode) n); } else if (n instanceof LoadHubNode) { - if (graph.getGuardsStage().ordinal() == StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) { - LoadHubNode loadHub = (LoadHubNode) n; - assert loadHub.kind() == wordKind; - ValueNode object = loadHub.object(); - GuardingNode guard = loadHub.getGuard(); - FloatingReadNode hub = createReadHub(graph, wordKind, object, guard); - graph.replaceFloating(loadHub, hub); - } + lowerLoadHubNode((LoadHubNode) n); } else if (n instanceof LoadMethodNode) { - LoadMethodNode loadMethodNode = (LoadMethodNode) n; - ResolvedJavaMethod method = loadMethodNode.getMethod(); - ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method); - graph.replaceFixed(loadMethodNode, metaspaceMethod); + lowerLoadMethodNode((LoadMethodNode) n); } else if (n instanceof StoreHubNode) { - StoreHubNode storeHub = (StoreHubNode) n; - WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue()); - graph.replaceFixed(storeHub, hub); + lowerStoreHubNode((StoreHubNode) n, graph); } else if (n instanceof CommitAllocationNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - CommitAllocationNode commit = (CommitAllocationNode) n; - ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()]; - BitSet omittedValues = new BitSet(); - int valuePos = 0; - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); - int entryCount = virtual.entryCount(); - FixedWithNextNode newObject; - if (virtual instanceof VirtualInstanceNode) { - newObject = graph.add(new NewInstanceNode(virtual.type(), true)); - } else { - newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true)); - } - graph.addBeforeFixed(commit, newObject); - allocations[objIndex] = newObject; - for (int i = 0; i < entryCount; i++) { - ValueNode value = commit.getValues().get(valuePos); - if (value instanceof VirtualObjectNode) { - value = allocations[commit.getVirtualObjects().indexOf(value)]; - } - if (value == null) { - omittedValues.set(valuePos); - } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - // Constant.illegal is always the defaultForKind, so it is skipped - Kind valueKind = value.kind(); - Kind entryKind = virtual.entryKind(i); - - // Truffle requires some leniency in terms of what can be put where: - Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind; - assert valueKind.getStackKind() == entryKind.getStackKind() || - (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode)); - ConstantLocationNode location; - BarrierType barrierType; - if (virtual instanceof VirtualInstanceNode) { - ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i); - location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph); - barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; - } else { - location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph); - barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE; - } - WriteNode write = new WriteNode(newObject, value, location, barrierType, entryKind == Kind.Object); - graph.addAfterFixed(newObject, graph.add(write)); - } - valuePos++; - - } - } - valuePos = 0; - - for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { - VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); - int entryCount = virtual.entryCount(); - ValueNode newObject = allocations[objIndex]; - for (int i = 0; i < entryCount; i++) { - if (omittedValues.get(valuePos)) { - ValueNode value = commit.getValues().get(valuePos); - assert value instanceof VirtualObjectNode; - ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; - if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { - assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object; - WriteNode write; - if (virtual instanceof VirtualInstanceNode) { - VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; - write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), BarrierType.IMPRECISE, true); - } else { - write = new WriteNode(newObject, allocValue, createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, true); - } - graph.addBeforeFixed(commit, graph.add(write)); - } - } - valuePos++; - } - } - - finishAllocatedObjects(tool, commit, allocations); - graph.removeFixed(commit); - } + lowerCommitAllocationNode((CommitAllocationNode) n, tool); } else if (n instanceof OSRStartNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { - OSRStartNode osrStart = (OSRStartNode) n; - StartNode newStart = graph.add(new StartNode()); - ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(wordKind))); - ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer)); - migrationEnd.setStateAfter(osrStart.stateAfter()); - - newStart.setNext(migrationEnd); - FixedNode next = osrStart.next(); - osrStart.setNext(null); - migrationEnd.setNext(next); - graph.setStart(newStart); - - // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) - int localsOffset = (graph.method().getMaxLocals() - 1) * 8; - for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) { - int size = FrameStateBuilder.stackSlots(osrLocal.kind()); - int offset = localsOffset - (osrLocal.index() + size - 1) * 8; - IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1); - ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false)); - osrLocal.replaceAndDelete(load); - graph.addBeforeFixed(migrationEnd, load); - } - osrStart.replaceAtUsages(newStart); - osrStart.safeDelete(); - } + lowerOSRStartNode((OSRStartNode) n); } else if (n instanceof DynamicCounterNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { - BenchmarkCounters.lower((DynamicCounterNode) n, registers, runtime.getConfig(), wordKind); - } + lowerDynamicCounterNode((DynamicCounterNode) n); } else if (n instanceof DeferredForeignCallNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) { - DeferredForeignCallNode deferred = (DeferredForeignCallNode) n; - ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, deferred.getDescriptor(), deferred.getArguments())); - graph.replaceFixedWithFixed(deferred, foreignCallNode); - } + lowerDeferredForeignCallNode((DeferredForeignCallNode) n); } else if (n instanceof CheckCastDynamicNode) { checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool); } else if (n instanceof InstanceOfNode) { @@ -443,11 +158,11 @@ newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool); } } else if (n instanceof MonitorEnterNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { monitorSnippets.lower((MonitorEnterNode) n, registers, tool); } } else if (n instanceof MonitorExitNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { monitorSnippets.lower((MonitorExitNode) n, tool); } } else if (n instanceof G1PreWriteBarrier) { @@ -480,8 +195,355 @@ } else if (n instanceof DeoptimizeNode || n instanceof UnwindNode) { /* No lowering, we generate LIR directly for these nodes. */ } else { - assert false : "Node implementing Lowerable not handled: " + n; - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n); + } + } + + private void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) { + StructuredGraph graph = arrayLengthNode.graph(); + ValueNode array = arrayLengthNode.array(); + ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(ARRAY_LENGTH_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, graph), + StampFactory.positiveInt(), BarrierType.NONE, false)); + arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool)); + graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); + } + + private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) { + if (invoke.callTarget() instanceof MethodCallTargetNode) { + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + NodeInputList parameters = callTarget.arguments(); + ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); + GuardingNode receiverNullCheck = null; + if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) { + receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool); + invoke.setGuard(receiverNullCheck); + } + JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); + + LoweredCallTargetNode loweredCallTarget = null; + if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) { + + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); + if (!hsMethod.getDeclaringClass().isInterface()) { + if (hsMethod.isInVirtualMethodTable()) { + int vtableEntryOffset = hsMethod.vtableEntryOffset(); + assert vtableEntryOffset > 0; + Kind wordKind = runtime.getTarget().wordKind; + FloatingReadNode hub = createReadHub(graph, wordKind, receiver, receiverNullCheck); + + ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod); + // We use LocationNode.ANY_LOCATION for the reads that access the + // compiled code entry as HotSpot does not guarantee they are final + // values. + ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, runtime.getConfig().methodCompiledEntryOffset, graph), + StampFactory.forKind(wordKind), BarrierType.NONE, false)); + + loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), + CallingConvention.Type.JavaCall)); + + graph.addBeforeFixed(invoke.asNode(), metaspaceMethod); + graph.addAfterFixed(metaspaceMethod, compiledEntry); + } + } + } + + if (loweredCallTarget == null) { + loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, + callTarget.invokeKind())); + } + callTarget.replaceAndDelete(loweredCallTarget); + } + } + + private void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) { + StructuredGraph graph = loadField.graph(); + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); + ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : loadField.object(); + assert loadField.kind() != Kind.Illegal; + BarrierType barrierType = getFieldLoadBarrierType(field); + ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); + graph.replaceFixedWithFixed(loadField, memoryRead); + memoryRead.setGuard(createNullCheck(object, memoryRead, tool)); + + if (loadField.isVolatile()) { + MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); + graph.addBeforeFixed(memoryRead, preMembar); + MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ)); + graph.addAfterFixed(memoryRead, postMembar); + } + } + + private void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) { + StructuredGraph graph = storeField.graph(); + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); + ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object(); + BarrierType barrierType = getFieldStoreBarrierType(storeField); + WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object)); + memoryWrite.setStateAfter(storeField.stateAfter()); + graph.replaceFixedWithFixed(storeField, memoryWrite); + memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool)); + FixedWithNextNode last = memoryWrite; + FixedWithNextNode first = memoryWrite; + + if (storeField.isVolatile()) { + MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); + graph.addBeforeFixed(first, preMembar); + MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); + graph.addAfterFixed(last, postMembar); + } + } + + private static void lowerCompareAndSwapNode(CompareAndSwapNode cas) { + // Separate out GC barrier semantics + StructuredGraph graph = cas.graph(); + LocationNode location = IndexedLocationNode.create(cas.getLocationIdentity(), cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); + LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas), + cas.expected().kind() == Kind.Object)); + atomicNode.setStateAfter(cas.stateAfter()); + graph.replaceFixedWithFixed(cas, atomicNode); + } + + private void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) { + StructuredGraph graph = loadIndexed.graph(); + Kind elementKind = loadIndexed.elementKind(); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false); + ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object)); + memoryRead.setGuard(createBoundsCheck(loadIndexed, tool)); + graph.replaceFixedWithFixed(loadIndexed, memoryRead); + } + + private void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) { + StructuredGraph graph = storeIndexed.graph(); + GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool); + Kind elementKind = storeIndexed.elementKind(); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false); + ValueNode value = storeIndexed.value(); + ValueNode array = storeIndexed.array(); + + CheckCastNode checkcastNode = null; + CheckCastDynamicNode checkcastDynamicNode = null; + if (elementKind == Kind.Object && !ObjectStamp.isObjectAlwaysNull(value)) { + // Store check! + ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array); + if (arrayType != null && ObjectStamp.isExactType(array)) { + ResolvedJavaType elementType = arrayType.getComponentType(); + if (!MetaUtil.isJavaLangObject(elementType)) { + checkcastNode = graph.add(new CheckCastNode(elementType, value, null, true)); + graph.addBeforeFixed(storeIndexed, checkcastNode); + value = checkcastNode; + } + } else { + Kind wordKind = runtime.getTarget().wordKind; + FloatingReadNode arrayClass = createReadHub(graph, wordKind, array, boundsCheck); + LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, runtime.getConfig().arrayClassElementOffset, graph); + /* + * Anchor the read of the element klass to the cfg, because it is only valid when + * arrayClass is an object class, which might not be the case in other parts of the + * compiled method. + */ + FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind), BeginNode.prevBegin(storeIndexed))); + checkcastDynamicNode = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true)); + graph.addBeforeFixed(storeIndexed, checkcastDynamicNode); + value = checkcastDynamicNode; + } + } + BarrierType barrierType = getArrayStoreBarrierType(storeIndexed); + WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object)); + memoryWrite.setGuard(boundsCheck); + memoryWrite.setStateAfter(storeIndexed.stateAfter()); + graph.replaceFixedWithFixed(storeIndexed, memoryWrite); + + // Lower the associated checkcast node. + if (checkcastNode != null) { + checkcastNode.lower(tool); + } else if (checkcastDynamicNode != null) { + checkcastDynamicSnippets.lower(checkcastDynamicNode, tool); + } + } + + private void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) { + StructuredGraph graph = load.graph(); + if (load.getGuardingCondition() != null) { + boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); + ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition())); + LocationNode location = createLocation(load); + ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), valueAnchorNode, BarrierType.NONE, compressible)); + load.replaceAtUsages(memoryRead); + graph.replaceFixedWithFixed(load, valueAnchorNode); + graph.addAfterFixed(valueAnchorNode, memoryRead); + } else if (graph.getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) { + assert load.kind() != Kind.Illegal; + boolean compressible = (!load.object().isNullConstant() && load.accessKind() == Kind.Object); + if (addReadBarrier(load)) { + unsafeLoadSnippets.lower(load, tool); + } else { + LocationNode location = createLocation(load); + ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), BarrierType.NONE, compressible)); + // An unsafe read must not float outside its block otherwise + // it may float above an explicit null check on its object. + memoryRead.setGuard(AbstractBeginNode.prevBegin(load)); + graph.replaceFixedWithFixed(load, memoryRead); + } + } + } + + private static void lowerUnsafeStoreNode(UnsafeStoreNode store) { + StructuredGraph graph = store.graph(); + LocationNode location = createLocation(store); + ValueNode object = store.object(); + BarrierType barrierType = getUnsafeStoreBarrierType(store); + WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object)); + write.setStateAfter(store.stateAfter()); + graph.replaceFixedWithFixed(store, write); + } + + private void lowerLoadHubNode(LoadHubNode loadHub) { + StructuredGraph graph = loadHub.graph(); + if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) { + Kind wordKind = runtime.getTarget().wordKind; + assert loadHub.kind() == wordKind; + ValueNode object = loadHub.object(); + GuardingNode guard = loadHub.getGuard(); + FloatingReadNode hub = createReadHub(graph, wordKind, object, guard); + graph.replaceFloating(loadHub, hub); + } + } + + private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) { + StructuredGraph graph = loadMethodNode.graph(); + ResolvedJavaMethod method = loadMethodNode.getMethod(); + ReadNode metaspaceMethod = createReadVirtualMethod(graph, runtime.getTarget().wordKind, loadMethodNode.getHub(), method); + graph.replaceFixed(loadMethodNode, metaspaceMethod); + } + + private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) { + WriteNode hub = createWriteHub(graph, runtime.getTarget().wordKind, storeHub.getObject(), storeHub.getValue()); + graph.replaceFixed(storeHub, hub); + } + + private void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) { + StructuredGraph graph = commit.graph(); + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()]; + BitSet omittedValues = new BitSet(); + int valuePos = 0; + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int entryCount = virtual.entryCount(); + FixedWithNextNode newObject; + if (virtual instanceof VirtualInstanceNode) { + newObject = graph.add(new NewInstanceNode(virtual.type(), true)); + } else { + newObject = graph.add(new NewArrayNode(((VirtualArrayNode) virtual).componentType(), ConstantNode.forInt(entryCount, graph), true)); + } + graph.addBeforeFixed(commit, newObject); + allocations[objIndex] = newObject; + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos); + if (value instanceof VirtualObjectNode) { + value = allocations[commit.getVirtualObjects().indexOf(value)]; + } + if (value == null) { + omittedValues.set(valuePos); + } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { + // Constant.illegal is always the defaultForKind, so it is skipped + Kind valueKind = value.kind(); + Kind entryKind = virtual.entryKind(i); + + // Truffle requires some leniency in terms of what can be put where: + Kind accessKind = valueKind.getStackKind() == entryKind.getStackKind() ? entryKind : valueKind; + assert valueKind.getStackKind() == entryKind.getStackKind() || + (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode)); + ConstantLocationNode location; + BarrierType barrierType; + if (virtual instanceof VirtualInstanceNode) { + ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i); + location = ConstantLocationNode.create(INIT_LOCATION, accessKind, ((HotSpotResolvedJavaField) field).offset(), graph); + barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; + } else { + location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(entryKind) + i * getScalingFactor(entryKind), graph); + barrierType = (entryKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE; + } + WriteNode write = new WriteNode(newObject, value, location, barrierType, entryKind == Kind.Object); + graph.addAfterFixed(newObject, graph.add(write)); + } + valuePos++; + + } + } + valuePos = 0; + + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int entryCount = virtual.entryCount(); + ValueNode newObject = allocations[objIndex]; + for (int i = 0; i < entryCount; i++) { + if (omittedValues.get(valuePos)) { + ValueNode value = commit.getValues().get(valuePos); + assert value instanceof VirtualObjectNode; + ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)]; + if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) { + assert virtual.entryKind(i) == Kind.Object && allocValue.kind() == Kind.Object; + WriteNode write; + if (virtual instanceof VirtualInstanceNode) { + VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; + write = new WriteNode(newObject, allocValue, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), BarrierType.IMPRECISE, true); + } else { + write = new WriteNode(newObject, allocValue, createArrayLocation(graph, virtual.entryKind(i), ConstantNode.forInt(i, graph), true), BarrierType.PRECISE, true); + } + graph.addBeforeFixed(commit, graph.add(write)); + } + } + valuePos++; + } + } + + finishAllocatedObjects(tool, commit, allocations); + graph.removeFixed(commit); + } + } + + private void lowerOSRStartNode(OSRStartNode osrStart) { + StructuredGraph graph = osrStart.graph(); + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + StartNode newStart = graph.add(new StartNode()); + ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind))); + ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer)); + migrationEnd.setStateAfter(osrStart.stateAfter()); + + newStart.setNext(migrationEnd); + FixedNode next = osrStart.next(); + osrStart.setNext(null); + migrationEnd.setNext(next); + graph.setStart(newStart); + + // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) + int localsOffset = (graph.method().getMaxLocals() - 1) * 8; + for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) { + int size = FrameStateBuilder.stackSlots(osrLocal.kind()); + int offset = localsOffset - (osrLocal.index() + size - 1) * 8; + IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1); + ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), BarrierType.NONE, false)); + osrLocal.replaceAndDelete(load); + graph.addBeforeFixed(migrationEnd, load); + } + osrStart.replaceAtUsages(newStart); + osrStart.safeDelete(); + } + } + + private void lowerDynamicCounterNode(DynamicCounterNode n) { + StructuredGraph graph = n.graph(); + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + BenchmarkCounters.lower(n, registers, runtime.getConfig(), runtime.getTarget().wordKind); + } + } + + private void lowerDeferredForeignCallNode(DeferredForeignCallNode deferred) { + StructuredGraph graph = deferred.graph(); + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) { + ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, deferred.getDescriptor(), deferred.stamp(), deferred.getArguments())); + graph.replaceFixedWithFixed(deferred, foreignCallNode); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Wed Mar 05 19:40:15 2014 -0800 @@ -26,9 +26,11 @@ import java.lang.reflect.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.replacements.*; /** * HotSpot implementation of {@link MetaAccessProvider}. @@ -110,14 +112,13 @@ // are not used (yet). final int modifiers = reflectionField.getModifiers(); final long offset = Modifier.isStatic(modifiers) ? unsafe.staticFieldOffset(reflectionField) : unsafe.objectFieldOffset(reflectionField); - final boolean internal = false; ResolvedJavaType holder = HotSpotResolvedObjectType.fromClass(fieldHolder); ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(fieldType); if (offset != -1) { HotSpotResolvedObjectType resolved = (HotSpotResolvedObjectType) holder; - return resolved.createField(name, type, offset, modifiers, internal); + return resolved.createField(name, type, offset, modifiers); } else { // TODO this cast will not succeed return (ResolvedJavaField) new HotSpotUnresolvedField(holder, name, type); @@ -284,4 +285,30 @@ } throw GraalInternalError.shouldNotReachHere(Integer.toHexString(reason)); } + + @Override + public long getMemorySize(Constant constant) { + if (constant.getKind() == Kind.Object) { + HotSpotResolvedObjectType lookupJavaType = (HotSpotResolvedObjectType) this.lookupJavaType(constant); + + if (lookupJavaType == null) { + return 0; + } else { + if (lookupJavaType.isArray()) { + // TODO(tw): Add compressed pointer support. + int length = Array.getLength(constant.asObject()); + ResolvedJavaType elementType = lookupJavaType.getComponentType(); + Kind elementKind = elementType.getKind(); + final int headerSize = HotSpotGraalRuntime.getArrayBaseOffset(elementKind); + int sizeOfElement = HotSpotGraalRuntime.runtime().getTarget().arch.getSizeInBytes(elementKind); + int alignment = HotSpotGraalRuntime.runtime().getTarget().wordSize; + int log2ElementSize = CodeUtil.log2(sizeOfElement); + return NewObjectSnippets.computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + } + return lookupJavaType.instanceSize(); + } + } else { + return constant.getKind().getByteCount(); + } + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Wed Mar 05 19:40:15 2014 -0800 @@ -207,6 +207,14 @@ return cells * config.dataLayoutCellSize; } + /** + * Returns whether profiling ran long enough that the profile information is mature. Other + * informational data will still be valid even if the profile isn't mature. + */ + public boolean isProfileMature() { + return runtime().getCompilerToVM().isMature(metaspaceMethodData); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java Wed Mar 05 19:40:15 2014 -0800 @@ -115,25 +115,11 @@ return true; } - public Object executeParallel(int dimX, int dimY, int dimZ, Object... args) throws InvalidInstalledCodeException { - - // For HSAIL, we do not pass the iteration variable, it comes from the workitemid - // assert checkArgs(args); - - assert isExternal(); // for now - - return runtime().getCompilerToGPU().executeParallelMethodVarargs(dimX, dimY, dimZ, args, this); - - } - @Override public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { assert checkArgs(args); - if (isExternal()) { - return runtime().getCompilerToGPU().executeExternalMethodVarargs(args, this); - } else { - return runtime().getCompilerToVM().executeCompiledMethodVarargs(args, this); - } + assert !isExternal(); + return runtime().getCompilerToVM().executeCompiledMethodVarargs(args, this); } @Override diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,6 +34,7 @@ private final HotSpotMethodData methodData; private final HotSpotResolvedJavaMethod method; + private boolean isMature; private int position; private int hintPosition; private int hintBCI; @@ -47,6 +48,7 @@ this.method = method; this.includeNormal = includeNormal; this.includeOSR = includeOSR; + this.isMature = methodData.isProfileMature(); hintPosition = 0; hintBCI = -1; } @@ -58,24 +60,36 @@ @Override public JavaTypeProfile getTypeProfile(int bci) { + if (!isMature) { + return null; + } findBCI(bci, false); return dataAccessor.getTypeProfile(methodData, position); } @Override public JavaMethodProfile getMethodProfile(int bci) { + if (!isMature) { + return null; + } findBCI(bci, false); return dataAccessor.getMethodProfile(methodData, position); } @Override public double getBranchTakenProbability(int bci) { + if (!isMature) { + return -1; + } findBCI(bci, false); return dataAccessor.getBranchTakenProbability(methodData, position); } @Override public double[] getSwitchProbabilities(int bci) { + if (!isMature) { + return null; + } findBCI(bci, false); return dataAccessor.getSwitchProbabilities(methodData, position); } @@ -94,6 +108,9 @@ @Override public int getExecutionCount(int bci) { + if (!isMature) { + return -1; + } findBCI(bci, false); return dataAccessor.getExecutionCount(methodData, position); } @@ -172,11 +189,20 @@ @Override public boolean isMature() { - return true; + return isMature; + } + + public void ignoreMature() { + isMature = true; } @Override public String toString() { return "HotSpotProfilingInfo<" + MetaUtil.profileToString(this, null, "; ") + ">"; } + + @Override + public void setMature() { + isMature = true; + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,7 +24,9 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType.*; import static com.oracle.graal.phases.GraalOptions.*; +import static java.lang.reflect.Modifier.*; import java.lang.annotation.*; import java.lang.reflect.*; @@ -44,41 +46,40 @@ */ public class HotSpotResolvedJavaField extends CompilerObject implements ResolvedJavaField { - // Must not conflict with any fields flags used by the VM - the assertion in the constructor - // checks this assumption - private static final int FIELD_INTERNAL_FLAG = 0x80000000; - private static final long serialVersionUID = 7692985878836955683L; private final HotSpotResolvedObjectType holder; private final String name; - private final JavaType type; + private JavaType type; private final int offset; - private final int modifiers; private Constant constant; - public HotSpotResolvedJavaField(HotSpotResolvedObjectType holder, String name, JavaType type, long offset, int modifiers, boolean internal) { - assert (modifiers & FIELD_INTERNAL_FLAG) == 0; + /** + * The {@linkplain HotSpotResolvedObjectType#getReflectionFieldModifiers() reflection} modifiers + * for this field plus the {@link #FIELD_INTERNAL_FLAG} if it applies. + */ + /** + * This value contains all flags as stored in the VM including internal ones. + */ + private final int modifiers; + + public HotSpotResolvedJavaField(HotSpotResolvedObjectType holder, String name, JavaType type, long offset, int modifiers) { this.holder = holder; this.name = name; this.type = type; assert offset != -1; assert offset == (int) offset : "offset larger than int"; this.offset = (int) offset; - if (internal) { - this.modifiers = modifiers | FIELD_INTERNAL_FLAG; - } else { - this.modifiers = modifiers; - } + this.modifiers = modifiers; } @Override public int getModifiers() { - return modifiers & Modifier.fieldModifiers(); + return modifiers & getReflectionFieldModifiers(); } @Override public boolean isInternal() { - return (modifiers & FIELD_INTERNAL_FLAG) != 0; + return (modifiers & runtime().getConfig().jvmAccFieldInternal) != 0; } /** @@ -118,42 +119,52 @@ return false; } - private static final List notEmbeddable = new ArrayList<>(); - - private static void addResolvedToSet(Field field) { - MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); - notEmbeddable.add(metaAccess.lookupJavaField(field)); - } + /** + * Separate out the static initialization to eliminate cycles between clinit and other locks + * that could lead to deadlock. Static code that doesn't call back into type or field machinery + * is probably ok but anything else should be made lazy. + */ + static class Embeddable { - static { - try { - addResolvedToSet(Boolean.class.getDeclaredField("TRUE")); - addResolvedToSet(Boolean.class.getDeclaredField("FALSE")); + /** + * @return Return true if it's ok to embed the value of {@code field}. + */ + public static boolean test(HotSpotResolvedJavaField field) { + return !ImmutableCode.getValue() || !fields.contains(field); + } - Class characterCacheClass = Character.class.getDeclaredClasses()[0]; - assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); - addResolvedToSet(characterCacheClass.getDeclaredField("cache")); + private static final List fields = new ArrayList<>(); + static { + try { + MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); + fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); + fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); - Class byteCacheClass = Byte.class.getDeclaredClasses()[0]; - assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); - addResolvedToSet(byteCacheClass.getDeclaredField("cache")); + Class characterCacheClass = Character.class.getDeclaredClasses()[0]; + assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); - Class shortCacheClass = Short.class.getDeclaredClasses()[0]; - assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); - addResolvedToSet(shortCacheClass.getDeclaredField("cache")); + Class byteCacheClass = Byte.class.getDeclaredClasses()[0]; + assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); + + Class shortCacheClass = Short.class.getDeclaredClasses()[0]; + assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); - Class integerCacheClass = Integer.class.getDeclaredClasses()[0]; - assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); - addResolvedToSet(integerCacheClass.getDeclaredField("cache")); + Class integerCacheClass = Integer.class.getDeclaredClasses()[0]; + assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); - Class longCacheClass = Long.class.getDeclaredClasses()[0]; - assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); - addResolvedToSet(longCacheClass.getDeclaredField("cache")); + Class longCacheClass = Long.class.getDeclaredClasses()[0]; + assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); - addResolvedToSet(Throwable.class.getDeclaredField("UNASSIGNED_STACK")); - addResolvedToSet(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL")); - } catch (SecurityException | NoSuchFieldException e) { - throw new GraalInternalError(e); + fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); + fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); + } catch (SecurityException | NoSuchFieldException e) { + throw new GraalInternalError(e); + } } } @@ -161,10 +172,7 @@ * in AOT mode, some fields should never be embedded even for snippets/replacements. */ private boolean isEmbeddable() { - if (ImmutableCode.getValue() && notEmbeddable.contains(this)) { - return false; - } - return true; + return Embeddable.test(this); } private static final String SystemClassName = "Ljava/lang/System;"; @@ -180,7 +188,7 @@ assert !ImmutableCode.getValue() || isCalledForSnippets() : receiver; if (receiver == null) { - assert Modifier.isStatic(modifiers); + assert isStatic(modifiers); if (constant == null) { if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable()) { if (Modifier.isFinal(getModifiers())) { @@ -194,13 +202,13 @@ * for non-static final fields, we must assume that they are only initialized if they * have a non-default value. */ - assert !Modifier.isStatic(modifiers); + assert !isStatic(modifiers); Object object = receiver.asObject(); // Canonicalization may attempt to process an unsafe read before - // processing a guard (e.g. a type check) for this read - // so we need to type check the object being read - if (isInObject(object)) { + // processing a guard (e.g. a null check or a type check) for this read + // so we need to check the object being read + if (object != null && isInObject(object)) { if (Modifier.isFinal(getModifiers())) { Constant value = readValue(receiver); if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) { @@ -226,21 +234,27 @@ /** * Determines if a given object contains this field. + * + * @return true iff this is a non-static field and its declaring class is assignable from + * {@code object}'s class */ public boolean isInObject(Object object) { + if (isStatic(modifiers)) { + return false; + } return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectType.fromClass(object.getClass())); } @Override public Constant readValue(Constant receiver) { if (receiver == null) { - assert Modifier.isStatic(modifiers); + assert isStatic(modifiers); if (holder.isInitialized()) { return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), holder.mirror(), offset, getKind() == Kind.Object); } return null; } else { - assert !Modifier.isStatic(modifiers); + assert !isStatic(modifiers); Object object = receiver.asObject(); assert object != null && isInObject(object); return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), object, offset, getKind() == Kind.Object); @@ -282,6 +296,13 @@ @Override public JavaType getType() { + if (!(type instanceof ResolvedJavaType)) { + // Don't allow unresolved types to hang around forever + ResolvedJavaType resolved = type.resolve(holder); + if (resolved != null) { + type = resolved; + } + } return type; } @@ -296,11 +317,7 @@ @Override public boolean isSynthetic() { - Field javaField = toJava(); - if (javaField != null) { - return javaField.isSynthetic(); - } - return false; + return (runtime().getConfig().syntheticFlag & modifiers) != 0; } /** @@ -323,6 +340,9 @@ } private Field toJava() { + if (isInternal()) { + return null; + } try { return holder.mirror().getDeclaredField(name); } catch (NoSuchFieldException e) { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed Mar 05 19:40:15 2014 -0800 @@ -157,10 +157,18 @@ return getMetaspaceMethodConstant(); } + /** + * Gets the complete set of modifiers for this method which includes the JVM specification + * modifiers as well as the HotSpot internal modifiers. + */ + public int getAllModifiers() { + HotSpotVMConfig config = runtime().getConfig(); + return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset); + } + @Override public int getModifiers() { - HotSpotVMConfig config = runtime().getConfig(); - return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset) & Modifier.methodModifiers(); + return getAllModifiers() & Modifier.methodModifiers(); } @Override @@ -237,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); } @@ -426,25 +416,8 @@ @Override public boolean isSynthetic() { - if (isConstructor()) { - Constructor javaConstructor = toJavaConstructor(); - return javaConstructor == null ? false : javaConstructor.isSynthetic(); - } - - // Cannot use toJava() as it ignores the return type - HotSpotSignature sig = getSignature(); - JavaType[] sigTypes = MetaUtil.signatureToTypes(sig, null); - MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); - for (Method method : holder.mirror().getDeclaredMethods()) { - if (method.getName().equals(name)) { - if (metaAccess.lookupJavaType(method.getReturnType()).equals(sig.getReturnType(holder))) { - if (matches(metaAccess, sigTypes, method.getParameterTypes())) { - return method.isSynthetic(); - } - } - } - } - return false; + int modifiers = getAllModifiers(); + return (runtime().getConfig().syntheticFlag & modifiers) != 0; } public boolean isDefault() { @@ -476,18 +449,6 @@ return result; } - private static boolean matches(MetaAccessProvider metaAccess, JavaType[] sigTypes, Class[] parameterTypes) { - if (parameterTypes.length == sigTypes.length) { - for (int i = 0; i < parameterTypes.length; i++) { - if (!metaAccess.lookupJavaType(parameterTypes[i]).equals(sigTypes[i])) { - return false; - } - } - return true; - } - return false; - } - private Method toJava() { try { return holder.mirror().getDeclaredMethod(name, signatureToTypes()); @@ -509,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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Wed Mar 05 19:40:15 2014 -0800 @@ -53,7 +53,7 @@ */ private NodeClass nodeClass; - private HashMap fieldCache; + private HashMap fieldCache; private HashMap methodCache; private HotSpotResolvedJavaField[] instanceFields; private ResolvedJavaType[] interfaces; @@ -418,16 +418,21 @@ return method; } - public synchronized ResolvedJavaField createField(String fieldName, JavaType type, long offset, int rawFlags, boolean internal) { - ResolvedJavaField result = null; + /** + * Gets the mask used to filter out HotSpot internal flags for fields when a {@link Field} + * object is created. This is the value of {@code JVM_RECOGNIZED_FIELD_MODIFIERS} in + * {@code jvm.h}, not {@link Modifier#fieldModifiers()}. + */ + public static int getReflectionFieldModifiers() { + return runtime().getConfig().recognizedFieldModifiers; + } - /* - * Filter out flags used internally by HotSpot, to get a canonical id value. When a field is - * created from a java.lang.reflect.Field, these flags would not be available anyway. - */ - int flags = rawFlags & fieldModifiers(); + public synchronized HotSpotResolvedJavaField createField(String fieldName, JavaType type, long offset, int rawFlags) { + HotSpotResolvedJavaField result = null; - long id = offset + ((long) flags << 32); + final int flags = rawFlags & getReflectionFieldModifiers(); + + final long id = offset + ((long) flags << 32); // (thomaswue) Must cache the fields, because the local load elimination only works if the // objects from two field lookups are identical. @@ -438,10 +443,12 @@ } if (result == null) { - result = new HotSpotResolvedJavaField(this, fieldName, type, offset, flags, internal); + result = new HotSpotResolvedJavaField(this, fieldName, type, offset, rawFlags); fieldCache.put(id, result); } else { assert result.getName().equals(fieldName); + // assert result.getType().equals(type); + assert result.offset() == offset; assert result.getModifiers() == flags; } @@ -453,8 +460,134 @@ return ((HotSpotResolvedJavaMethod) method).uniqueConcreteMethod(); } + /** + * This class represents the field information for one field contained in the fields array of an + * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. + */ + private class FieldInfo { + /** + * Native pointer into the array of Java shorts. + */ + private final long metaspaceData; + + /** + * Creates a field info for the field in the fields array at index {@code index}. + * + * @param index index to the fields array + */ + public FieldInfo(int index) { + HotSpotVMConfig config = runtime().getConfig(); + // Get Klass::_fields + final long metaspaceFields = unsafe.getAddress(metaspaceKlass() + config.instanceKlassFieldsOffset); + assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; + metaspaceData = metaspaceFields + config.arrayU2DataOffset + config.fieldInfoFieldSlots * 2 * index; // TODO + // Short.BYTES + } + + private int getAccessFlags() { + return readFieldSlot(runtime().getConfig().fieldInfoAccessFlagsOffset); + } + + private int getNameIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoNameIndexOffset); + } + + private int getSignatureIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoSignatureIndexOffset); + } + + public int getOffset() { + HotSpotVMConfig config = runtime().getConfig(); + final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); + final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); + final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; + return offset; + } + + /** + * Helper method to read an entry (slot) from the field array. Currently field info is laid + * on top an array of Java shorts. + */ + private int readFieldSlot(int index) { + return unsafe.getChar(metaspaceData + 2 * index); // TODO Short.BYTES + } + + /** + * Returns the name of this field as a {@link String}. If the field is an internal field the + * name index is pointing into the vmSymbols table. + */ + public String getName() { + final int nameIndex = getNameIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(nameIndex) : constantPool().lookupUtf8(nameIndex); + } + + /** + * Returns the signature of this field as {@link String}. If the field is an internal field + * the signature index is pointing into the vmSymbols table. + */ + public String getSignature() { + final int signatureIndex = getSignatureIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(signatureIndex) : constantPool().lookupUtf8(signatureIndex); + } + + public JavaType getType() { + String signature = getSignature(); + Kind kind = Kind.fromTypeString(signature); + + JavaType type; + if (kind.isPrimitive()) { + type = HotSpotResolvedPrimitiveType.fromKind(kind); + } else { + String signatureClass = getNameForClassForName(signature); + Class c = null; + try { + // This class is the accessing class so we use its classloader. + c = Class.forName(signatureClass, false, mirror().getClassLoader()); + } catch (ClassNotFoundException e) { + throw new GraalInternalError(e); + } + if (c == null) { + type = HotSpotUnresolvedJavaType.create(signature); + } else { + type = HotSpotResolvedObjectType.fromClass(c); + } + } + return type; + } + + /** + * Returns a name that is suitable to be passed to {@link Class#forName}. + */ + private String getNameForClassForName(String name) { + // If this is an array type just return it. + if (name.charAt(0) == '[') { + return name.replace('/', '.'); + } + + // Decode name if necessary. + if (name.charAt(name.length() - 1) == ';') { + assert name.charAt(0) == 'L'; + return name.substring(1, name.length() - 1).replace('/', '.'); + } + + // Primitive type name. + return name; + } + + private boolean isInternal() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldInternal) != 0; + } + + public boolean isStatic() { + return Modifier.isStatic(getAccessFlags()); + } + + public boolean hasGenericSignature() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldHasGenericSignature) != 0; + } + } + private static class OffsetComparator implements Comparator { - @Override public int compare(HotSpotResolvedJavaField o1, HotSpotResolvedJavaField o2) { return o1.offset() - o2.offset(); @@ -467,8 +600,24 @@ if (isArray() || isInterface()) { instanceFields = new HotSpotResolvedJavaField[0]; } else { - HotSpotResolvedJavaField[] myFields = runtime().getCompilerToVM().getInstanceFields(this); - Arrays.sort(myFields, new OffsetComparator()); + final int fieldCount = getFieldCount(); + ArrayList fieldsArray = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + FieldInfo field = new FieldInfo(i); + + // We are only interested in instance fields. + if (!field.isStatic()) { + HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); + fieldsArray.add(resolvedJavaField); + } + } + + // TODO use in 1.8: fieldsArray.sort(new OffsetComparator()); + Collections.sort(fieldsArray, new OffsetComparator()); + + HotSpotResolvedJavaField[] myFields = fieldsArray.toArray(new HotSpotResolvedJavaField[0]); + if (javaClass != Object.class) { HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); HotSpotResolvedJavaField[] fields = Arrays.copyOf(superFields, superFields.length + myFields.length); @@ -478,6 +627,7 @@ assert myFields.length == 0 : "java.lang.Object has fields!"; instanceFields = myFields; } + } } if (!includeSuperclasses) { @@ -496,6 +646,29 @@ return instanceFields; } + /** + * Returns the actual field count of this class's internal {@code InstanceKlass::_fields} array + * by walking the array and discounting the generic signature slots at the end of the array. + * + *

+ * See {@code FieldStreamBase::init_generic_signature_start_slot} + */ + private int getFieldCount() { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceFields = unsafe.getAddress(metaspaceKlass() + config.instanceKlassFieldsOffset); + int metaspaceFieldsLength = unsafe.getInt(metaspaceFields + config.arrayU1LengthOffset); + int fieldCount = 0; + + for (int i = 0, index = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { + FieldInfo field = new FieldInfo(index); + if (field.hasGenericSignature()) { + metaspaceFieldsLength--; + } + fieldCount++; + } + return fieldCount; + } + @Override public Class mirror() { return javaClass; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Wed Mar 05 19:40:15 2014 -0800 @@ -42,6 +42,26 @@ this.dimensions = dimensions; } + /** + * Creates an unresolved type for a valid {@link JavaType#getName() type name}. + */ + public static HotSpotUnresolvedJavaType create(String name) { + int dims = 0; + int startIndex = 0; + while (name.charAt(startIndex) == '[') { + startIndex++; + dims++; + } + + // Decode name if necessary. + if (name.charAt(name.length() - 1) == ';') { + assert name.charAt(startIndex) == 'L'; + return new HotSpotUnresolvedJavaType(name, name.substring(startIndex + 1, name.length() - 1), dims); + } else { + return new HotSpotUnresolvedJavaType(HotSpotUnresolvedJavaType.getFullName(name, dims), name, dims); + } + } + public static String getFullName(String name, int dimensions) { StringBuilder str = new StringBuilder(name.length() + dimensions + 2); for (int i = 0; i < dimensions; i++) { diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,7 +33,7 @@ /** * {@link MacroNode Macro node} for {@link Class#cast(Object)}. * - * @see ClassSubstitutions#isInstance(Class, Object) + * @see ClassSubstitutions#cast(Class, Object) */ public class ClassCastNode extends MacroNode implements Canonicalizable { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -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, Kind.Object, classMirrorOffset, graph); FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp)); return freadNode; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -78,10 +78,7 @@ ProxyNode proxy = (ProxyNode) usage; proxy.replaceAndDelete(proxy.value()); } - FixedNode next = osr.next(); - osr.setNext(null); - ((FixedWithNextNode) osr.predecessor()).setNext(next); - GraphUtil.killWithUnusedFloatingInputs(osr); + GraphUtil.removeFixedWithUnusedInputs(osr); Debug.dump(graph, "OnStackReplacement loop peeling result"); } while (true); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot.replacements; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; - import sun.misc.*; import com.oracle.graal.api.meta.*; @@ -32,8 +31,8 @@ import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.word.*; @@ -57,7 +56,6 @@ } static final long kOffset; - static final LocationIdentity kLocationIdentity; static final Class AESCryptClass; static { @@ -67,7 +65,6 @@ ClassLoader cl = Launcher.getLauncher().getClassLoader(); AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl); kOffset = UnsafeAccess.unsafe.objectFieldOffset(AESCryptClass.getDeclaredField("K")); - kLocationIdentity = HotSpotResolvedObjectType.fromClass(AESCryptClass).findInstanceFieldWithOffset(kOffset); } catch (Exception ex) { throw new GraalInternalError(ex); } @@ -84,7 +81,8 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { - Object kObject = UnsafeLoadNode.load(rcvr, kOffset, Kind.Object, kLocationIdentity); + Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass); + Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, Kind.Object, LocationIdentity.ANY_LOCATION); Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,30 +22,18 @@ */ package com.oracle.graal.hotspot.replacements; -import java.lang.reflect.Modifier; -import java.util.Arrays; +import java.lang.reflect.*; +import java.util.*; -import com.oracle.graal.api.meta.Constant; -import com.oracle.graal.api.meta.JavaType; -import com.oracle.graal.api.meta.ResolvedJavaField; -import com.oracle.graal.api.meta.ResolvedJavaMethod; -import com.oracle.graal.api.meta.ResolvedJavaType; -import com.oracle.graal.graph.GraalInternalError; -import com.oracle.graal.graph.NodeInputList; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; -import com.oracle.graal.hotspot.meta.HotSpotResolvedJavaMethod; -import com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType; -import com.oracle.graal.hotspot.meta.HotSpotSignature; -import com.oracle.graal.nodes.CallTargetNode; -import com.oracle.graal.nodes.Invoke; -import com.oracle.graal.nodes.InvokeNode; -import com.oracle.graal.nodes.PiNode; -import com.oracle.graal.nodes.ValueNode; -import com.oracle.graal.nodes.java.MethodCallTargetNode; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.java.SelfReplacingMethodCallTargetNode; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.replacements.nodes.MacroNode; +import com.oracle.graal.replacements.nodes.*; /** * Common base class for method handle invoke nodes. @@ -281,7 +269,7 @@ // invoker's stamp would be wrong because it's a less concrete type // (usually java.lang.Object). InvokeNode invoke; - if (callTarget.returnStamp().kind() != stamp().kind()) { + if (stamp() == StampFactory.forVoid()) { invoke = new InvokeNode(callTarget, getBci(), stamp()); } else { invoke = new InvokeNode(callTarget, getBci()); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyCallNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,194 @@ +/* + * 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.replacements; + +import static com.oracle.graal.api.meta.LocationIdentity.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +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.graal.phases.*; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.runtime.*; + +public final class ArrayCopyCallNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single { + + @Input private ValueNode src; + @Input private ValueNode srcPos; + @Input private ValueNode dest; + @Input private ValueNode destPos; + @Input private ValueNode length; + + private Kind elementKind; + private boolean aligned; + private boolean disjoint; + + private ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint) { + super(StampFactory.forVoid()); + assert elementKind != null; + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.elementKind = elementKind; + this.aligned = aligned; + this.disjoint = disjoint; + } + + private ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) { + this(src, srcPos, dest, destPos, length, elementKind, false, false); + } + + public ValueNode getSource() { + return src; + } + + public ValueNode getSourcePosition() { + return srcPos; + } + + public ValueNode getDestination() { + return dest; + } + + public ValueNode getDestinationPosition() { + return destPos; + } + + @Override + public ValueNode getArray() { + return dest; + } + + @Override + public ValueNode getIndex() { + return destPos; + } + + @Override + public ValueNode getLength() { + return length; + } + + @Override + public boolean isObjectArray() { + return elementKind == Kind.Object; + } + + @Override + public boolean isInitialization() { + return false; + } + + public void addSnippetArguments(Arguments args) { + args.add("src", src); + args.add("srcPos", srcPos); + args.add("dest", dest); + args.add("destPos", destPos); + args.add("length", length); + } + + public Kind getElementKind() { + return elementKind; + } + + private boolean shouldUnroll() { + return getLength().isConstant() && getLength().asConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue(); + } + + private ValueNode computeBase(ValueNode base, ValueNode pos) { + FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base)); + graph().addBeforeFixed(this, basePtr); + ValueNode loc = IndexedLocationNode.create(getLocationIdentity(), elementKind, arrayBaseOffset(elementKind), pos, graph(), arrayIndexScale(elementKind)); + return graph().unique(new ComputeAddressNode(basePtr, loc, StampFactory.forKind(Kind.Long))); + } + + @Override + public void lower(LoweringTool tool) { + if (graph().getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + updateAlignedDisjoint(); + ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint()); + StructuredGraph graph = graph(); + ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); + ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); + ValueNode len = getLength(); + if (len.stamp().getStackKind() != Kind.Long) { + len = IntegerConvertNode.convert(len, StampFactory.forKind(Kind.Long)); + } + ForeignCallNode call = graph.add(new ForeignCallNode(Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len)); + call.setStateAfter(stateAfter()); + graph.replaceFixedWithFixed(this, call); + + } + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return ANY_LOCATION; + } + + @NodeIntrinsic + public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind); + + @NodeIntrinsic + public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, @ConstantNodeParameter boolean aligned, + @ConstantNodeParameter boolean disjoint); + + public boolean isAligned() { + return aligned; + } + + public boolean isDisjoint() { + return disjoint; + } + + public void updateAlignedDisjoint() { + Kind componentKind = elementKind; + if (srcPos == destPos) { + // Can treat as disjoint + disjoint = true; + } + Constant constantSrc = srcPos.stamp().asConstant(); + Constant constantDst = destPos.stamp().asConstant(); + if (constantSrc != null && constantDst != null) { + if (!aligned) { + aligned = ArrayCopyNode.isHeapWordAligned(constantSrc, componentKind) && ArrayCopyNode.isHeapWordAligned(constantDst, componentKind); + } + if (constantSrc.asInt() >= constantDst.asInt()) { + // low to high copy so treat as disjoint + disjoint = true; + } + } + } +} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -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); } + static boolean isHeapWordAligned(Constant value, Kind kind) { + return (arrayBaseOffset(kind) + (long) 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()); @@ -70,11 +75,14 @@ if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { return null; } - if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType()) || !ObjectStamp.isExactType(getDestination().stamp())) { + if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) { + return null; + } + if (!isExact()) { return null; } Kind componentKind = srcType.getComponentType().getKind(); - final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); + final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind, shouldUnroll(), isExact())); try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) { return replacements.getSnippet(snippetMethod); } catch (Throwable e) { @@ -115,7 +123,7 @@ } else { assert snippetGraph != null : "ArrayCopySnippets should be installed"; snippetGraph = snippetGraph.copy(); - if (getLength().isConstant() && getLength().asConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue()) { + if (shouldUnroll()) { final StructuredGraph copy = snippetGraph; try (Scope s = Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method())) { unrollFixedLengthLoop(copy, getLength().asConstant().asInt(), tool); @@ -127,6 +135,28 @@ return lowerReplacement(snippetGraph, tool); } + private boolean shouldUnroll() { + return getLength().isConstant() && getLength().asConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue(); + } + + /* + * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays. + */ + private boolean isExact() { + ResolvedJavaType srcType = ObjectStamp.typeOrNull(getSource().stamp()); + if (srcType.getComponentType().getKind().isPrimitive() || getSource() == getDestination()) { + return true; + } + + ResolvedJavaType destType = ObjectStamp.typeOrNull(getDestination().stamp()); + if (ObjectStamp.isExactType(getDestination().stamp())) { + if (destType != null && destType.isAssignableFrom(srcType)) { + return true; + } + } + return false; + } + private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { return position >= 0 && position + length <= virtualObject.entryCount(); } @@ -188,4 +218,5 @@ } } } + } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,39 +22,54 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.nodes.GuardingPiNode.*; -import static com.oracle.graal.nodes.calc.IsNullNode.*; import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*; import static com.oracle.graal.phases.GraalOptions.*; +import static com.oracle.graal.replacements.SnippetTemplate.*; import java.lang.reflect.*; 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.*; -import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.Fold; -import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.word.*; @SuppressWarnings("unused") public class ArrayCopySnippets implements Snippets { private static final EnumMap arraycopyMethods = new EnumMap<>(Kind.class); + private static final EnumMap arraycopyCalls = new EnumMap<>(Kind.class); + public static final Method genericArraycopySnippet; 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) { + arraycopyCalls.put(kind, ArrayCopySnippets.class.getDeclaredMethod("objectArraycopyUnchecked", arrayClass, int.class, arrayClass, int.class, int.class)); + } else { + arraycopyCalls.put(kind, ArrayCopySnippets.class.getDeclaredMethod(kind + "Arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); + } + } } static { @@ -74,7 +89,14 @@ } } - public static Method getSnippetForKind(Kind kind) { + public static Method getSnippetForKind(Kind kind, boolean shouldUnroll, boolean exact) { + Method m = null; + if (!shouldUnroll && exact) { + m = arraycopyCalls.get(kind); + if (m != null) { + return m; + } + } return arraycopyMethods.get(kind); } @@ -195,6 +217,62 @@ } } + @NodeIntrinsic(ForeignCallNode.class) + public static native void callArraycopy(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word src, Word dest, Word len); + + 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); + ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, kind, aligned, disjoint); + } + + @Snippet + public static void objectArraycopyUnchecked(Object[] src, int srcPos, Object[] dest, int destPos, int length) { + callArraycopyTemplate(objectCallCounter, Kind.Object, false, false, src, srcPos, dest, destPos, 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 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 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 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 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 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 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 doubleArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { + callArraycopyTemplate(doubleCallCounter, Kind.Double, false, false, 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,8 +288,19 @@ 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 objectCallCounter = new SnippetCounter(counters, "Object[]", "arraycopy call for Object[] arrays"); + + private static final SnippetCounter booleanCallCounter = new SnippetCounter(counters, "boolean[]", "arraycopy call for boolean[] arrays"); + private static final SnippetCounter byteCallCounter = new SnippetCounter(counters, "byte[]", "arraycopy call for byte[] arrays"); + private static final SnippetCounter charCallCounter = new SnippetCounter(counters, "char[]", "arraycopy call for char[] arrays"); + private static final SnippetCounter doubleCallCounter = new SnippetCounter(counters, "double[]", "arraycopy call for double[] arrays"); + private static final SnippetCounter floatCallCounter = new SnippetCounter(counters, "float[]", "arraycopy call for float[] arrays"); + private static final SnippetCounter intCallCounter = new SnippetCounter(counters, "int[]", "arraycopy call for int[] arrays"); + private static final SnippetCounter longCallCounter = new SnippetCounter(counters, "long[]", "arraycopy call for long[] arrays"); + private static final SnippetCounter shortCallCounter = new SnippetCounter(counters, "short[]", "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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -30,8 +30,8 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.replacements.Snippet.Fold; import com.oracle.graal.word.*; @@ -43,22 +43,20 @@ public class CipherBlockChainingSubstitutions { private static final long embeddedCipherOffset; - private static final LocationIdentity embeddedCipherLocationIdentity; private static final long rOffset; - private static final LocationIdentity rLocationIdentity; + private static final Class cipherBlockChainingClass; + private static final Class feedbackCipherClass; static { try { // Need to use launcher class path as com.sun.crypto.provider.AESCrypt // is normally not on the boot class path ClassLoader cl = Launcher.getLauncher().getClassLoader(); - Class feedbackCipherClass = Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl); + feedbackCipherClass = Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl); embeddedCipherOffset = UnsafeAccess.unsafe.objectFieldOffset(feedbackCipherClass.getDeclaredField("embeddedCipher")); - embeddedCipherLocationIdentity = HotSpotResolvedObjectType.fromClass(feedbackCipherClass).findInstanceFieldWithOffset(embeddedCipherOffset); - Class cipherBlockChainingClass = Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl); + cipherBlockChainingClass = Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl); rOffset = UnsafeAccess.unsafe.objectFieldOffset(cipherBlockChainingClass.getDeclaredField("r")); - rLocationIdentity = HotSpotResolvedObjectType.fromClass(cipherBlockChainingClass).findInstanceFieldWithOffset(rOffset); } catch (Exception ex) { throw new GraalInternalError(ex); } @@ -71,9 +69,10 @@ @MethodSubstitution(isStatic = false, optional = true) static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity); + Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); if (getAESCryptClass().isInstance(embeddedCipher)) { - crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); + Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); + crypt(rcvr, in, inOffset, inLength, out, outOffset, aesCipher, true); } else { encrypt(rcvr, in, inOffset, inLength, out, outOffset); } @@ -81,39 +80,46 @@ @MethodSubstitution(isStatic = false, optional = true) static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity); + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { - crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); + Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false); } else { - decrypt(rcvr, in, inOffset, inLength, out, outOffset); + decrypt(realReceiver, in, inOffset, inLength, out, outOffset); } } @MethodSubstitution(value = "encrypt", isStatic = false, optional = true) static int encryptInt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity); + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); if (getAESCryptClass().isInstance(embeddedCipher)) { - crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); + Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true); return inLength; } else { - return encryptInt(rcvr, in, inOffset, inLength, out, outOffset); + return encryptInt(realReceiver, in, inOffset, inLength, out, outOffset); } } @MethodSubstitution(value = "decrypt", isStatic = false, optional = true) static int decryptInt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity); + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { - crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); + Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false); return inLength; } else { - return decryptInt(rcvr, in, inOffset, inLength, out, outOffset); + return decryptInt(realReceiver, in, inOffset, inLength, out, outOffset); } } private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { - Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, AESCryptSubstitutions.kLocationIdentity); - Object rObject = UnsafeLoadNode.load(rcvr, rOffset, Kind.Object, rLocationIdentity); + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, Kind.Object, LocationIdentity.ANY_LOCATION); Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)); Word rAddr = (Word) Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -96,7 +96,7 @@ if (superKlass.equal(0)) { return null; } else { - return piCast(superKlass.readObject(classMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true); + return piCastExactNonNull(superKlass.readObject(classMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class); } } } @@ -110,7 +110,7 @@ Word klass = loadWordFromObject(thisObj, klassOffset()); if (klass.notEqual(0)) { if (klassIsArray(klass)) { - return piCast(klass.readObject(arrayKlassComponentMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true); + return piCastExactNonNull(klass.readObject(arrayKlassComponentMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class); } } return null; diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Wed Mar 05 19:40:15 2014 -0800 @@ -230,7 +230,7 @@ Arguments args; StructuredGraph graph = instanceOf.graph(); - if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet()) { + if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet() && hintInfo.exact == null) { Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph); args = new Arguments(instanceofWithProfile, graph.getGuardsStage(), tool.getLoweringStage()); args.add("object", object); @@ -256,7 +256,7 @@ } args.add("trueValue", replacer.trueValue); args.add("falseValue", replacer.falseValue); - if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet()) { + if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet() && hintInfo.exact == null) { args.addConst("nullSeen", hintInfo.profile.getNullSeen() != TriState.FALSE); } return args; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Wed Mar 05 19:40:15 2014 -0800 @@ -53,7 +53,7 @@ private static final boolean USE_C_RUNTIME = Boolean.getBoolean("graal.loadExceptionObject.useCRuntime"); @Snippet - public static Object loadException(@ConstantParameter Register threadRegister) { + public static Throwable loadException(@ConstantParameter Register threadRegister) { Word thread = registerAsWord(threadRegister); Object exception = readExceptionOop(thread); writeExceptionOop(thread, null); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,7 +34,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graph.iterators.*; @@ -425,7 +424,6 @@ public void lower(MonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers, LoweringTool tool) { StructuredGraph graph = monitorenterNode.graph(); checkBalancedMonitors(graph, tool); - FrameState stateAfter = monitorenterNode.stateAfter(); Arguments args; if (useFastLocking) { @@ -435,24 +433,15 @@ } args.add("object", monitorenterNode.object()); args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth()); - boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("stackPointerRegister", registers.getStackPointerRegister()); - args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || tracingEnabledForMethod); - - Map nodes = template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); + args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph.method())); - for (Node n : nodes.values()) { - if (n instanceof BeginLockScopeNode) { - BeginLockScopeNode begin = (BeginLockScopeNode) n; - begin.setStateAfter(stateAfter); - } - } + template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); } public void lower(MonitorExitNode monitorexitNode, LoweringTool tool) { StructuredGraph graph = monitorexitNode.graph(); - FrameState stateAfter = monitorexitNode.stateAfter(); Arguments args; if (useFastLocking) { @@ -462,16 +451,9 @@ } args.add("object", monitorexitNode.object()); args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth()); - args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); - - Map nodes = template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); + args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(graph.method())); - for (Node n : nodes.values()) { - if (n instanceof EndLockScopeNode) { - EndLockScopeNode end = (EndLockScopeNode) n; - end.setStateAfter(stateAfter); - } - } + template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); } static boolean isTracingEnabledForType(ValueNode object) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -41,7 +41,7 @@ @MethodSubstitution(isStatic = false, forced = true) public static Class getClass(final Object thisObj) { Word hub = loadHub(thisObj); - return piCast(hub.readObject(Word.signed(classMirrorOffset()), LocationIdentity.FINAL_LOCATION), Class.class, true, true); + return piCastExactNonNull(hub.readObject(Word.signed(classMirrorOffset()), LocationIdentity.FINAL_LOCATION), Class.class); } @MethodSubstitution(isStatic = false) diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,6 +33,7 @@ import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.word.*; @@ -44,7 +45,7 @@ @MethodSubstitution public static Thread currentThread() { - return (Thread) CurrentJavaThreadNode.get().readObject(threadObjectOffset(), LocationIdentity.FINAL_LOCATION); + return PiNode.piCastExactNonNull(CurrentJavaThreadNode.get().readObject(threadObjectOffset(), LocationIdentity.FINAL_LOCATION), Thread.class); } @MethodSubstitution(isStatic = false) diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Mar 05 19:40:15 2014 -0800 @@ -35,6 +35,7 @@ import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/GraphKit.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/GraphKit.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +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.hotspot.stubs; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.*; -import com.oracle.graal.word.phases.*; - -/** - * A utility for manually creating a graph. This will be expanded as necessary to support all - * subsystems that employ manual graph creation (as opposed to {@linkplain GraphBuilderPhase - * bytecode parsing} based graph creation). - */ -public class GraphKit { - - private final Providers providers; - private final StructuredGraph graph; - private FixedWithNextNode lastFixedNode; - - public GraphKit(StructuredGraph graph, Providers providers) { - this.providers = providers; - this.graph = graph; - this.lastFixedNode = graph.start(); - } - - public StructuredGraph getGraph() { - return graph; - } - - /** - * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}. - * - * @return a node similar to {@code node} if one exists, otherwise {@code node} - */ - protected T unique(T node) { - return graph.unique(node); - } - - /** - * Appends a fixed node to the graph. - */ - protected T append(T node) { - T result = graph.add(node); - assert lastFixedNode != null; - assert result.predecessor() == null; - graph.addAfterFixed(lastFixedNode, result); - if (result instanceof FixedWithNextNode) { - lastFixedNode = (FixedWithNextNode) result; - } else { - lastFixedNode = null; - } - return result; - } - - /** - * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of - * arguments. - * - * @param declaringClass the class declaring the invoked method - * @param name the name of the invoked method - * @param args the arguments to the invocation - */ - public InvokeNode createInvoke(Class declaringClass, String name, ValueNode... args) { - ResolvedJavaMethod method = null; - for (Method m : declaringClass.getDeclaredMethods()) { - if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) { - assert method == null : "found more than one method in " + declaringClass + " named " + name; - method = providers.getMetaAccess().lookupJavaMethod(m); - } - } - assert method != null : "did not find method in " + declaringClass + " named " + name; - Signature signature = method.getSignature(); - JavaType returnType = signature.getReturnType(null); - assert checkArgs(method, args); - MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, method, args, returnType)); - InvokeNode invoke = append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI)); - return invoke; - } - - /** - * Determines if a given set of arguments is compatible with the signature of a given method. - * - * @return true if {@code args} are compatible with the signature if {@code method} - * @throws AssertionError if {@code args} are not compatible with the signature if - * {@code method} - */ - public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) { - Signature signature = method.getSignature(); - if (signature.getParameterCount(false) != args.length) { - throw new AssertionError(graph + ": wrong number of arguments to " + method); - } - for (int i = 0; i != args.length; i++) { - Kind expected = signature.getParameterKind(i).getStackKind(); - Kind actual = args[i].stamp().kind(); - if (expected != actual) { - throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of calls to " + method + " [" + actual + " != " + expected + "]"); - } - } - return true; - } - - /** - * Rewrite all word types in the graph. - */ - public void rewriteWordTypes() { - new WordTypeRewriterPhase(providers.getMetaAccess(), providers.getCodeCache().getTarget().wordKind).apply(graph); - } - - /** - * {@linkplain #inline(InvokeNode) Inlines} all invocations currently in the graph. - */ - public void inlineInvokes() { - for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) { - inline(invoke); - } - - // Clean up all code that is now dead after inlining. - new DeadCodeEliminationPhase().apply(graph); - assert graph.getNodes().filter(InvokeNode.class).isEmpty(); - } - - /** - * Inlines a given invocation to a method. The graph of the inlined method is - * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and - * method substitutions. - */ - public void inline(InvokeNode invoke) { - ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); - ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false), providers.getCodeCache().getTarget()); - StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); - InliningUtil.inline(invoke, calleeGraph, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Wed Mar 05 19:40:15 2014 -0800 @@ -146,8 +146,8 @@ // The stub itself needs the incoming calling convention. CallingConvention incomingCc = linkage.getIncomingCallingConvention(); final CompilationResult compResult = compileGraph(graph, incomingCc, getInstalledCodeOwner(), providers, backend, codeCache.getTarget(), null, - providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), new SpeculationLog(), - providers.getSuites().getDefaultSuites(), true, new CompilationResult(), CompilationResultBuilderFactory.Default); + providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), null, providers.getSuites().getDefaultSuites(), true, + new CompilationResult(), CompilationResultBuilderFactory.Default); assert destroyedRegisters != null; try (Scope s = Debug.scope("CodeInstall")) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/TestUtil.java --- a/graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/TestUtil.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/TestUtil.java Wed Mar 05 19:40:15 2014 -0800 @@ -49,7 +49,7 @@ new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); PhaseSuite graphBuilderSuite = suitesProvider.getDefaultGraphBuilderSuite(); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); - compileGraph(graph, cc, method, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), new SpeculationLog(), - suites, true, new CompilationResult(), CompilationResultBuilderFactory.Default); + compileGraph(graph, cc, method, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null, suites, true, + new CompilationResult(), CompilationResultBuilderFactory.Default); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Wed Mar 05 19:40:15 2014 -0800 @@ -172,7 +172,7 @@ * * @param method the compiler interface method containing the code */ - public BciBlockMapping(ResolvedJavaMethod method) { + private BciBlockMapping(ResolvedJavaMethod method) { this.method = method; exceptionHandlers = method.getExceptionHandlers(); stream = new BytecodeStream(method.getCode()); @@ -879,6 +879,16 @@ } } + public static BciBlockMapping create(ResolvedJavaMethod method) { + BciBlockMapping map = new BciBlockMapping(method); + map.build(); + if (Debug.isDumpEnabled()) { + Debug.dump(map, MetaUtil.format("After block building %f %R %H.%n(%P)", method)); + } + + return map; + } + private static void loadTwo(Block block, int local) { loadOne(block, local); loadOne(block, local + 1); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Wed Mar 05 19:40:15 2014 -0800 @@ -90,7 +90,7 @@ if (kind == Kind.Object && type instanceof ResolvedJavaType) { stamp = StampFactory.declared((ResolvedJavaType) type); } else { - stamp = StampFactory.forKind(type.getKind()); + stamp = StampFactory.forKind(kind); } ParameterNode param = graph.unique(new ParameterNode(index, stamp)); storeLocal(javaIndex, param); diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -44,6 +44,7 @@ import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; @@ -67,8 +68,8 @@ public static final class RuntimeCalls { - public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", Object.class); - public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", Object.class, int.class); + public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class); + public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", IndexOutOfBoundsException.class, int.class); } /** @@ -213,16 +214,6 @@ return getName() + " " + MetaUtil.format("%H.%n(%p):%r", method); } - private BciBlockMapping createBlockMap() { - BciBlockMapping map = new BciBlockMapping(method); - map.build(); - if (Debug.isDumpEnabled()) { - Debug.dump(map, MetaUtil.format("After block building %f %R %H.%n(%P)", method)); - } - - return map; - } - protected void build() { if (PrintProfilingInformation.getValue()) { TTY.println("Profiling info for " + MetaUtil.format("%H.%n(%p)", method)); @@ -232,7 +223,7 @@ Indent indent = Debug.logAndIndent("build graph for %s", method); // compute the block map, setup exception handlers and get the entrypoint(s) - BciBlockMapping blockMap = createBlockMap(); + BciBlockMapping blockMap = BciBlockMapping.create(method); loopHeaders = blockMap.loopHeaders; lastInstr = currentGraph.start(); @@ -302,11 +293,11 @@ return unwindBlock; } - public BytecodeStream stream() { + protected BytecodeStream stream() { return stream; } - public int bci() { + protected int bci() { return stream.currentBCI(); } @@ -326,14 +317,6 @@ frameState.storeLocal(index, value); } - public static boolean covers(ExceptionHandler handler, int bci) { - return handler.getStartBCI() <= bci && bci < handler.getEndBCI(); - } - - public static boolean isCatchAll(ExceptionHandler handler) { - return handler.catchTypeCPI() == 0; - } - /** * @param type the unresolved type of the constant */ @@ -597,35 +580,35 @@ switch (opcode) { case IADD: case LADD: - v = new IntegerAddNode(result, x, y); + v = new IntegerAddNode(StampFactory.forKind(result), x, y); break; case FADD: case DADD: - v = new FloatAddNode(result, x, y, isStrictFP); + v = new FloatAddNode(StampFactory.forKind(result), x, y, isStrictFP); break; case ISUB: case LSUB: - v = new IntegerSubNode(result, x, y); + v = new IntegerSubNode(StampFactory.forKind(result), x, y); break; case FSUB: case DSUB: - v = new FloatSubNode(result, x, y, isStrictFP); + v = new FloatSubNode(StampFactory.forKind(result), x, y, isStrictFP); break; case IMUL: case LMUL: - v = new IntegerMulNode(result, x, y); + v = new IntegerMulNode(StampFactory.forKind(result), x, y); break; case FMUL: case DMUL: - v = new FloatMulNode(result, x, y, isStrictFP); + v = new FloatMulNode(StampFactory.forKind(result), x, y, isStrictFP); break; case FDIV: case DDIV: - v = new FloatDivNode(result, x, y, isStrictFP); + v = new FloatDivNode(StampFactory.forKind(result), x, y, isStrictFP); break; case FREM: case DREM: - v = new FloatRemNode(result, x, y, isStrictFP); + v = new FloatRemNode(StampFactory.forKind(result), x, y, isStrictFP); break; default: throw new GraalInternalError("should not reach"); @@ -640,11 +623,11 @@ switch (opcode) { case IDIV: case LDIV: - v = new IntegerDivNode(result, x, y); + v = new IntegerDivNode(StampFactory.forKind(result), x, y); break; case IREM: case LREM: - v = new IntegerRemNode(result, x, y); + v = new IntegerRemNode(StampFactory.forKind(result), x, y); break; default: throw new GraalInternalError("should not reach"); @@ -663,15 +646,15 @@ switch (opcode) { case ISHL: case LSHL: - v = new LeftShiftNode(kind, x, s); + v = new LeftShiftNode(StampFactory.forKind(kind), x, s); break; case ISHR: case LSHR: - v = new RightShiftNode(kind, x, s); + v = new RightShiftNode(StampFactory.forKind(kind), x, s); break; case IUSHR: case LUSHR: - v = new UnsignedRightShiftNode(kind, x, s); + v = new UnsignedRightShiftNode(StampFactory.forKind(kind), x, s); break; default: throw new GraalInternalError("should not reach"); @@ -682,19 +665,20 @@ private void genLogicOp(Kind kind, int opcode) { ValueNode y = frameState.pop(kind); ValueNode x = frameState.pop(kind); + Stamp stamp = StampFactory.forKind(kind); BitLogicNode v; switch (opcode) { case IAND: case LAND: - v = new AndNode(kind, x, y); + v = new AndNode(stamp, x, y); break; case IOR: case LOR: - v = new OrNode(kind, x, y); + v = new OrNode(stamp, x, y); break; case IXOR: case LXOR: - v = new XorNode(kind, x, y); + v = new XorNode(stamp, x, y); break; default: throw new GraalInternalError("should not reach"); @@ -708,9 +692,30 @@ frameState.ipush(append(new NormalizeCompareNode(x, y, isUnorderedLess))); } - private void genConvert(Kind from, Kind to) { + private void genFloatConvert(FloatConvert op, Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + frameState.push(to.getStackKind(), append(new FloatConvertNode(op, input))); + } + + private void genSignExtend(Kind from, Kind to) { ValueNode input = frameState.pop(from.getStackKind()); - frameState.push(to.getStackKind(), append(new ConvertNode(from, to, input))); + if (from != from.getStackKind()) { + input = append(new NarrowNode(input, from.getBitCount())); + } + frameState.push(to.getStackKind(), append(new SignExtendNode(input, to.getBitCount()))); + } + + private void genZeroExtend(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + if (from != from.getStackKind()) { + input = append(new NarrowNode(input, from.getBitCount())); + } + frameState.push(to.getStackKind(), append(new ZeroExtendNode(input, to.getBitCount()))); + } + + private void genNarrow(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + frameState.push(to.getStackKind(), append(new NarrowNode(input, to.getBitCount()))); } private void genIncrement() { @@ -718,7 +723,7 @@ int delta = stream().readIncrement(); ValueNode x = frameState.loadLocal(index); ValueNode y = appendConstant(Constant.forInt(delta)); - frameState.storeLocal(index, append(new IntegerAddNode(Kind.Int, x, y))); + frameState.storeLocal(index, append(new IntegerAddNode(StampFactory.forKind(Kind.Int), x, y))); } private void genGoto() { @@ -815,10 +820,12 @@ eagerResolvingForSnippets(cpi, opcode); JavaMethod result = constantPool.lookupMethod(cpi, opcode); /* - * assert !graphBuilderConfig.unresolvedIsError() || ((result instanceof - * ResolvedJavaMethod) && ((ResolvedJavaMethod) - * result).getDeclaringClass().isInitialized()) : result; + * In general, one cannot assume that the declaring class being initialized is useful, + * since the actual concrete receiver may be a different class (except for static + * calls). Also, interfaces are initialized only under special circumstances, so that + * this assertion would often fail for interface calls. */ + assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())); return result; } @@ -950,12 +957,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); @@ -993,6 +1004,7 @@ trueSucc.setNext(handleException(exception, bci())); } else { DeferredForeignCallNode call = currentGraph.add(new DeferredForeignCallNode(CREATE_NULL_POINTER_EXCEPTION)); + call.setStamp(StampFactory.exactNonNull(metaAccess.lookupJavaType(CREATE_NULL_POINTER_EXCEPTION.getResultType()))); call.setStateAfter(frameState.create(bci())); trueSucc.setNext(call); call.setNext(handleException(call, bci())); @@ -1017,12 +1029,15 @@ falseSucc.setNext(handleException(exception, bci())); } else { DeferredForeignCallNode call = currentGraph.add(new DeferredForeignCallNode(CREATE_OUT_OF_BOUNDS_EXCEPTION, index)); + call.setStamp(StampFactory.exactNonNull(metaAccess.lookupJavaType(CREATE_OUT_OF_BOUNDS_EXCEPTION.getResultType()))); call.setStateAfter(frameState.create(bci())); falseSucc.setNext(call); call.setNext(handleException(call, bci())); } } + private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions"); + protected void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) { assert receiver != null; if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) { @@ -1034,7 +1049,7 @@ ValueNode length = append(new ArrayLengthNode(receiver)); emitBoundsCheck(outOfBoundsIndex, length); } - Debug.metric("ExplicitExceptions").increment(); + EXPLICIT_EXCEPTIONS.increment(); } private void genPutField(JavaField field) { @@ -1067,15 +1082,6 @@ } } - private ConstantNode genTypeOrDeopt(Representation representation, JavaType type, boolean initialized) { - if (initialized) { - return appendConstant(((ResolvedJavaType) type).getEncoding(representation)); - } else { - handleUnresolvedExceptionType(representation, type); - return null; - } - } - private void appendOptimizedStoreField(StoreFieldNode store) { append(store); } @@ -1711,14 +1717,17 @@ ResolvedJavaType resolvedCatchType = (ResolvedJavaType) catchType; for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) { if (skippedType.isAssignableFrom(resolvedCatchType)) { - append(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); + Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1); + ValueNode exception = frameState.stackAt(0); + FixedNode trueSuccessor = currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); + FixedNode nextDispatch = createTarget(nextBlock, frameState); + append(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), trueSuccessor, nextDispatch, 0)); return; } } } - ConstantNode typeInstruction = genTypeOrDeopt(Representation.ObjectHub, catchType, initialized); - if (typeInstruction != null) { + if (initialized) { Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1); ValueNode exception = frameState.stackAt(0); CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false)); @@ -1730,6 +1739,8 @@ FixedNode nextDispatch = createTarget(nextBlock, frameState); checkCast.setNext(catchSuccessor); append(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), checkCast, nextDispatch, 0.5)); + } else { + handleUnresolvedExceptionType(Representation.ObjectHub, catchType); } } @@ -1991,21 +2002,21 @@ case LOR : // fall through case LXOR : genLogicOp(Kind.Long, opcode); break; case IINC : genIncrement(); break; - case I2L : genConvert(Kind.Int, Kind.Long); break; - case I2F : genConvert(Kind.Int, Kind.Float); break; - case I2D : genConvert(Kind.Int, Kind.Double); break; - case L2I : genConvert(Kind.Long, Kind.Int); break; - case L2F : genConvert(Kind.Long, Kind.Float); break; - case L2D : genConvert(Kind.Long, Kind.Double); break; - case F2I : genConvert(Kind.Float, Kind.Int); break; - case F2L : genConvert(Kind.Float, Kind.Long); break; - case F2D : genConvert(Kind.Float, Kind.Double); break; - case D2I : genConvert(Kind.Double, Kind.Int); break; - case D2L : genConvert(Kind.Double, Kind.Long); break; - case D2F : genConvert(Kind.Double, Kind.Float); break; - case I2B : genConvert(Kind.Int, Kind.Byte); break; - case I2C : genConvert(Kind.Int, Kind.Char); break; - case I2S : genConvert(Kind.Int, Kind.Short); break; + case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; + case L2I : genNarrow(Kind.Long, Kind.Int); break; + case I2L : genSignExtend(Kind.Int, Kind.Long); break; + case I2B : genSignExtend(Kind.Byte, Kind.Int); break; + case I2S : genSignExtend(Kind.Short, Kind.Int); break; + case I2C : genZeroExtend(Kind.Char, Kind.Int); break; case LCMP : genCompareOp(Kind.Long, false); break; case FCMPL : genCompareOp(Kind.Float, true); break; case FCMPG : genCompareOp(Kind.Float, false); break; diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2b.java Wed Mar 05 19:40:15 2014 -0800 @@ -53,4 +53,51 @@ 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); + } + + public static long testLong(int a) { + return (byte) a; + } + + @Test + public void runL0() throws Throwable { + runTest("testLong", -1); + } + + @Test + public void runL1() throws Throwable { + runTest("testLong", 2); + } + + @Test + public void runL2() throws Throwable { + runTest("testLong", 255); + } + + @Test + public void runL3() throws Throwable { + runTest("testLong", 128); + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2c.java Wed Mar 05 19:40:15 2014 -0800 @@ -48,4 +48,41 @@ 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); + } + + public static long testLong(int a) { + return (char) a; + } + + @Test + public void runL0() throws Throwable { + runTest("testLong", -1); + } + + @Test + public void runL1() throws Throwable { + runTest("testLong", 645); + } + + @Test + public void runL2() throws Throwable { + runTest("testLong", 65535); + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_i2s.java Wed Mar 05 19:40:15 2014 -0800 @@ -53,4 +53,51 @@ 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); + } + + public static long testLong(int a) { + return (short) a; + } + + @Test + public void runL0() throws Throwable { + runTest("testLong", -1); + } + + @Test + public void runL1() throws Throwable { + runTest("testLong", 34); + } + + @Test + public void runL2() throws Throwable { + runTest("testLong", 65535); + } + + @Test + public void runL3() throws Throwable { + runTest("testLong", 32768); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/ConvertCompare.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/ConvertCompare.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/ConvertCompare.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,4 +34,32 @@ public void run0() throws Throwable { runTest("test", 0, 2.87f); } + + public static boolean testChar42(int x) { + return ((char) x) == 42; + } + + @Test + public void run1() { + runTest("testChar42", 42); + } + + @Test + public void run2() { + runTest("testChar42", (int) Character.MAX_VALUE); + } + + public static boolean testCharMax(int x) { + return ((char) x) == Character.MAX_VALUE; + } + + @Test + public void run3() { + runTest("testCharMax", 42); + } + + @Test + public void run4() { + runTest("testCharMax", (int) Character.MAX_VALUE); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Wed Mar 05 19:40:15 2014 -0800 @@ -44,7 +44,7 @@ DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, INEG, LNEG, INOT, LNOT, SQRT, - I2L, L2I, I2B, I2C, I2S, + L2I, B2I, S2I, B2L, S2L, I2L, F2D, D2F, I2F, I2D, L2F, L2D, @@ -373,9 +373,6 @@ case L2I: masm.andl(asIntReg(result), 0xFFFFFFFF); break; - case I2C: - masm.andl(asIntReg(result), 0xFFFF); - break; default: throw GraalInternalError.shouldNotReachHere(); } @@ -495,12 +492,18 @@ masm.sqrtsd(asDoubleReg(dst), asDoubleReg(src)); break; - case I2B: + case B2I: masm.movsbl(asIntReg(dst), asIntReg(src)); break; - case I2S: + case S2I: masm.movswl(asIntReg(dst), asIntReg(src)); break; + case B2L: + masm.movsbq(asLongReg(dst), asIntReg(src)); + break; + case S2L: + masm.movswq(asLongReg(dst), asIntReg(src)); + break; case I2L: masm.movslq(asLongReg(dst), asIntReg(src)); break; @@ -551,7 +554,7 @@ case IDIV: case IREM: masm.cdql(); - exceptionOffset = masm.codeBuffer.position(); + exceptionOffset = masm.position(); masm.idivl(asRegister(src)); break; @@ -559,7 +562,7 @@ case LDIV: case LREM: masm.cdqq(); - exceptionOffset = masm.codeBuffer.position(); + exceptionOffset = masm.position(); masm.idivq(asRegister(src)); break; @@ -567,7 +570,7 @@ case IUREM: // Must zero the high 64-bit word (in RDX) of the dividend masm.xorq(AMD64.rdx, AMD64.rdx); - exceptionOffset = masm.codeBuffer.position(); + exceptionOffset = masm.position(); masm.divl(asRegister(src)); break; @@ -575,7 +578,7 @@ case LUREM: // Must zero the high 64-bit word (in RDX) of the dividend masm.xorq(AMD64.rdx, AMD64.rdx); - exceptionOffset = masm.codeBuffer.position(); + exceptionOffset = masm.position(); masm.divq(asRegister(src)); break; default: @@ -755,12 +758,18 @@ masm.sqrtsd(asDoubleReg(dst), (AMD64Address) crb.asDoubleAddr(src)); break; - case I2B: + case B2I: masm.movsbl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); break; - case I2S: + case S2I: masm.movswl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); break; + case B2L: + masm.movsbq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src)); + break; + case S2L: + masm.movswq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src)); + break; case I2L: masm.movslq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src)); break; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,295 @@ +/* + * 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.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.graph.UnsafeAccess.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import java.lang.reflect.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.amd64.AMD64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Address.Scale; +import com.oracle.graal.asm.amd64.AMD64Assembler.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.spi.*; + +/** + * Emits code which compares two arrays of the same length. If the CPU supports any vector + * instructions specialized code is emitted to leverage these instructions. + */ +@Opcode("ARRAY_EQUALS") +public class AMD64ArrayEqualsOp extends AMD64LIRInstruction { + + private final Kind kind; + private final int arrayBaseOffset; + private final int arrayIndexScale; + + @Def({REG}) protected Value resultValue; + @Alive({REG}) protected Value array1Value; + @Alive({REG}) protected Value array2Value; + @Alive({REG}) protected Value lengthValue; + @Temp({REG}) protected Value temp1; + @Temp({REG}) protected Value temp2; + @Temp({REG}) protected Value temp3; + @Temp({REG}) protected Value temp4; + @Temp({REG}) protected Value vectorTemp1; + @Temp({REG}) protected Value vectorTemp2; + + public AMD64ArrayEqualsOp(LIRGeneratorTool tool, Kind kind, Value result, Value array1, Value array2, Value length) { + this.kind = kind; + + Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); + this.arrayBaseOffset = unsafe.arrayBaseOffset(arrayClass); + this.arrayIndexScale = unsafe.arrayIndexScale(arrayClass); + + this.resultValue = result; + this.array1Value = array1; + this.array2Value = array2; + this.lengthValue = length; + + // Allocate some temporaries. + this.temp1 = tool.newVariable(tool.target().wordKind); + this.temp2 = tool.newVariable(tool.target().wordKind); + this.temp3 = tool.newVariable(tool.target().wordKind); + this.temp4 = tool.newVariable(tool.target().wordKind); + + // We only need the vector temporaries if we generate SSE code. + if (supportsSSE41(tool.target())) { + this.vectorTemp1 = tool.newVariable(Kind.Double); + this.vectorTemp2 = tool.newVariable(Kind.Double); + } + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register result = asRegister(resultValue); + Register array1 = asRegister(temp1); + Register array2 = asRegister(temp2); + Register length = asRegister(temp3); + + Label trueLabel = new Label(); + Label falseLabel = new Label(); + Label done = new Label(); + + // Load array base addresses. + masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset)); + masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset)); + + // Get array length in bytes. + masm.imull(length, asRegister(lengthValue), arrayIndexScale); + masm.movl(result, length); // copy + + if (supportsSSE41(crb.target)) { + emitSSE41Compare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); + } + + emit8ByteCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); + emitTailCompares(masm, result, array1, array2, length, trueLabel, falseLabel); + + // Return true + masm.bind(trueLabel); + masm.movl(result, 1); + masm.jmpb(done); + + // Return false + masm.bind(falseLabel); + masm.xorl(result, result); + + // That's it + masm.bind(done); + } + + /** + * Returns if the underlying AMD64 architecture supports SSE 4.1 instructions. + * + * @param target target description of the underlying architecture + * @return true if the underlying architecture supports SSE 4.1 + */ + private static boolean supportsSSE41(TargetDescription target) { + AMD64 arch = (AMD64) target.arch; + return arch.getFeatures().contains(CPUFeature.SSE4_1); + } + + /** + * Vector size used in {@link #emitSSE41Compare}. + */ + private static final int SSE4_1_VECTOR_SIZE = 16; + + /** + * Emits code that uses SSE4.1 128-bit (16-byte) vector compares. + */ + private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + assert supportsSSE41(crb.target); + + Register vector1 = asDoubleReg(vectorTemp1); + Register vector2 = asDoubleReg(vectorTemp2); + + Label loop = new Label(); + Label compareTail = new Label(); + + // Compare 16-byte vectors + masm.andl(result, SSE4_1_VECTOR_SIZE - 1); // tail count (in bytes) + masm.andl(length, ~(SSE4_1_VECTOR_SIZE - 1)); // vector count (in bytes) + masm.jccb(ConditionFlag.Zero, compareTail); + + masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.negq(length); + + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + masm.movdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.pxor(vector1, vector2); + masm.ptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.addq(length, SSE4_1_VECTOR_SIZE); + masm.jcc(ConditionFlag.NotZero, loop); + + masm.testl(result, result); + masm.jcc(ConditionFlag.Zero, trueLabel); + + /* + * Compare the remaining bytes with an unaligned memory load aligned to the end of the + * array. + */ + masm.movdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); + masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); + masm.pxor(vector1, vector2); + masm.ptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.jmp(trueLabel); + + masm.bind(compareTail); + masm.movl(length, result); + } + + /** + * Vector size used in {@link #emit8ByteCompare}. + */ + private static final int VECTOR_SIZE = 8; + + /** + * Emits code that uses 8-byte vector compares. + */ + private void emit8ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + Label loop = new Label(); + Label compareTail = new Label(); + + Register temp = asRegister(temp4); + + masm.andl(result, VECTOR_SIZE - 1); // tail count (in bytes) + masm.andl(length, ~(VECTOR_SIZE - 1)); // vector count (in bytes) + masm.jccb(ConditionFlag.Zero, compareTail); + + masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.negq(length); + + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + masm.movq(temp, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.cmpq(temp, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + masm.addq(length, VECTOR_SIZE); + masm.jccb(ConditionFlag.NotZero, loop); + + masm.testl(result, result); + masm.jccb(ConditionFlag.Zero, trueLabel); + + /* + * Compare the remaining bytes with an unaligned memory load aligned to the end of the + * array. + */ + masm.movq(temp, new AMD64Address(array1, result, Scale.Times1, -VECTOR_SIZE)); + masm.cmpq(temp, new AMD64Address(array2, result, Scale.Times1, -VECTOR_SIZE)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + masm.jmpb(trueLabel); + + masm.bind(compareTail); + masm.movl(length, result); + } + + /** + * Emits code to compare the remaining 1 to 4 bytes. + */ + private void emitTailCompares(AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + Label compare2Bytes = new Label(); + Label compare1Byte = new Label(); + + Register temp = asRegister(temp4); + + if (kind.getByteCount() <= 4) { + // Compare trailing 4 bytes, if any. + masm.testl(result, 4); + masm.jccb(ConditionFlag.Zero, compare2Bytes); + masm.movl(temp, new AMD64Address(array1, 0)); + masm.cmpl(temp, new AMD64Address(array2, 0)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + + if (kind.getByteCount() <= 2) { + // Move array pointers forward. + masm.leaq(array1, new AMD64Address(array1, 4)); + masm.leaq(array2, new AMD64Address(array2, 4)); + + // Compare trailing 2 bytes, if any. + masm.bind(compare2Bytes); + masm.testl(result, 2); + masm.jccb(ConditionFlag.Zero, compare1Byte); + masm.movzwl(temp, new AMD64Address(array1, 0)); + masm.movzwl(length, new AMD64Address(array2, 0)); + masm.cmpl(temp, length); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + + // The one-byte tail compare is only required for boolean and byte arrays. + if (kind.getByteCount() <= 1) { + // Move array pointers forward before we compare the last trailing byte. + masm.leaq(array1, new AMD64Address(array1, 2)); + masm.leaq(array2, new AMD64Address(array2, 2)); + + // Compare trailing byte, if any. + masm.bind(compare1Byte); + masm.testl(result, 1); + masm.jccb(ConditionFlag.Zero, trueLabel); + masm.movzbl(temp, new AMD64Address(array1, 0)); + masm.movzbl(length, new AMD64Address(array2, 0)); + masm.cmpl(temp, length); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + } else { + masm.bind(compare1Byte); + } + } else { + masm.bind(compare2Bytes); + } + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CCall.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,62 @@ +/* + * 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.lir.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64CCall extends AMD64LIRInstruction { + + @Def({REG, ILLEGAL}) protected Value result; + @Use({REG, STACK}) protected Value[] parameters; + @Use({REG}) protected Value functionPtr; + @Use({REG}) protected Value numberOfFloatingPointArguments; + + public AMD64CCall(Value result, Value functionPtr, Value numberOfFloatingPointArguments, Value[] parameters) { + this.result = result; + this.functionPtr = functionPtr; + this.parameters = parameters; + this.numberOfFloatingPointArguments = numberOfFloatingPointArguments; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + directCall(masm); + } + + private void directCall(AMD64MacroAssembler masm) { + Register reg = ValueUtil.asRegister(functionPtr); + masm.call(reg); + masm.ensureUniquePC(); + } + + @Override + public boolean destroysCallerSavedRegisters() { + return true; + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Wed Mar 05 19:40:15 2014 -0800 @@ -155,7 +155,7 @@ if (align) { emitAlignmentForDirectCall(crb, masm); } - int before = masm.codeBuffer.position(); + int before = masm.position(); if (scratch != null) { // offset might not fit a 32-bit immediate, generate an // indirect call with a 64-bit immediate @@ -164,7 +164,7 @@ } else { masm.call(); } - int after = masm.codeBuffer.position(); + int after = masm.position(); crb.recordDirectCall(before, after, callTarget, info); crb.recordExceptionHandlers(after, info); masm.ensureUniquePC(); @@ -172,7 +172,7 @@ protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) { // make sure that the displacement word of the call ends up word aligned - int offset = masm.codeBuffer.position(); + int offset = masm.position(); offset += crb.target.arch.getMachineCodeCallDisplacementOffset(); int modulus = crb.target.wordSize; if (offset % modulus != 0) { @@ -181,25 +181,25 @@ } public static void directJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target) { - int before = masm.codeBuffer.position(); + int before = masm.position(); masm.jmp(0, true); - int after = masm.codeBuffer.position(); + int after = masm.position(); crb.recordDirectCall(before, after, target, null); masm.ensureUniquePC(); } public static void directConditionalJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) { - int before = masm.codeBuffer.position(); + int before = masm.position(); masm.jcc(cond, 0, true); - int after = masm.codeBuffer.position(); + int after = masm.position(); crb.recordDirectCall(before, after, target, null); masm.ensureUniquePC(); } public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { - int before = masm.codeBuffer.position(); + int before = masm.position(); masm.call(dst); - int after = masm.codeBuffer.position(); + int after = masm.position(); crb.recordIndirectCall(before, after, callTarget, info); crb.recordExceptionHandlers(after, info); masm.ensureUniquePC(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CharArrayEqualsOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CharArrayEqualsOp.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +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.graal.lir.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import sun.misc.*; - -import com.oracle.graal.amd64.*; -import com.oracle.graal.amd64.AMD64.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.asm.amd64.AMD64Address.Scale; -import com.oracle.graal.asm.amd64.AMD64Assembler.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.spi.*; - -/** - * Emits code which compares two {@code char[]}. If the CPU supports any vector instructions - * specialized code is emitted to leverage these instructions. - */ -@Opcode("CHAR_ARRAY_EQUALS") -public class AMD64CharArrayEqualsOp extends AMD64LIRInstruction { - - @Def({REG}) protected Value resultValue; - @Alive({REG}) protected Value array1Value; - @Alive({REG}) protected Value array2Value; - @Alive({REG}) protected Value lengthValue; - @Temp({REG}) protected Value temp1; - @Temp({REG}) protected Value temp2; - @Temp({REG}) protected Value temp3; - @Temp({REG}) protected Value temp4; - @Temp({REG}) protected Value vectorTemp1; - @Temp({REG}) protected Value vectorTemp2; - - public AMD64CharArrayEqualsOp(LIRGeneratorTool tool, Value result, Value array1, Value array2, Value length) { - this.resultValue = result; - this.array1Value = array1; - this.array2Value = array2; - this.lengthValue = length; - - // Allocate some temporaries. - this.temp1 = tool.newVariable(tool.target().wordKind); - this.temp2 = tool.newVariable(tool.target().wordKind); - this.temp3 = tool.newVariable(tool.target().wordKind); - this.temp4 = tool.newVariable(tool.target().wordKind); - - // We only need the vector temporaries if we generate SSE code. - if (supportsSSE41(tool.target())) { - this.vectorTemp1 = tool.newVariable(Kind.Double); - this.vectorTemp2 = tool.newVariable(Kind.Double); - } - } - - /** - * Returns if the underlying AMD64 architecture supports SSE 4.1 instructions. - * - * @param target target description of the underlying architecture - * @return true if the underlying architecture supports SSE 4.1 - */ - private static boolean supportsSSE41(TargetDescription target) { - AMD64 arch = (AMD64) target.arch; - return arch.getFeatures().contains(CPUFeature.SSE4_1); - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - Register result = asRegister(resultValue); - Register array1 = asRegister(temp1); - Register array2 = asRegister(temp2); - Register length = asRegister(temp3); - - Label trueLabel = new Label(); - Label falseLabel = new Label(); - - // Load array base addresses. - masm.leaq(array1, new AMD64Address(asRegister(array1Value), Unsafe.ARRAY_CHAR_BASE_OFFSET)); - masm.leaq(array2, new AMD64Address(asRegister(array2Value), Unsafe.ARRAY_CHAR_BASE_OFFSET)); - - masm.movq(length, asRegister(lengthValue)); - masm.shll(length, 1); // get length in bytes - masm.movl(result, length); // copy - - if (supportsSSE41(crb.target)) { - emitSSE41Compare(crb, masm, result, array1, array2, length, falseLabel, trueLabel); - // Fall-through to tail compare. - } - emit4ByteCompare(crb, masm, result, array1, array2, length, falseLabel, trueLabel); - } - - /** - * Vector size used in {@link #emit4ByteCompare}. - */ - private static final int VECTOR_SIZE = 4; - - /** - * Emits code that uses 4-byte vector compares. - */ - private void emit4ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label falseLabel, Label trueLabel) { - Label compareVectors = new Label(); - Label compareChar = new Label(); - Label done = new Label(); - Register temp = asRegister(temp4); - - masm.andl(length, 0xfffffffc); // vector count (in bytes) - masm.jccb(ConditionFlag.Zero, compareChar); - - masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.negq(length); - - // Align the main loop - masm.align(crb.target.wordSize * 2); - masm.bind(compareVectors); - masm.movl(temp, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.cmpl(temp, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.jccb(ConditionFlag.NotEqual, falseLabel); - masm.addq(length, VECTOR_SIZE); - masm.jcc(ConditionFlag.NotZero, compareVectors); - - // Compare trailing char (final 2 bytes), if any - masm.bind(compareChar); - masm.testl(result, 0x2); // tail char - masm.jccb(ConditionFlag.Zero, trueLabel); - masm.movzwl(temp, new AMD64Address(array1, 0)); - masm.movzwl(length, new AMD64Address(array2, 0)); - masm.cmpl(temp, length); - masm.jccb(ConditionFlag.NotEqual, falseLabel); - - masm.bind(trueLabel); - masm.movl(result, 1); // return true - masm.jmpb(done); - - masm.bind(falseLabel); - masm.xorl(result, result); // return false - - // That's it - masm.bind(done); - } - - /** - * Vector size used in {@link #emitSSE41Compare}. - */ - private static final int SSE4_1_VECTOR_SIZE = 16; - - /** - * Emits code that uses SSE4.1 128-bit (16-byte) vector compares. - */ - private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label falseLabel, Label trueLabel) { - assert supportsSSE41(crb.target); - - Register vector1 = asDoubleReg(vectorTemp1); - Register vector2 = asDoubleReg(vectorTemp2); - - Label compareWideVectors = new Label(); - Label compareTail = new Label(); - - // Compare 16-byte vectors - masm.andl(result, 0x0000000e); // tail count (in bytes) - masm.andl(length, 0xfffffff0); // vector count (in bytes) - masm.jccb(ConditionFlag.Zero, compareTail); - - masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.negq(length); - - // Align the main loop - masm.align(crb.target.wordSize * 2); - masm.bind(compareWideVectors); - masm.movdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.pxor(vector1, vector2); - - masm.ptest(vector1, vector1); - masm.jccb(ConditionFlag.NotZero, falseLabel); - masm.addq(length, SSE4_1_VECTOR_SIZE); - masm.jcc(ConditionFlag.NotZero, compareWideVectors); - - masm.testl(result, result); - masm.jccb(ConditionFlag.Zero, trueLabel); - - masm.movdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); - masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); - masm.pxor(vector1, vector2); - - masm.ptest(vector1, vector1); - masm.jccb(ConditionFlag.NotZero, falseLabel); - masm.jmpb(trueLabel); - - masm.bind(compareTail); // length is zero - masm.movl(length, result); - } -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Wed Mar 05 19:40:15 2014 -0800 @@ -61,25 +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 (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()); } } @@ -91,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; } @@ -184,7 +198,6 @@ masm.movl(idxScratchReg, indexReg); } - Buffer buf = masm.codeBuffer; // Compare index against jump table bounds int highKey = lowKey + targets.length - 1; if (lowKey != 0) { @@ -201,9 +214,8 @@ } // Set scratch to address of jump table - int leaPos = buf.position(); masm.leaq(scratchReg, new AMD64Address(AMD64.rip, 0)); - int afterLea = buf.position(); + final int afterLea = masm.position(); // Load jump table entry into scratch and jump to it masm.movslq(idxScratchReg, new AMD64Address(scratchReg, idxScratchReg, Scale.Times4, 0)); @@ -211,29 +223,29 @@ masm.jmp(scratchReg); // Inserting padding so that jump table address is 4-byte aligned - if ((buf.position() & 0x3) != 0) { - masm.nop(4 - (buf.position() & 0x3)); + if ((masm.position() & 0x3) != 0) { + masm.nop(4 - (masm.position() & 0x3)); } // Patch LEA instruction above now that we know the position of the jump table - int jumpTablePos = buf.position(); - buf.setPosition(leaPos); - masm.leaq(scratchReg, new AMD64Address(AMD64.rip, jumpTablePos - afterLea)); - buf.setPosition(jumpTablePos); + // TODO this is ugly and should be done differently + final int jumpTablePos = masm.position(); + final int leaDisplacementPosition = afterLea - 4; + masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition); // Emit jump table entries for (LabelRef target : targets) { Label label = target.label(); - int offsetToJumpTableBase = buf.position() - jumpTablePos; + int offsetToJumpTableBase = masm.position() - jumpTablePos; if (label.isBound()) { int imm32 = label.position() - jumpTablePos; - buf.emitInt(imm32); + masm.emitInt(imm32); } else { - label.addPatchAt(buf.position()); + label.addPatchAt(masm.position()); - buf.emitByte(0); // pseudo-opcode for jump table entry - buf.emitShort(offsetToJumpTableBase); - buf.emitByte(0); // padding to make jump table entry 4 bytes wide + masm.emitByte(0); // pseudo-opcode for jump table entry + masm.emitShort(offsetToJumpTableBase); + masm.emitByte(0); // padding to make jump table entry 4 bytes wide } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java Wed Mar 05 19:40:15 2014 -0800 @@ -101,4 +101,9 @@ protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) { return StackSlot.get(kind, -spillSize + additionalOffset, true); } + + @Override + public LIRInstruction createSpillMove(AllocatableValue result, Value input) { + return AMD64Move.createMove(result, input); + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Wed Mar 05 19:40:15 2014 -0800 @@ -41,6 +41,16 @@ public class AMD64Move { + public static AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { + if (src instanceof AMD64AddressValue) { + return new LeaOp(dst, (AMD64AddressValue) src); + } else if (isRegister(src) || isStackSlot(dst)) { + return new MoveFromRegOp(dst, src); + } else { + return new MoveToRegOp(dst, src); + } + } + @Opcode("MOVE") public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp { @@ -112,7 +122,7 @@ @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { if (state != null) { - crb.recordImplicitException(masm.codeBuffer.position(), state); + crb.recordImplicitException(masm.position(), state); } emitMemAccess(crb, masm); } @@ -139,6 +149,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; @@ -317,7 +329,7 @@ @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - crb.recordImplicitException(masm.codeBuffer.position(), state); + crb.recordImplicitException(masm.position(), state); masm.nullCheck(asRegister(input)); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java Wed Mar 05 19:40:15 2014 -0800 @@ -105,12 +105,12 @@ UNDEF; public static class ConvertOp extends HSAILLIRInstruction { - private final Kind from; - private final Kind to; + private final String from; + private final String to; @Def({REG}) protected AllocatableValue result; @Use({REG, STACK}) protected AllocatableValue x; - public ConvertOp(AllocatableValue result, AllocatableValue x, Kind to, Kind from) { + public ConvertOp(AllocatableValue result, AllocatableValue x, String to, String from) { this.from = from; this.to = to; this.result = result; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILFrameMap.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILFrameMap.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILFrameMap.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,9 +22,12 @@ */ package com.oracle.graal.lir.hsail; +import static com.oracle.graal.api.code.ValueUtil.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.lir.*; +import com.oracle.graal.lir.hsail.HSAILMove.*; /** * HSAIL specific frame map. @@ -69,4 +72,15 @@ protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) { return StackSlot.get(kind, -spillSize + additionalOffset, true); } + + @Override + public LIRInstruction createSpillMove(AllocatableValue dst, Value src) { + if (src instanceof HSAILAddressValue) { + return new LeaOp(dst, (HSAILAddressValue) src); + } else if (isRegister(src) || isStackSlot(dst)) { + return new MoveFromRegOp(dst, src); + } else { + return new MoveToRegOp(dst, src); + } + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Wed Mar 05 19:40:15 2014 -0800 @@ -146,7 +146,7 @@ @Override public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { if (state != null) { - // crb.recordImplicitException(masm.codeBuffer.position(), state); + // crb.recordImplicitException(masm.position(), state); throw new InternalError("NYI"); } emitMemAccess(masm); @@ -200,6 +200,56 @@ } } + public static class StoreConstantOp extends MemOp { + + protected final Constant input; + + public StoreConstantOp(Kind kind, HSAILAddressValue address, Constant input, LIRFrameState state) { + super(kind, address, state); + this.input = input; + } + + @Override + public void emitMemAccess(HSAILAssembler masm) { + switch (kind) { + case Boolean: + case Byte: + masm.emitStoreImmediate(kind, input.asLong() & 0xFF, address.toAddress()); + break; + case Char: + case Short: + masm.emitStoreImmediate(kind, input.asLong() & 0xFFFF, address.toAddress()); + break; + case Int: + case Long: + masm.emitStoreImmediate(kind, input.asLong(), address.toAddress()); + break; + case Float: + masm.emitStoreImmediate(input.asFloat(), address.toAddress()); + break; + case Double: + masm.emitStoreImmediate(input.asDouble(), address.toAddress()); + break; + case Object: + if (input.isNull()) { + masm.emitStoreImmediate(kind, 0L, address.toAddress()); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to object ref"); + } + break; + case NarrowOop: + if (input.isNull()) { + masm.emitStoreImmediate(kind, 0L, address.toAddress()); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to object ref"); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + public static class LoadCompressedPointer extends LoadOp { private final long base; @@ -255,7 +305,7 @@ encodePointer(masm, scratch, base, shift, alignment, testForNull); if (state != null) { throw new InternalError("NYI"); - // crb.recordImplicitException(masm.codeBuffer.position(), state); + // crb.recordImplicitException(masm.position(), state); } masm.emitStore(scratch, address.toAddress(), "u32"); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Wed Mar 05 19:40:15 2014 -0800 @@ -86,9 +86,9 @@ @Override public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { if (crb.isSuccessorEdge(trueDestination)) { - masm.bra(masm.nameOf(falseDestination.label()), predRegNum); + masm.bra(masm.nameOf(falseDestination.label()), predRegNum, false); } else { - masm.bra(masm.nameOf(trueDestination.label())); + masm.bra(masm.nameOf(trueDestination.label()), predRegNum, true); if (!crb.isSuccessorEdge(falseDestination)) { masm.jmp(falseDestination.label()); } @@ -238,7 +238,7 @@ default: throw new GraalInternalError("switch only supported for int, long and object"); } - masm.bra(masm.nameOf(target), predRegNum); + masm.bra(masm.nameOf(target), predRegNum, true); } }; strategy.run(closure); @@ -266,8 +266,6 @@ @Override public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { - Buffer buf = masm.codeBuffer; - // Compare index against jump table bounds int highKey = lowKey + targets.length - 1; @@ -281,11 +279,11 @@ // Jump to default target if index is not within the jump table if (defaultTarget != null) { - masm.bra(masm.nameOf(defaultTarget.label()), predRegNum); + masm.bra(masm.nameOf(defaultTarget.label()), predRegNum, true); } // address of jump table - int tablePos = buf.position(); + int tablePos = masm.position(); JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); String name = "jumptable" + jt.position; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXFrameMap.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXFrameMap.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXFrameMap.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; /** @@ -69,4 +70,10 @@ protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) { return StackSlot.get(kind, -spillSize + additionalOffset, true); } + + @Override + public LIRInstruction createSpillMove(AllocatableValue result, Value input) { + throw GraalInternalError.shouldNotReachHere("Spill moves should never be necessary for PTX code"); + } + } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMemOp.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMemOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMemOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -54,6 +54,7 @@ public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { PTXAddress addr = address.toAddress(); switch (kind) { + case Boolean: case Byte: case Short: case Char: diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Wed Mar 05 19:40:15 2014 -0800 @@ -252,7 +252,7 @@ @Override public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { - crb.recordImplicitException(masm.codeBuffer.position(), state); + crb.recordImplicitException(masm.position(), state); masm.nullCheck(asRegister(input)); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Wed Mar 05 19:40:15 2014 -0800 @@ -490,6 +490,13 @@ } } else if (isConstant(src2)) { switch (opcode) { + case IREM: + assert isSimm13(crb.asIntConst(src2)); + new Sra(asIntReg(src1), 0, asIntReg(src1)).emit(masm); + new Sdivx(asIntReg(src1), crb.asIntConst(src2), asIntReg(scratch1)).emit(masm); + new Mulx(asIntReg(scratch1), crb.asIntConst(src2), asIntReg(scratch2)).emit(masm); + new Sub(asIntReg(src1), asIntReg(scratch2), asIntReg(dst)).emit(masm); + break; case LREM: assert isSimm13(crb.asIntConst(src2)); new Sdivx(asLongReg(src1), crb.asIntConst(src2), asLongReg(scratch1)).emit(masm); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java Wed Mar 05 19:40:15 2014 -0800 @@ -147,7 +147,7 @@ if (align) { // We don't need alignment on SPARC. } - int before = masm.codeBuffer.position(); + int before = masm.position(); if (scratch != null) { // offset might not fit a 30-bit displacement, generate an // indirect call with a 64-bit immediate @@ -156,7 +156,7 @@ } else { new Call(0).emit(masm); } - int after = masm.codeBuffer.position(); + int after = masm.position(); crb.recordDirectCall(before, after, callTarget, info); crb.recordExceptionHandlers(after, info); new Nop().emit(masm); // delay slot @@ -164,19 +164,19 @@ } public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) { - int before = masm.codeBuffer.position(); + int before = masm.position(); new Sethix(0L, dst, true).emit(masm); new Jmp(new SPARCAddress(dst, 0)).emit(masm); - int after = masm.codeBuffer.position(); + int after = masm.position(); crb.recordIndirectCall(before, after, target, null); new Nop().emit(masm); // delay slot masm.ensureUniquePC(); } public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { - int before = masm.codeBuffer.position(); + int before = masm.position(); new Jmpl(dst, 0, o7).emit(masm); - int after = masm.codeBuffer.position(); + int after = masm.position(); crb.recordIndirectCall(before, after, callTarget, info); crb.recordExceptionHandlers(after, info); new Nop().emit(masm); // delay slot diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Wed Mar 05 19:40:15 2014 -0800 @@ -57,6 +57,26 @@ public class SPARCControlFlow { + public static class ReturnOp extends SPARCLIRInstruction implements BlockEndOp { + + @Use({REG, ILLEGAL}) protected Value x; + + public ReturnOp(Value x) { + this.x = x; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + emitCodeHelper(crb, masm); + } + + public static void emitCodeHelper(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + new Ret().emit(masm); + // On SPARC we always leave the frame (in the delay slot). + crb.frameContext.leave(crb); + } + } + public static class BranchOp extends SPARCLIRInstruction implements StandardOp.BranchOp { protected final Condition condition; @@ -132,6 +152,121 @@ } } + public static class StrategySwitchOp extends SPARCLIRInstruction implements BlockEndOp { + @Use({CONST}) protected Constant[] keyConstants; + private final LabelRef[] keyTargets; + private LabelRef defaultTarget; + @Alive({REG}) protected Value key; + @Temp({REG, ILLEGAL}) protected Value scratch; + private final SwitchStrategy strategy; + + public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { + this.strategy = strategy; + this.keyConstants = strategy.keyConstants; + this.keyTargets = keyTargets; + this.defaultTarget = defaultTarget; + this.key = key; + this.scratch = scratch; + assert keyConstants.length == keyTargets.length; + assert keyConstants.length == strategy.keyProbabilities.length; + assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int); + } + + @Override + public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) { + final Register keyRegister = asRegister(key); + + BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) { + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + switch (key.getKind()) { + case Int: + if (crb.codeCache.needsDataPatch(keyConstants[index])) { + crb.recordInlineDataInCode(keyConstants[index]); + } + long lc = keyConstants[index].asLong(); + assert NumUtil.isInt(lc); + new Cmp(keyRegister, (int) lc).emit(masm); + emitCompare(masm, target, condition, CC.Icc); + break; + case Long: { + Register temp = asLongReg(scratch); + SPARCMove.move(crb, masm, temp.asValue(Kind.Long), keyConstants[index]); + new Cmp(keyRegister, temp).emit(masm); + emitCompare(masm, target, condition, CC.Xcc); + break; + } + case Object: { + Register temp = asObjectReg(scratch); + SPARCMove.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]); + new Cmp(keyRegister, temp).emit(masm); + emitCompare(masm, target, condition, CC.Ptrcc); + break; + } + default: + throw new GraalInternalError("switch only supported for int, long and object"); + } + new Nop().emit(masm); // delay slot + } + }; + strategy.run(closure); + } + } + + public static class TableSwitchOp extends SPARCLIRInstruction implements BlockEndOp { + + private final int lowKey; + private final LabelRef defaultTarget; + private final LabelRef[] targets; + @Alive protected Value index; + @Temp protected Value scratch; + + public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) { + this.lowKey = lowKey; + this.defaultTarget = defaultTarget; + this.targets = targets; + this.index = index; + this.scratch = scratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register value = asIntReg(index); + Register scratchReg = asLongReg(scratch); + + // Compare index against jump table bounds + int highKey = lowKey + targets.length - 1; + if (lowKey != 0) { + // subtract the low value from the switch value + new Sub(value, lowKey, value).emit(masm); + // masm.setp_gt_s32(value, highKey - lowKey); + } else { + // masm.setp_gt_s32(value, highKey); + } + + // Jump to default target if index is not within the jump table + if (defaultTarget != null) { + new Bpgu(CC.Icc, defaultTarget.label()).emit(masm); + new Nop().emit(masm); // delay slot + } + + // Load jump table entry into scratch and jump to it + // masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0)); + // masm.addq(scratch, value); + new Jmp(new SPARCAddress(scratchReg, 0)).emit(masm); + new Nop().emit(masm); // delay slot + + // address of jump table + int tablePos = masm.position(); + + JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); + crb.compilationResult.addAnnotation(jt); + + // SPARC: unimp: tableswitch extract + throw GraalInternalError.unimplemented(); + } + } + @Opcode("CMOVE") public static class CondMoveOp extends SPARCLIRInstruction { @@ -262,140 +397,4 @@ throw GraalInternalError.shouldNotReachHere(); } } - - public static class ReturnOp extends SPARCLIRInstruction { - - @Use({REG, ILLEGAL}) protected Value x; - - public ReturnOp(Value x) { - this.x = x; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - emitCodeHelper(crb, masm); - } - - public static void emitCodeHelper(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - new Ret().emit(masm); - // On SPARC we always leave the frame (in the delay slot). - crb.frameContext.leave(crb); - } - } - - public static class StrategySwitchOp extends SPARCLIRInstruction implements BlockEndOp { - @Use({CONST}) protected Constant[] keyConstants; - private final LabelRef[] keyTargets; - private LabelRef defaultTarget; - @Alive({REG}) protected Value key; - @Temp({REG, ILLEGAL}) protected Value scratch; - private final SwitchStrategy strategy; - - public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { - this.strategy = strategy; - this.keyConstants = strategy.keyConstants; - this.keyTargets = keyTargets; - this.defaultTarget = defaultTarget; - this.key = key; - this.scratch = scratch; - assert keyConstants.length == keyTargets.length; - assert keyConstants.length == strategy.keyProbabilities.length; - assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int); - } - - @Override - public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) { - final Register keyRegister = asRegister(key); - - BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) { - @Override - protected void conditionalJump(int index, Condition condition, Label target) { - switch (key.getKind()) { - case Int: - if (crb.codeCache.needsDataPatch(keyConstants[index])) { - crb.recordInlineDataInCode(keyConstants[index]); - } - long lc = keyConstants[index].asLong(); - assert NumUtil.isInt(lc); - new Cmp(keyRegister, (int) lc).emit(masm); - emitCompare(masm, target, condition, CC.Icc); - break; - case Long: { - Register temp = asLongReg(scratch); - SPARCMove.move(crb, masm, temp.asValue(Kind.Long), keyConstants[index]); - new Cmp(keyRegister, temp).emit(masm); - emitCompare(masm, target, condition, CC.Xcc); - break; - } - case Object: { - Register temp = asObjectReg(scratch); - SPARCMove.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]); - new Cmp(keyRegister, temp).emit(masm); - emitCompare(masm, target, condition, CC.Ptrcc); - break; - } - default: - throw new GraalInternalError("switch only supported for int, long and object"); - } - new Nop().emit(masm); // delay slot - } - }; - strategy.run(closure); - } - } - - public static class TableSwitchOp extends SPARCLIRInstruction implements BlockEndOp { - - private final int lowKey; - private final LabelRef defaultTarget; - private final LabelRef[] targets; - @Alive protected Value index; - @Temp protected Value scratch; - - public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) { - this.lowKey = lowKey; - this.defaultTarget = defaultTarget; - this.targets = targets; - this.index = index; - this.scratch = scratch; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register value = asIntReg(index); - Register scratchReg = asLongReg(scratch); - - Buffer buf = masm.codeBuffer; - // Compare index against jump table bounds - int highKey = lowKey + targets.length - 1; - if (lowKey != 0) { - // subtract the low value from the switch value - new Sub(value, lowKey, value).emit(masm); - // masm.setp_gt_s32(value, highKey - lowKey); - } else { - // masm.setp_gt_s32(value, highKey); - } - - // Jump to default target if index is not within the jump table - if (defaultTarget != null) { - new Bpgu(CC.Icc, defaultTarget.label()).emit(masm); - new Nop().emit(masm); // delay slot - } - - // Load jump table entry into scratch and jump to it - // masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0)); - // masm.addq(scratch, value); - new Jmp(new SPARCAddress(scratchReg, 0)).emit(masm); - new Nop().emit(masm); // delay slot - - // address of jump table - int tablePos = buf.position(); - - JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); - crb.compilationResult.addAnnotation(jt); - - // SPARC: unimp: tableswitch extract - throw GraalInternalError.unimplemented(); - } - } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java Wed Mar 05 19:40:15 2014 -0800 @@ -101,4 +101,9 @@ protected StackSlot allocateNewSpillSlot(PlatformKind kind, int additionalOffset) { return StackSlot.get(kind, -spillSize + additionalOffset, true); } + + @Override + public LIRInstruction createSpillMove(AllocatableValue result, Value input) { + return SPARCMove.createMove(result, input); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Wed Mar 05 19:40:15 2014 -0800 @@ -39,6 +39,16 @@ public class SPARCMove { + public static SPARCLIRInstruction createMove(AllocatableValue dst, Value src) { + if (src instanceof SPARCAddressValue) { + return new LoadAddressOp(dst, (SPARCAddressValue) src); + } else if (isRegister(src) || isStackSlot(dst)) { + return new MoveFromRegOp(dst, src); + } else { + return new MoveToRegOp(dst, src); + } + } + @Opcode("MOVE") public static class MoveToRegOp extends SPARCLIRInstruction implements MoveOp { @@ -110,7 +120,7 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { if (state != null) { - crb.recordImplicitException(masm.codeBuffer.position(), state); + crb.recordImplicitException(masm.position(), state); } emitMemAccess(masm); } @@ -215,7 +225,7 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - crb.recordImplicitException(masm.codeBuffer.position(), state); + crb.recordImplicitException(masm.position(), state); new Ldx(new SPARCAddress(asRegister(input), 0), r0).emit(masm); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java Wed Mar 05 19:40:15 2014 -0800 @@ -45,6 +45,8 @@ private ControlFlowOptimizer() { } + private static final DebugMetric BLOCKS_DELETED = Debug.metric("BlocksDeleted"); + /** * Checks whether a block can be deleted. Only blocks with exactly one successor and an * unconditional branch to this successor are eligable. @@ -68,6 +70,16 @@ return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry(); } + private static void alignBlock(LIR lir, Block block) { + if (!block.isAligned()) { + block.setAlign(true); + List instructions = lir.lir(block); + assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label"; + StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0); + instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true)); + } + } + private static void deleteEmptyBlocks(LIR lir, List blocks) { assert verifyBlocks(lir, blocks); Iterator iterator = blocks.iterator(); @@ -87,7 +99,12 @@ } block.getSuccessors().clear(); block.getPredecessors().clear(); - Debug.metric("BlocksDeleted").increment(); + + if (block.isAligned()) { + alignBlock(lir, other); + } + + BLOCKS_DELETED.increment(); iterator.remove(); } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Wed Mar 05 19:40:15 2014 -0800 @@ -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}. @@ -316,7 +320,7 @@ spillSize += (slots * target.wordSize); if (!objects.isEmpty()) { - assert objects.length() < slots; + assert objects.length() <= slots; StackSlot result = null; for (int slotIndex = 0; slotIndex < slots; slotIndex++) { StackSlot objectSlot = null; @@ -378,4 +382,6 @@ } } } + + public abstract LIRInstruction createSpillMove(AllocatableValue result, Value input); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java Wed Mar 05 19:40:15 2014 -0800 @@ -42,6 +42,6 @@ @Override public void emitCode(CompilationResultBuilder crb) { - crb.recordInfopoint(crb.asm.codeBuffer.position(), state, reason); + crb.recordInfopoint(crb.asm.position(), state, reason); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,7 +24,6 @@ import java.util.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.lir.LIRInstruction.StateProcedure; import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.nodes.*; @@ -58,15 +57,8 @@ private int numVariables; - public SpillMoveFactory spillMoveFactory; - public final BlockMap> lirInstructions; - public interface SpillMoveFactory { - - LIRInstruction createMove(AllocatableValue result, Value input); - } - private boolean hasArgInCallerFrame; /** diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java Wed Mar 05 19:40:15 2014 -0800 @@ -89,11 +89,11 @@ public abstract static class BaseSwitchClosure implements SwitchClosure { private final CompilationResultBuilder crb; - private final AbstractAssembler masm; + private final Assembler masm; private final LabelRef[] keyTargets; private final LabelRef defaultTarget; - public BaseSwitchClosure(CompilationResultBuilder crb, AbstractAssembler masm, LabelRef[] keyTargets, LabelRef defaultTarget) { + public BaseSwitchClosure(CompilationResultBuilder crb, Assembler masm, LabelRef[] keyTargets, LabelRef defaultTarget) { this.crb = crb; this.masm = masm; this.keyTargets = keyTargets; diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Wed Mar 05 19:40:15 2014 -0800 @@ -54,7 +54,7 @@ } } - public final AbstractAssembler asm; + public final Assembler asm; public final CompilationResult compilationResult; public final TargetDescription target; public final CodeCacheProvider codeCache; @@ -78,8 +78,7 @@ private List exceptionInfoList; - public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, - CompilationResult compilationResult) { + public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext, CompilationResult compilationResult) { this.target = codeCache.getTarget(); this.codeCache = codeCache; this.foreignCalls = foreignCalls; @@ -97,15 +96,15 @@ private static final CompilationResult.Mark[] NO_REFS = {}; public CompilationResult.Mark recordMark(Object id) { - return compilationResult.recordMark(asm.codeBuffer.position(), id, NO_REFS); + return compilationResult.recordMark(asm.position(), id, NO_REFS); } public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) { - return compilationResult.recordMark(asm.codeBuffer.position(), id, references); + return compilationResult.recordMark(asm.position(), id, references); } public void blockComment(String s) { - compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.codeBuffer.position(), s)); + compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.position(), s)); } /** @@ -114,7 +113,7 @@ * the compilation result. */ public void finish() { - compilationResult.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); + compilationResult.setTargetCode(asm.close(false), asm.position()); // Record exception handlers if they exist if (exceptionInfoList != null) { @@ -159,8 +158,8 @@ 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()); + int pos = asm.position(); + Debug.log("Inline data in code: pos = %d, data = %s", pos, data); compilationResult.recordInlineData(pos, data); } @@ -171,8 +170,8 @@ 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()); + int pos = asm.position(); + Debug.log("Data reference in code: pos = %d, data = %s", pos, data); compilationResult.recordDataReference(pos, data); return asm.getPlaceholder(); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilderFactory.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilderFactory.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilderFactory.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,7 +34,7 @@ /** * Creates a new {@link CompilationResultBuilder}. */ - CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, + CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext, CompilationResult compilationResult); /** @@ -42,7 +42,7 @@ */ CompilationResultBuilderFactory Default = new CompilationResultBuilderFactory() { - public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, + public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext, CompilationResult compilationResult) { return new CompilationResultBuilder(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,7 +22,6 @@ */ package com.oracle.graal.loop; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -119,28 +118,28 @@ } @Override - public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) { - Kind fromKind = phi.kind(); + public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) { + Stamp fromStamp = phi.stamp(); StructuredGraph graph = graph(); ValueNode stride = strideNode(); ValueNode initNode = this.initNode(); - if (fromKind != kind) { - stride = graph.unique(new ConvertNode(fromKind, kind, stride)); - initNode = graph.unique(new ConvertNode(fromKind, kind, initNode)); + if (!fromStamp.isCompatible(stamp)) { + stride = IntegerConvertNode.convert(stride, stamp); + initNode = IntegerConvertNode.convert(initNode, stamp); } ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount); - if (maxTripCount.kind() != kind) { - maxTripCount = graph.unique(new ConvertNode(maxTripCount.kind(), kind, maxTripCount)); + if (!maxTripCount.stamp().isCompatible(stamp)) { + maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp); } - return IntegerArithmeticNode.add(graph, IntegerArithmeticNode.mul(graph, stride, IntegerArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode); + return IntegerArithmeticNode.add(graph, IntegerArithmeticNode.mul(graph, stride, IntegerArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerStamp(stamp, 1, graph))), initNode); } @Override public ValueNode exitValueNode() { - Kind kind = phi.kind(); + Stamp stamp = phi.stamp(); ValueNode maxTripCount = loop.counted().maxTripCountNode(false); - if (maxTripCount.kind() != kind) { - maxTripCount = graph().unique(new ConvertNode(maxTripCount.kind(), kind, maxTripCount)); + if (!maxTripCount.stamp().isCompatible(stamp)) { + maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp); } return IntegerArithmeticNode.add(graph(), IntegerArithmeticNode.mul(graph(), strideNode(), maxTripCount), initNode()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java Wed Mar 05 19:40:15 2014 -0800 @@ -29,6 +29,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; public class CountedLoopInfo { @@ -52,18 +53,18 @@ public ValueNode maxTripCountNode(boolean assumePositive) { StructuredGraph graph = iv.valueNode().graph(); - Kind kind = iv.valueNode().kind(); + Stamp stamp = iv.valueNode().stamp(); IntegerArithmeticNode range = IntegerArithmeticNode.sub(graph, end, iv.initNode()); if (oneOff) { if (iv.direction() == Direction.Up) { - range = IntegerArithmeticNode.add(graph, range, ConstantNode.forIntegerKind(kind, 1, graph)); + range = IntegerArithmeticNode.add(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph)); } else { - range = IntegerArithmeticNode.sub(graph, range, ConstantNode.forIntegerKind(kind, 1, graph)); + range = IntegerArithmeticNode.sub(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph)); } } - IntegerDivNode div = graph.add(new IntegerDivNode(kind, range, iv.strideNode())); + IntegerDivNode div = graph.add(new IntegerDivNode(iv.valueNode().stamp().unrestricted(), range, iv.strideNode())); graph.addBeforeFixed(loop.entryPoint(), div); - ConstantNode zero = ConstantNode.forIntegerKind(kind, 0, graph); + ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0, graph); if (assumePositive) { return div; } @@ -137,19 +138,19 @@ if (overflowGuard != null) { return overflowGuard; } - Kind kind = iv.valueNode().kind(); + IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp(); StructuredGraph graph = iv.valueNode().graph(); CompareNode cond; // we use a negated guard with a < condition to achieve a >= - ConstantNode one = ConstantNode.forIntegerKind(kind, 1, graph); + ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph); if (iv.direction() == Direction.Up) { - IntegerArithmeticNode v1 = sub(graph, ConstantNode.forIntegerKind(kind, kind.getMaxValue(), graph), sub(graph, iv.strideNode(), one)); + IntegerArithmeticNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, IntegerStamp.defaultMaxValue(stamp.getBits(), stamp.isUnsigned()), graph), sub(graph, iv.strideNode(), one)); if (oneOff) { v1 = sub(graph, v1, one); } cond = graph.unique(new IntegerLessThanNode(v1, end)); } else { assert iv.direction() == Direction.Down; - IntegerArithmeticNode v1 = add(graph, ConstantNode.forIntegerKind(kind, kind.getMinValue(), graph), sub(graph, one, iv.strideNode())); + IntegerArithmeticNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, IntegerStamp.defaultMinValue(stamp.getBits(), stamp.isUnsigned()), graph), sub(graph, one, iv.strideNode())); if (oneOff) { v1 = add(graph, v1, one); } @@ -161,7 +162,7 @@ return overflowGuard; } - public Kind getKind() { - return iv.valueNode().kind(); + public IntegerStamp getStamp() { + return (IntegerStamp) iv.valueNode().stamp(); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,10 +22,10 @@ */ package com.oracle.graal.loop; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; public class DerivedOffsetInductionVariable extends InductionVariable { @@ -92,8 +92,8 @@ } @Override - public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) { - return op(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(graph(), kind, offset)); + public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) { + return op(base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(offset, stamp)); } @Override diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,7 +22,6 @@ */ package com.oracle.graal.loop; -import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.type.*; @@ -102,8 +101,8 @@ } @Override - public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) { - return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(graph(), kind, scale)); + public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) { + return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(scale, stamp)); } @Override diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,9 +22,9 @@ */ package com.oracle.graal.loop; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; /** * This class describes a value node that is an induction variable in a counted loop. @@ -89,10 +89,10 @@ * induction variable in the loop body of the last iteration. */ public ValueNode extremumNode() { - return extremumNode(false, valueNode().kind()); + return extremumNode(false, valueNode().stamp()); } - public abstract ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind); + public abstract ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp); public abstract boolean isConstantExtremum(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,7 +22,6 @@ */ package com.oracle.graal.loop.phases; -import com.oracle.graal.api.meta.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; @@ -38,7 +37,7 @@ if (context.getOptimisticOptimizations().useLoopLimitChecks()) { loops.detectedCountedLoops(); for (LoopEx loop : loops.countedLoops()) { - if (loop.lirLoop().children.isEmpty() && loop.counted().getKind() == Kind.Int) { + if (loop.lirLoop().children.isEmpty() && loop.counted().getStamp().getBits() <= 32) { boolean hasSafepoint = false; for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) { hasSafepoint |= loopEnd.canSafepoint(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java --- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -44,83 +44,83 @@ @Test public void testBooleanConstant() { - assertEquals(new IntegerStamp(Kind.Int, 1, 1, 0x1, 0x1), ConstantNode.forBoolean(true, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0, 0x0), ConstantNode.forBoolean(false, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 1, 1, 0x1, 0x1), ConstantNode.forBoolean(true, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 0, 0, 0x0, 0x0), ConstantNode.forBoolean(false, graph).stamp()); } @Test public void testByteConstant() { - assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0, 0x0), ConstantNode.forByte((byte) 0, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 16, 16, 0x10, 0x10), ConstantNode.forByte((byte) 16, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, -16, -16, 0xfffffff0L, 0xfffffff0L), ConstantNode.forByte((byte) -16, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 127, 127, 0x7f, 0x7f), ConstantNode.forByte((byte) 127, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forByte((byte) -128, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 0, 0, 0x0, 0x0), ConstantNode.forByte((byte) 0, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 16, 16, 0x10, 0x10), ConstantNode.forByte((byte) 16, graph).stamp()); + assertEquals(new IntegerStamp(32, false, -16, -16, 0xfffffff0L, 0xfffffff0L), ConstantNode.forByte((byte) -16, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 127, 127, 0x7f, 0x7f), ConstantNode.forByte((byte) 127, graph).stamp()); + assertEquals(new IntegerStamp(32, false, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forByte((byte) -128, graph).stamp()); } @Test public void testShortConstant() { - assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0, 0x0), ConstantNode.forShort((short) 0, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 128, 128, 0x80, 0x80), ConstantNode.forShort((short) 128, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forShort((short) -128, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 32767, 32767, 0x7fff, 0x7fff), ConstantNode.forShort((short) 32767, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, -32768, -32768, 0xffff8000L, 0xffff8000L), ConstantNode.forShort((short) -32768, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 0, 0, 0x0, 0x0), ConstantNode.forShort((short) 0, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 128, 128, 0x80, 0x80), ConstantNode.forShort((short) 128, graph).stamp()); + assertEquals(new IntegerStamp(32, false, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forShort((short) -128, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 32767, 32767, 0x7fff, 0x7fff), ConstantNode.forShort((short) 32767, graph).stamp()); + assertEquals(new IntegerStamp(32, false, -32768, -32768, 0xffff8000L, 0xffff8000L), ConstantNode.forShort((short) -32768, graph).stamp()); } @Test public void testCharConstant() { - assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0, 0x0), ConstantNode.forChar((char) 0, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 'A', 'A', 'A', 'A'), ConstantNode.forChar('A', graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 128, 128, 0x80, 0x80), ConstantNode.forChar((char) 128, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 65535, 65535, 0xffff, 0xffff), ConstantNode.forChar((char) 65535, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 0, 0, 0x0, 0x0), ConstantNode.forChar((char) 0, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 'A', 'A', 'A', 'A'), ConstantNode.forChar('A', graph).stamp()); + assertEquals(new IntegerStamp(32, false, 128, 128, 0x80, 0x80), ConstantNode.forChar((char) 128, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 65535, 65535, 0xffff, 0xffff), ConstantNode.forChar((char) 65535, graph).stamp()); } @Test public void testIntConstant() { - assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0, 0x0), ConstantNode.forInt(0, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, 128, 128, 0x80, 0x80), ConstantNode.forInt(128, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forInt(-128, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, Integer.MAX_VALUE, Integer.MAX_VALUE, 0x7fffffff, 0x7fffffff), ConstantNode.forInt(Integer.MAX_VALUE, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Int, Integer.MIN_VALUE, Integer.MIN_VALUE, 0x80000000L, 0x80000000L), ConstantNode.forInt(Integer.MIN_VALUE, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 0, 0, 0x0, 0x0), ConstantNode.forInt(0, graph).stamp()); + assertEquals(new IntegerStamp(32, false, 128, 128, 0x80, 0x80), ConstantNode.forInt(128, graph).stamp()); + assertEquals(new IntegerStamp(32, false, -128, -128, 0xffffff80L, 0xffffff80L), ConstantNode.forInt(-128, graph).stamp()); + assertEquals(new IntegerStamp(32, false, Integer.MAX_VALUE, Integer.MAX_VALUE, 0x7fffffff, 0x7fffffff), ConstantNode.forInt(Integer.MAX_VALUE, graph).stamp()); + assertEquals(new IntegerStamp(32, false, Integer.MIN_VALUE, Integer.MIN_VALUE, 0x80000000L, 0x80000000L), ConstantNode.forInt(Integer.MIN_VALUE, graph).stamp()); } @Test public void testLongConstant() { - assertEquals(new IntegerStamp(Kind.Long, 0, 0, 0x0, 0x0), ConstantNode.forLong(0, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Long, 128, 128, 0x80, 0x80), ConstantNode.forLong(128, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Long, -128, -128, 0xffffffffffffff80L, 0xffffffffffffff80L), ConstantNode.forLong(-128, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Long, Long.MAX_VALUE, Long.MAX_VALUE, 0x7fffffffffffffffL, 0x7fffffffffffffffL), ConstantNode.forLong(Long.MAX_VALUE, graph).stamp()); - assertEquals(new IntegerStamp(Kind.Long, Long.MIN_VALUE, Long.MIN_VALUE, 0x8000000000000000L, 0x8000000000000000L), ConstantNode.forLong(Long.MIN_VALUE, graph).stamp()); + assertEquals(new IntegerStamp(64, false, 0, 0, 0x0, 0x0), ConstantNode.forLong(0, graph).stamp()); + assertEquals(new IntegerStamp(64, false, 128, 128, 0x80, 0x80), ConstantNode.forLong(128, graph).stamp()); + assertEquals(new IntegerStamp(64, false, -128, -128, 0xffffffffffffff80L, 0xffffffffffffff80L), ConstantNode.forLong(-128, graph).stamp()); + assertEquals(new IntegerStamp(64, false, Long.MAX_VALUE, Long.MAX_VALUE, 0x7fffffffffffffffL, 0x7fffffffffffffffL), ConstantNode.forLong(Long.MAX_VALUE, graph).stamp()); + assertEquals(new IntegerStamp(64, false, Long.MIN_VALUE, Long.MIN_VALUE, 0x8000000000000000L, 0x8000000000000000L), ConstantNode.forLong(Long.MIN_VALUE, graph).stamp()); } @Test public void testPositiveRanges() { - assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0, 0), StampFactory.forInteger(Kind.Int, 0, 0)); - assertEquals(new IntegerStamp(Kind.Int, 0, 1, 0, 1), StampFactory.forInteger(Kind.Int, 0, 1)); - assertEquals(new IntegerStamp(Kind.Int, 0, 0x123, 0, 0x1ff), StampFactory.forInteger(Kind.Int, 0, 0x123)); - assertEquals(new IntegerStamp(Kind.Int, 0x120, 0x123, 0x120, 0x123), StampFactory.forInteger(Kind.Int, 0x120, 0x123)); - assertEquals(new IntegerStamp(Kind.Int, 10000, 15000, 0x2000, 0x3fff), StampFactory.forInteger(Kind.Int, 10000, 15000)); - assertEquals(new IntegerStamp(Kind.Long, 0, 1, 0, 1), StampFactory.forInteger(Kind.Long, 0, 1)); - assertEquals(new IntegerStamp(Kind.Long, 10000, 15000, 0x2000, 0x3fff), StampFactory.forInteger(Kind.Long, 10000, 15000)); - assertEquals(new IntegerStamp(Kind.Long, 140000000000L, 150000000000L, 0x2000000000L, 0x23ffffffffL), StampFactory.forInteger(Kind.Long, 140000000000L, 150000000000L)); + assertEquals(new IntegerStamp(32, false, 0, 0, 0, 0), StampFactory.forInteger(Kind.Int, 0, 0)); + assertEquals(new IntegerStamp(32, false, 0, 1, 0, 1), StampFactory.forInteger(Kind.Int, 0, 1)); + assertEquals(new IntegerStamp(32, false, 0, 0x123, 0, 0x1ff), StampFactory.forInteger(Kind.Int, 0, 0x123)); + assertEquals(new IntegerStamp(32, false, 0x120, 0x123, 0x120, 0x123), StampFactory.forInteger(Kind.Int, 0x120, 0x123)); + assertEquals(new IntegerStamp(32, false, 10000, 15000, 0x2000, 0x3fff), StampFactory.forInteger(Kind.Int, 10000, 15000)); + assertEquals(new IntegerStamp(64, false, 0, 1, 0, 1), StampFactory.forInteger(Kind.Long, 0, 1)); + assertEquals(new IntegerStamp(64, false, 10000, 15000, 0x2000, 0x3fff), StampFactory.forInteger(Kind.Long, 10000, 15000)); + assertEquals(new IntegerStamp(64, false, 140000000000L, 150000000000L, 0x2000000000L, 0x23ffffffffL), StampFactory.forInteger(Kind.Long, 140000000000L, 150000000000L)); } @Test public void testNegativeRanges() { - assertEquals(new IntegerStamp(Kind.Int, -2, -1, 0xfffffffeL, 0xffffffffL), StampFactory.forInteger(Kind.Int, -2, -1)); - assertEquals(new IntegerStamp(Kind.Int, -20, -10, 0xffffffe0L, 0xffffffffL), StampFactory.forInteger(Kind.Int, -20, -10)); - assertEquals(new IntegerStamp(Kind.Int, -10000, 0, 0, 0xffffffffL), StampFactory.forInteger(Kind.Int, -10000, 0)); - assertEquals(new IntegerStamp(Kind.Int, -10000, -1, 0xffffc000L, 0xffffffffL), StampFactory.forInteger(Kind.Int, -10000, -1)); - assertEquals(new IntegerStamp(Kind.Int, -10010, -10000, 0xffffd8e0L, 0xffffd8ffL), StampFactory.forInteger(Kind.Int, -10010, -10000)); - assertEquals(new IntegerStamp(Kind.Long, -2, -1, 0xfffffffffffffffeL, 0xffffffffffffffffL), StampFactory.forInteger(Kind.Long, -2, -1)); - assertEquals(new IntegerStamp(Kind.Long, -10010, -10000, 0xffffffffffffd8e0L, 0xffffffffffffd8ffL), StampFactory.forInteger(Kind.Long, -10010, -10000)); - assertEquals(new IntegerStamp(Kind.Long, -150000000000L, -140000000000L, 0xffffffdc00000000L, 0xffffffdfffffffffL), StampFactory.forInteger(Kind.Long, -150000000000L, -140000000000L)); + assertEquals(new IntegerStamp(32, false, -2, -1, 0xfffffffeL, 0xffffffffL), StampFactory.forInteger(Kind.Int, -2, -1)); + assertEquals(new IntegerStamp(32, false, -20, -10, 0xffffffe0L, 0xffffffffL), StampFactory.forInteger(Kind.Int, -20, -10)); + assertEquals(new IntegerStamp(32, false, -10000, 0, 0, 0xffffffffL), StampFactory.forInteger(Kind.Int, -10000, 0)); + assertEquals(new IntegerStamp(32, false, -10000, -1, 0xffffc000L, 0xffffffffL), StampFactory.forInteger(Kind.Int, -10000, -1)); + assertEquals(new IntegerStamp(32, false, -10010, -10000, 0xffffd8e0L, 0xffffd8ffL), StampFactory.forInteger(Kind.Int, -10010, -10000)); + assertEquals(new IntegerStamp(64, false, -2, -1, 0xfffffffffffffffeL, 0xffffffffffffffffL), StampFactory.forInteger(Kind.Long, -2, -1)); + assertEquals(new IntegerStamp(64, false, -10010, -10000, 0xffffffffffffd8e0L, 0xffffffffffffd8ffL), StampFactory.forInteger(Kind.Long, -10010, -10000)); + assertEquals(new IntegerStamp(64, false, -150000000000L, -140000000000L, 0xffffffdc00000000L, 0xffffffdfffffffffL), StampFactory.forInteger(Kind.Long, -150000000000L, -140000000000L)); } @Test public void testMixedRanges() { - assertEquals(new IntegerStamp(Kind.Int, -1, 0, 0, 0xffffffffL), StampFactory.forInteger(Kind.Int, -1, 0)); - assertEquals(new IntegerStamp(Kind.Int, -10000, 1000, 0, 0xffffffffL), StampFactory.forInteger(Kind.Int, -10000, 1000)); - assertEquals(new IntegerStamp(Kind.Long, -10000, 1000, 0, 0xffffffffffffffffL), StampFactory.forInteger(Kind.Long, -10000, 1000)); + assertEquals(new IntegerStamp(32, false, -1, 0, 0, 0xffffffffL), StampFactory.forInteger(Kind.Int, -1, 0)); + assertEquals(new IntegerStamp(32, false, -10000, 1000, 0, 0xffffffffL), StampFactory.forInteger(Kind.Int, -10000, 1000)); + assertEquals(new IntegerStamp(64, false, -10000, 1000, 0, 0xffffffffffffffffL), StampFactory.forInteger(Kind.Long, -10000, 1000)); } @Test @@ -159,15 +159,15 @@ @Test public void testXor() { - assertEquals(new IntegerStamp(Kind.Int, 0, 0xff, 0, 0xff), StampTool.xor(new IntegerStamp(Kind.Int, 0, 0, 0, 0), new IntegerStamp(Kind.Int, 0, 0xff, 0, 0xff))); - assertEquals(new IntegerStamp(Kind.Int, 0x10, 0x1f, 0x10, 0x1f), StampTool.xor(new IntegerStamp(Kind.Int, 0, 0, 0, 0), new IntegerStamp(Kind.Int, 0x10, 0x1f, 0x10, 0x1f))); - assertEquals(new IntegerStamp(Kind.Int, 0x0, 0xf, 0x0, 0xf), StampTool.xor(new IntegerStamp(Kind.Int, 0x10, 0x10, 0x10, 0x10), new IntegerStamp(Kind.Int, 0x10, 0x1f, 0x10, 0x1f))); - assertEquals(new IntegerStamp(Kind.Int, 0x10, 0x1f, 0x10, 0x1f), StampTool.xor(new IntegerStamp(Kind.Int, 0x10, 0x10, 0x10, 0x10), new IntegerStamp(Kind.Int, 0x0, 0xf, 0x0, 0xf))); + assertEquals(new IntegerStamp(32, false, 0, 0xff, 0, 0xff), StampTool.xor(new IntegerStamp(32, false, 0, 0, 0, 0), new IntegerStamp(32, false, 0, 0xff, 0, 0xff))); + assertEquals(new IntegerStamp(32, false, 0x10, 0x1f, 0x10, 0x1f), StampTool.xor(new IntegerStamp(32, false, 0, 0, 0, 0), new IntegerStamp(32, false, 0x10, 0x1f, 0x10, 0x1f))); + assertEquals(new IntegerStamp(32, false, 0x0, 0xf, 0x0, 0xf), StampTool.xor(new IntegerStamp(32, false, 0x10, 0x10, 0x10, 0x10), new IntegerStamp(32, false, 0x10, 0x1f, 0x10, 0x1f))); + assertEquals(new IntegerStamp(32, false, 0x10, 0x1f, 0x10, 0x1f), StampTool.xor(new IntegerStamp(32, false, 0x10, 0x10, 0x10, 0x10), new IntegerStamp(32, false, 0x0, 0xf, 0x0, 0xf))); } @Test public void testNot() { - assertEquals(new IntegerStamp(Kind.Int, -11, -1, 0xffff_fff0L, 0xffff_ffffL), StampTool.not(new IntegerStamp(Kind.Int, 0, 10, 0, 0xf))); + assertEquals(new IntegerStamp(32, false, -11, -1, 0xffff_fff0L, 0xffff_ffffL), StampTool.not(new IntegerStamp(32, false, 0, 10, 0, 0xf))); } @Test @@ -258,6 +258,70 @@ @Test public void testAnd() { - assertEquals(new IntegerStamp(Kind.Int, Integer.MIN_VALUE, 0x40000000L, 0, 0xc0000000L), StampTool.and(StampFactory.forKind(Kind.Int), StampFactory.forConstant(Constant.forInt(0xc0000000)))); + assertEquals(new IntegerStamp(32, false, Integer.MIN_VALUE, 0x40000000L, 0, 0xc0000000L), StampTool.and(StampFactory.forKind(Kind.Int), StampFactory.forConstant(Constant.forInt(0xc0000000)))); + } + + private static void testSignExtendShort(long lower, long upper) { + Stamp shortStamp = StampFactory.forInteger(16, false, lower, upper); + Stamp intStamp = StampTool.signExtend(shortStamp, 32); + assertEquals(StampFactory.forInteger(32, false, lower, upper), intStamp); + } + + @Test + public void testSignExtend() { + testSignExtendShort(5, 7); + testSignExtendShort(0, 42); + testSignExtendShort(-42, -1); + testSignExtendShort(-42, 0); + testSignExtendShort(-1, 1); + testSignExtendShort(Short.MIN_VALUE, Short.MAX_VALUE); + } + + private static void testZeroExtendShort(long lower, long upper, long newLower, long newUpper) { + Stamp shortStamp = StampFactory.forInteger(16, false, lower, upper); + Stamp intStamp = StampTool.zeroExtend(shortStamp, 32); + assertEquals(StampFactory.forInteger(32, false, newLower, newUpper), intStamp); + } + + @Test + public void testZeroExtend() { + testZeroExtendShort(5, 7, 5, 7); + testZeroExtendShort(0, 42, 0, 42); + testZeroExtendShort(-42, -1, 0xFFFF - 41, 0xFFFF); + testZeroExtendShort(-42, 0, 0, 0xFFFF); + testZeroExtendShort(-1, 1, 0, 0xFFFF); + testZeroExtendShort(Short.MIN_VALUE, Short.MAX_VALUE, 0, 0xFFFF); + } + + private static void testSignExtendChar(long lower, long upper, long newLower, long newUpper) { + Stamp charStamp = StampFactory.forInteger(16, true, lower, upper); + Stamp uintStamp = StampTool.signExtend(charStamp, 32); + assertEquals(StampFactory.forInteger(32, true, newLower, newUpper), uintStamp); + } + + @Test + public void testSignExtendUnsigned() { + testSignExtendChar(5, 7, 5, 7); + testSignExtendChar(0, 42, 0, 42); + testSignExtendChar(5, 0xF000, 5, 0xFFFFF000L); + testSignExtendChar(0, 0xF000, 0, 0xFFFFF000L); + testSignExtendChar(0xF000, Character.MAX_VALUE, 0xFFFFF000L, 0xFFFFFFFFL); + testSignExtendChar(Character.MIN_VALUE, Character.MAX_VALUE, 0, 0xFFFFFFFFL); + } + + private static void testZeroExtendChar(long lower, long upper) { + Stamp charStamp = StampFactory.forInteger(16, true, lower, upper); + Stamp uintStamp = StampTool.zeroExtend(charStamp, 32); + assertEquals(StampFactory.forInteger(32, true, lower, upper), uintStamp); + } + + @Test + public void testZeroExtendUnsigned() { + testZeroExtendChar(5, 7); + testZeroExtendChar(0, 42); + testZeroExtendChar(5, 0xF000); + testZeroExtendChar(0, 0xF000); + testZeroExtendChar(0xF000, Character.MAX_VALUE); + testZeroExtendChar(Character.MIN_VALUE, Character.MAX_VALUE); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -70,7 +70,7 @@ * Used to measure the impact of ConstantNodes not recording their usages. This and all code * predicated on this value being true will be removed at some point. */ - public static final boolean ConstantNodeRecordsUsages = Boolean.getBoolean("graal.constantNodeRecordsUsages"); + public static final boolean ConstantNodeRecordsUsages = Boolean.parseBoolean(System.getProperty("graal.constantNodeRecordsUsages", "true")); @Override public boolean recordsUsages() { @@ -151,8 +151,18 @@ } } + public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) { + if (stamp instanceof PrimitiveStamp) { + return forPrimitive(stamp, constant, graph); + } else { + ConstantNode ret = forConstant(constant, metaAccess, graph); + assert ret.stamp().isCompatible(stamp); + return ret; + } + } + /** - * Returns a node for a primitive constant. + * Returns a node for a Java primitive. */ public static ConstantNode forPrimitive(Constant constant, StructuredGraph graph) { assert constant.getKind() != Kind.Object; @@ -160,6 +170,19 @@ } /** + * Returns a node for a primitive of a given type. + */ + public static ConstantNode forPrimitive(Stamp stamp, Constant constant, StructuredGraph graph) { + if (stamp instanceof IntegerStamp) { + assert constant.getKind().isNumericInteger() && stamp.getStackKind() == constant.getKind().getStackKind(); + return forIntegerStamp(stamp, constant.asLong(), graph); + } else { + assert constant.getKind().isNumericFloat() && stamp.getStackKind() == constant.getKind(); + return forPrimitive(constant, graph); + } + } + + /** * Returns a node for a double constant. * * @param d the double value for which to create the instruction @@ -255,6 +278,33 @@ return graph.unique(node); } + /** + * Returns a node for a constant integer that's not directly representable as Java primitive + * (e.g. short). + */ + public static ConstantNode forIntegerBits(int bits, boolean unsigned, long value, StructuredGraph graph) { + Constant constant = Constant.forPrimitiveInt(bits, value); + long bounds; + if (unsigned) { + bounds = ZeroExtendNode.zeroExtend(value, bits); + } else { + bounds = SignExtendNode.signExtend(value, bits); + } + return unique(graph, new ConstantNode(constant, StampFactory.forInteger(bits, unsigned, bounds, bounds))); + } + + /** + * Returns a node for a constant integer that's compatible to a given stamp. + */ + public static ConstantNode forIntegerStamp(Stamp stamp, long value, StructuredGraph graph) { + if (stamp instanceof IntegerStamp) { + IntegerStamp intStamp = (IntegerStamp) stamp; + return forIntegerBits(intStamp.getBits(), intStamp.isUnsigned(), value, graph); + } else { + return forIntegerKind(stamp.getStackKind(), value, graph); + } + } + public static ConstantNode forIntegerKind(Kind kind, long value, StructuredGraph graph) { switch (kind) { case Byte: @@ -279,6 +329,13 @@ } } + /** + * Returns a node for a constant double that's compatible to a given stamp. + */ + public static ConstantNode forFloatingStamp(Stamp stamp, double value, StructuredGraph graph) { + return forFloatingKind(stamp.getStackKind(), value, graph); + } + public static ConstantNode defaultForKind(Kind kind, StructuredGraph graph) { switch (kind) { case Boolean: diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -36,6 +36,6 @@ @Override public String targetName() { - return "Direct#" + ((JavaMethod) target()).getName(); + return MetaUtil.format("Direct#%h.%n", target()); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -51,7 +51,7 @@ tool.deleteBranch(next); } - DeoptimizeNode deopt = graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, getReason())); + DeoptimizeNode deopt = graph().add(new DeoptimizeNode(getAction(), getReason())); deopt.setDeoptimizationState(getDeoptimizationState()); setNext(deopt); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Mar 05 19:40:15 2014 -0800 @@ -244,8 +244,8 @@ /** * Creates a copy of this frame state with one stack element of type popKind popped from the - * stack and the values in pushedValues pushed on the stack. The pushedValues are expected to be - * in slot encoding: a long or double is followed by a null slot. + * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted + * correctly in slot encoding: a long or double will be followed by a null slot. */ public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) { ArrayList copy = new ArrayList<>(values.subList(0, localsSize + stackSize)); @@ -257,7 +257,12 @@ assert lastSlot.kind().getStackKind() == popKind.getStackKind(); copy.remove(copy.size() - 1); } - Collections.addAll(copy, pushedValues); + for (ValueNode node : pushedValues) { + copy.add(node); + if (node.kind() == Kind.Long || node.kind() == Kind.Double) { + copy.add(null); + } + } int newStackSize = copy.size() - localsSize; copy.addAll(values.subList(localsSize + stackSize, values.size())); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -109,11 +109,6 @@ if (c.getValue() != negated) { return graph().start(); } - } else if (negated && condition() instanceof ShortCircuitOrNode) { - ShortCircuitOrNode or = (ShortCircuitOrNode) condition(); - GuardNode firstGuard = graph().unique(new GuardNode(or.getX(), getGuard(), reason, action, !or.isXNegated(), speculation)); - GuardNode secondGuard = graph().unique(new GuardNode(or.getY(), firstGuard, reason, action, !or.isYNegated(), speculation)); - return secondGuard; } return this; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -31,6 +31,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; public class LoopBeginNode extends MergeNode implements IterableNodeType, LIRLowerable { @@ -184,7 +185,11 @@ public void removeExits() { for (LoopExitNode loopexit : loopExits().snapshot()) { loopexit.removeProxies(); + FrameState stateAfter = loopexit.stateAfter(); graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode())); + if (stateAfter != null && stateAfter.isAlive() && stateAfter.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -30,7 +30,7 @@ /** * A {@link PiNode} that also provides an array length in addition to a more refined stamp. A usage - * that reads the array length, such as an {@link ArrayLengthNode}, can be canonicalized base on + * that reads the array length, such as an {@link ArrayLengthNode}, can be canonicalized based on * this information. */ public final class PiArrayNode extends PiNode implements ArrayLengthProvider { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +//JaCoCo Exclude + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; @@ -102,9 +104,21 @@ @NodeIntrinsic public static native T piCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor); + public static T piCastExactNonNull(Object object, @ConstantNodeParameter Class toType) { + return piCast(object, toType, true, true); + } + + public static T piCast(Object object, @ConstantNodeParameter Class toType) { + return piCast(object, toType, false, false); + } + + public static T piCastNonNull(Object object, @ConstantNodeParameter Class toType) { + return piCast(object, toType, false, true); + } + @SuppressWarnings("unused") @NodeIntrinsic - public static T piCast(Object object, @ConstantNodeParameter Class toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull) { + private static T piCast(Object object, @ConstantNodeParameter Class toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull) { return toType.cast(object); } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -80,7 +80,7 @@ } public final Kind kind() { - return stamp().kind(); + return stamp().getStackKind(); } /** @@ -126,13 +126,6 @@ return null; } - @Override - public boolean verify() { - assertTrue(kind() != null, "Should have a valid kind"); - assertTrue(kind() == kind().getStackKind(), "Should have a stack kind : %s", kind()); - return super.verify(); - } - public ValueNode asNode() { return this; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -30,10 +30,10 @@ import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "&") -public final class AndNode extends BitLogicNode implements Canonicalizable { +public final class AndNode extends BitLogicNode implements Canonicalizable, NarrowableArithmeticNode { - public AndNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public AndNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -44,7 +44,7 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - return Constant.forIntegerKind(kind(), inputs[0].asLong() & inputs[1].asLong(), null); + return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() & inputs[1].asLong()); } @Override @@ -53,28 +53,18 @@ return x(); } if (x().isConstant() && !y().isConstant()) { - return graph().unique(new AndNode(kind(), y(), x())); + return graph().unique(new AndNode(stamp(), y(), x())); } if (x().isConstant()) { - return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); + return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { - if (kind() == Kind.Int) { - int c = y().asConstant().asInt(); - if (c == -1) { - return x(); - } - if (c == 0) { - return ConstantNode.forInt(0, graph()); - } - } else { - assert kind() == Kind.Long; - long c = y().asConstant().asLong(); - if (c == -1) { - return x(); - } - if (c == 0) { - return ConstantNode.forLong(0, graph()); - } + long rawY = y().asConstant().asLong(); + long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp())); + if ((rawY & mask) == mask) { + return x(); + } + if ((rawY & mask) == 0) { + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } return BinaryNode.reassociate(this, ValueNode.isConstantPredicate()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,7 +22,6 @@ */ package com.oracle.graal.nodes.calc; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; @@ -47,12 +46,12 @@ /** * Creates a new BinaryNode instance. * - * @param kind the result type of this instruction + * @param stamp the result type of this instruction * @param x the first input instruction * @param y the second input instruction */ - public BinaryNode(Kind kind, ValueNode x, ValueNode y) { - super(StampFactory.forKind(kind)); + public BinaryNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp); this.x = x; this.y = y; } @@ -84,53 +83,38 @@ } public static BinaryNode add(StructuredGraph graph, ValueNode x, ValueNode y) { - assert x.kind() == y.kind(); - switch (x.kind()) { - case Byte: - case Char: - case Short: - case Int: - case Long: - return IntegerArithmeticNode.add(graph, x, y); - case Float: - case Double: - return graph.unique(new FloatAddNode(x.kind(), x, y, false)); - default: - throw GraalInternalError.shouldNotReachHere(); + assert x.stamp().isCompatible(y.stamp()); + Stamp stamp = x.stamp(); + if (stamp instanceof IntegerStamp) { + return IntegerArithmeticNode.add(graph, x, y); + } else if (stamp instanceof FloatStamp) { + return graph.unique(new FloatAddNode(stamp, x, y, false)); + } else { + throw GraalInternalError.shouldNotReachHere(); } } public static BinaryNode sub(StructuredGraph graph, ValueNode x, ValueNode y) { - assert x.kind() == y.kind(); - switch (x.kind()) { - case Byte: - case Char: - case Short: - case Int: - case Long: - return IntegerArithmeticNode.sub(graph, x, y); - case Float: - case Double: - return graph.unique(new FloatSubNode(x.kind(), x, y, false)); - default: - throw GraalInternalError.shouldNotReachHere(); + assert x.stamp().isCompatible(y.stamp()); + Stamp stamp = x.stamp(); + if (stamp instanceof IntegerStamp) { + return IntegerArithmeticNode.sub(graph, x, y); + } else if (stamp instanceof FloatStamp) { + return graph.unique(new FloatSubNode(stamp, x, y, false)); + } else { + throw GraalInternalError.shouldNotReachHere(); } } public static BinaryNode mul(StructuredGraph graph, ValueNode x, ValueNode y) { - assert x.kind() == y.kind(); - switch (x.kind()) { - case Byte: - case Char: - case Short: - case Int: - case Long: - return IntegerArithmeticNode.mul(graph, x, y); - case Float: - case Double: - return graph.unique(new FloatMulNode(x.kind(), x, y, false)); - default: - throw GraalInternalError.shouldNotReachHere(); + assert x.stamp().isCompatible(y.stamp()); + Stamp stamp = x.stamp(); + if (stamp instanceof IntegerStamp) { + return IntegerArithmeticNode.mul(graph, x, y); + } else if (stamp instanceof FloatStamp) { + return graph.unique(new FloatMulNode(stamp, x, y, false)); + } else { + throw GraalInternalError.shouldNotReachHere(); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,14 +22,14 @@ */ package com.oracle.graal.nodes.calc; -import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; /** * The {@code LogicNode} class definition. */ -public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable { +public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode { /** * Constructs a new logic operation node. @@ -37,44 +37,23 @@ * @param x the first input into this node * @param y the second input into this node */ - public BitLogicNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); - assert kind == Kind.Int || kind == Kind.Long; + public BitLogicNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); + assert stamp instanceof IntegerStamp; } public static BitLogicNode and(StructuredGraph graph, ValueNode v1, ValueNode v2) { - assert v1.kind() == v2.kind(); - switch (v1.kind()) { - case Int: - return graph.unique(new AndNode(Kind.Int, v1, v2)); - case Long: - return graph.unique(new AndNode(Kind.Long, v1, v2)); - default: - throw ValueNodeUtil.shouldNotReachHere(); - } + assert v1.stamp().isCompatible(v2.stamp()); + return graph.unique(new AndNode(StampTool.and(v1.stamp(), v2.stamp()), v1, v2)); } public static BitLogicNode or(StructuredGraph graph, ValueNode v1, ValueNode v2) { - assert v1.kind() == v2.kind(); - switch (v1.kind()) { - case Int: - return graph.unique(new OrNode(Kind.Int, v1, v2)); - case Long: - return graph.unique(new OrNode(Kind.Long, v1, v2)); - default: - throw ValueNodeUtil.shouldNotReachHere(); - } + assert v1.stamp().isCompatible(v2.stamp()); + return graph.unique(new OrNode(StampTool.or(v1.stamp(), v2.stamp()), v1, v2)); } public static BitLogicNode xor(StructuredGraph graph, ValueNode v1, ValueNode v2) { - assert v1.kind() == v2.kind(); - switch (v1.kind()) { - case Int: - return graph.unique(new XorNode(Kind.Int, v1, v2)); - case Long: - return graph.unique(new XorNode(Kind.Long, v1, v2)); - default: - throw ValueNodeUtil.shouldNotReachHere(); - } + assert v1.stamp().isCompatible(v2.stamp()); + return graph.unique(new XorNode(StampTool.xor(v1.stamp(), v2.stamp()), v1, v2)); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -136,15 +136,15 @@ if (x() instanceof ConvertNode && y() instanceof ConvertNode) { ConvertNode convertX = (ConvertNode) x(); ConvertNode convertY = (ConvertNode) y(); - if (convertX.isLossless() && convertY.isLossless() && convertX.getFromKind() == convertY.getFromKind()) { - setX(convertX.value()); - setY(convertY.value()); + if (convertX.isLossless() && convertY.isLossless() && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) { + setX(convertX.getInput()); + setY(convertY.getInput()); } } else if (x() instanceof ConvertNode && y().isConstant()) { ConvertNode convertX = (ConvertNode) x(); ConstantNode newY = canonicalConvertConstant(convertX, y().asConstant()); if (newY != null) { - setX(convertX.value()); + setX(convertX.getInput()); setY(newY); } } else if (y() instanceof ConvertNode && x().isConstant()) { @@ -152,7 +152,7 @@ ConstantNode newX = canonicalConvertConstant(convertY, x().asConstant()); if (newX != null) { setX(newX); - setY(convertY.value()); + setY(convertY.getInput()); } } return this; @@ -160,10 +160,9 @@ private static ConstantNode canonicalConvertConstant(ConvertNode convert, Constant constant) { if (convert.isLossless()) { - assert constant.getKind() == convert.getToKind(); - Constant reverseConverted = ConvertNode.convert(convert.getToKind(), convert.getFromKind(), constant); - if (convert.evalConst(reverseConverted).equals(constant)) { - return ConstantNode.forPrimitive(reverseConverted, convert.graph()); + Constant reverseConverted = convert.reverse(constant); + if (convert.convert(reverseConverted).equals(constant)) { + return ConstantNode.forPrimitive(convert.getInput().stamp(), reverseConverted, convert.graph()); } } return null; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -49,8 +49,8 @@ } public ConditionalNode(LogicNode condition, ValueNode trueValue, ValueNode falseValue) { - super(trueValue.kind(), trueValue, falseValue); - assert trueValue.kind() == falseValue.kind(); + super(trueValue.stamp().meet(falseValue.stamp()), trueValue, falseValue); + assert trueValue.stamp().isCompatible(falseValue.stamp()); this.condition = condition; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,277 +22,36 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.code.*; 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.spi.*; import com.oracle.graal.nodes.type.*; /** - * The {@code ConvertNode} class represents a conversion between primitive types. + * Represents a conversion between primitive types. */ -public class ConvertNode extends FloatingNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable { - - @Input private ValueNode value; - - private final Kind from; - private final Kind to; - - public ValueNode value() { - return value; - } - - /** - * Constructs a new Convert instance. - * - * @param from the kind of the incoming value - * @param to the result kind - * @param value the instruction producing the input value - */ - public ConvertNode(Kind from, Kind to, ValueNode value) { - super(StampFactory.forKind(to.getStackKind())); - assert value.kind() == from.getStackKind() : "convert(" + from + ", " + to + ") : " + value.kind() + " != " + from; - this.from = from; - this.to = to; - this.value = value; - } +public abstract class ConvertNode extends FloatingNode implements ArithmeticOperation { - public Kind getFromKind() { - return from; - } - - public Kind getToKind() { - return to; - } + @Input private ValueNode input; - public boolean isLossless() { - if (from == to) { - return true; - } - switch (from) { - case Byte: - return true; - case Short: - case Char: - return to != Kind.Byte; - case Int: - return to == Kind.Long || to == Kind.Double; - case Float: - return to == Kind.Double; - case Long: - case Double: - return false; - } - throw GraalInternalError.shouldNotReachHere(); + protected ConvertNode(Stamp stamp, ValueNode input) { + super(stamp); + this.input = input; } - public static Constant convert(Kind from, Kind to, Constant c) { - switch (from) { - case Byte: - byte byteVal = (byte) c.asInt(); - switch (to) { - case Byte: - return Constant.forByte(byteVal); - case Short: - return Constant.forShort(byteVal); - case Char: - return Constant.forChar((char) byteVal); - case Int: - return Constant.forInt(byteVal); - case Long: - return Constant.forLong(byteVal); - case Float: - return Constant.forFloat(byteVal); - case Double: - return Constant.forDouble(byteVal); - } - break; - case Char: - char charVal = (char) c.asInt(); - switch (to) { - case Byte: - return Constant.forByte((byte) charVal); - case Short: - return Constant.forShort((short) charVal); - case Char: - return Constant.forChar(charVal); - case Int: - return Constant.forInt(charVal); - case Long: - return Constant.forLong(charVal); - case Float: - return Constant.forFloat(charVal); - case Double: - return Constant.forDouble(charVal); - } - break; - case Short: - short shortVal = (short) c.asInt(); - switch (to) { - case Byte: - return Constant.forByte((byte) shortVal); - case Short: - return Constant.forShort(shortVal); - case Char: - return Constant.forChar((char) shortVal); - case Int: - return Constant.forInt(shortVal); - case Long: - return Constant.forLong(shortVal); - case Float: - return Constant.forFloat(shortVal); - case Double: - return Constant.forDouble(shortVal); - } - break; - case Int: - int intVal = c.asInt(); - switch (to) { - case Byte: - return Constant.forByte((byte) intVal); - case Short: - return Constant.forShort((short) intVal); - case Char: - return Constant.forChar((char) intVal); - case Int: - return Constant.forInt(intVal); - case Long: - return Constant.forLong(intVal); - case Float: - return Constant.forFloat(intVal); - case Double: - return Constant.forDouble(intVal); - } - break; - case Long: - long longVal = c.asLong(); - switch (to) { - case Byte: - return Constant.forByte((byte) longVal); - case Short: - return Constant.forShort((short) longVal); - case Char: - return Constant.forChar((char) longVal); - case Int: - return Constant.forInt((int) longVal); - case Long: - return Constant.forLong(longVal); - case Float: - return Constant.forFloat(longVal); - case Double: - return Constant.forDouble(longVal); - } - break; - case Float: - float floatVal = c.asFloat(); - switch (to) { - case Byte: - return Constant.forByte((byte) floatVal); - case Short: - return Constant.forShort((short) floatVal); - case Char: - return Constant.forChar((char) floatVal); - case Int: - return Constant.forInt((int) floatVal); - case Long: - return Constant.forLong((long) floatVal); - case Float: - return Constant.forFloat(floatVal); - case Double: - return Constant.forDouble(floatVal); - } - break; - case Double: - double doubleVal = c.asDouble(); - switch (to) { - case Byte: - return Constant.forByte((byte) doubleVal); - case Short: - return Constant.forShort((short) doubleVal); - case Char: - return Constant.forChar((char) doubleVal); - case Int: - return Constant.forInt((int) doubleVal); - case Long: - return Constant.forLong((long) doubleVal); - case Float: - return Constant.forFloat((float) doubleVal); - case Double: - return Constant.forDouble(doubleVal); - } - break; - } - throw GraalInternalError.shouldNotReachHere(); + public ValueNode getInput() { + return input; } - public Constant evalConst(Constant... inputs) { - assert inputs.length == 1; - return convert(from, to, inputs[0]); - } + public abstract Constant convert(Constant c); - @Override - public Node canonical(CanonicalizerTool tool) { - if (from == to) { - return value; - } else if (value.isConstant()) { - return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph()); - } else if (value instanceof ConvertNode) { - ConvertNode other = (ConvertNode) value; - if (other.isLossless() && other.to != Kind.Char) { - if (other.from == this.to) { - return other.value(); - } else { - return graph().unique(new ConvertNode(other.from, this.to, other.value())); - } - } - } - return this; - } + public abstract Constant reverse(Constant c); + + public abstract boolean isLossless(); @Override - public boolean inferStamp() { - Stamp stamp = value.stamp(); - if (!(stamp instanceof IntegerStamp)) { - if (stamp instanceof FloatStamp) { - return false; - } - assert stamp instanceof IllegalStamp; - return updateStamp(stamp); - } - Stamp newStamp; - IntegerStamp integerStamp = (IntegerStamp) stamp; - switch (to) { - case Byte: - case Short: - case Char: - case Int: - newStamp = StampTool.narrowingKindConversion(integerStamp, to); - break; - case Long: - newStamp = StampTool.intToLong(integerStamp); - break; - default: - return false; - } - return updateStamp(newStamp); - } - - @Override - public void lower(LoweringTool tool) { - tool.getLowerer().lower(this, tool); - } - - @Override - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitConvert(from, to, gen.operand(value()))); - } - - public static ValueNode convert(StructuredGraph graph, Kind toKind, ValueNode value) { - Kind fromKind = value.kind(); - if (fromKind == toKind) { - return value; - } - return graph.unique(new ConvertNode(fromKind, toKind, value)); + public Constant evalConst(Constant... inputs) { + assert inputs.length == 1; + return convert(inputs[0]); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,7 +22,6 @@ */ package com.oracle.graal.nodes.calc; -import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; @@ -39,8 +38,8 @@ return y; } - public FixedBinaryNode(Kind kind, ValueNode x, ValueNode y) { - super(StampFactory.forKind(kind)); + public FixedBinaryNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp); this.x = x; this.y = y; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,20 +27,22 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "+") public final class FloatAddNode extends FloatArithmeticNode implements Canonicalizable { - public FloatAddNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { - super(kind, x, y, isStrictFP); + public FloatAddNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) { + super(stamp, x, y, isStrictFP); } public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Float) { + assert inputs[0].getKind() == inputs[1].getKind(); + if (inputs[0].getKind() == Kind.Float) { return Constant.forFloat(inputs[0].asFloat() + inputs[1].asFloat()); } else { - assert kind() == Kind.Double; + assert inputs[0].getKind() == Kind.Double; return Constant.forDouble(inputs[0].asDouble() + inputs[1].asDouble()); } } @@ -48,22 +50,14 @@ @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { - return graph().unique(new FloatAddNode(kind(), y(), x(), isStrictFP())); + return graph().unique(new FloatAddNode(stamp(), y(), x(), isStrictFP())); } if (x().isConstant()) { return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { - if (kind() == Kind.Float) { - float c = y().asConstant().asFloat(); - if (c == 0.0f) { - return x(); - } - } else { - assert kind() == Kind.Double; - double c = y().asConstant().asDouble(); - if (c == 0.0) { - return x(); - } + Constant c = y().asConstant(); + if ((c.getKind() == Kind.Float && c.asFloat() == 0.0f) || (c.getKind() == Kind.Double && c.asDouble() == 0.0)) { + return x(); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,17 +22,17 @@ */ package com.oracle.graal.nodes.calc; -import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable { private final boolean isStrictFP; - public FloatArithmeticNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { - super(kind, x, y); - assert kind.isNumericFloat(); + public FloatArithmeticNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) { + super(stamp, x, y); + assert stamp instanceof FloatStamp; this.isStrictFP = isStrictFP; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,197 @@ +/* + * 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.nodes.calc; + +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.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A {@code FloatConvert} converts between integers and floating point numbers according to Java + * semantics. + */ +public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable { + + public enum FloatConvert { + F2I, D2I, F2L, D2L, I2F, L2F, D2F, I2D, L2D, F2D; + + public FloatConvert reverse() { + switch (this) { + case D2F: + return F2D; + case D2I: + return I2D; + case D2L: + return L2D; + case F2D: + return D2F; + case F2I: + return I2F; + case F2L: + return L2F; + case I2D: + return D2I; + case I2F: + return F2I; + case L2D: + return D2L; + case L2F: + return F2L; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + + private final FloatConvert op; + + public FloatConvertNode(FloatConvert op, ValueNode input) { + super(createStamp(op, input), input); + this.op = op; + } + + private static Stamp createStamp(FloatConvert op, ValueNode input) { + switch (op) { + case I2F: + case I2D: + assert input.stamp() instanceof IntegerStamp && ((IntegerStamp) input.stamp()).getBits() == 32; + break; + case L2F: + case L2D: + assert input.stamp() instanceof IntegerStamp && ((IntegerStamp) input.stamp()).getBits() == 64; + break; + case F2I: + case F2L: + case F2D: + assert input.stamp() instanceof FloatStamp && ((FloatStamp) input.stamp()).getBits() == 32; + break; + case D2I: + case D2L: + case D2F: + assert input.stamp() instanceof FloatStamp && ((FloatStamp) input.stamp()).getBits() == 64; + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + + switch (op) { + case F2I: + case D2I: + return StampFactory.forKind(Kind.Int); + case F2L: + case D2L: + return StampFactory.forKind(Kind.Long); + case I2F: + case L2F: + case D2F: + return StampFactory.forKind(Kind.Float); + case I2D: + case L2D: + case F2D: + return StampFactory.forKind(Kind.Double); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + public FloatConvert getOp() { + return op; + } + + @Override + public boolean inferStamp() { + return updateStamp(createStamp(op, getInput())); + } + + private static Constant convert(FloatConvert op, Constant value) { + switch (op) { + case F2I: + return Constant.forInt((int) value.asFloat()); + case D2I: + return Constant.forInt((int) value.asDouble()); + case F2L: + return Constant.forLong((long) value.asFloat()); + case D2L: + return Constant.forLong((long) value.asDouble()); + case I2F: + return Constant.forFloat(value.asInt()); + case L2F: + return Constant.forFloat(value.asLong()); + case D2F: + return Constant.forFloat((float) value.asDouble()); + case I2D: + return Constant.forDouble(value.asInt()); + case L2D: + return Constant.forDouble(value.asLong()); + case F2D: + return Constant.forDouble(value.asFloat()); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public Constant convert(Constant c) { + return convert(op, c); + } + + @Override + public Constant reverse(Constant c) { + return convert(op.reverse(), c); + } + + @Override + public boolean isLossless() { + switch (op) { + case F2D: + case I2D: + return true; + default: + return false; + } + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (getInput().isConstant()) { + return ConstantNode.forPrimitive(evalConst(getInput().asConstant()), graph()); + } else if (getInput() instanceof FloatConvertNode) { + FloatConvertNode other = (FloatConvertNode) getInput(); + if (other.isLossless() && other.op == this.op.reverse()) { + return other.getInput(); + } + } + return this; + } + + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public void generate(ArithmeticLIRGenerator gen) { + gen.setResult(this, gen.emitFloatConvert(op, gen.operand(getInput()))); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,20 +27,22 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "/") public final class FloatDivNode extends FloatArithmeticNode implements Canonicalizable { - public FloatDivNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { - super(kind, x, y, isStrictFP); + public FloatDivNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) { + super(stamp, x, y, isStrictFP); } public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Float) { + assert inputs[0].getKind() == inputs[1].getKind(); + if (inputs[0].getKind() == Kind.Float) { return Constant.forFloat(inputs[0].asFloat() / inputs[1].asFloat()); } else { - assert kind() == Kind.Double; + assert inputs[0].getKind() == Kind.Double; return Constant.forDouble(inputs[0].asDouble() / inputs[1].asDouble()); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,9 +22,9 @@ */ package com.oracle.graal.nodes.calc; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "==") public final class FloatEqualsNode extends CompareNode { @@ -37,8 +37,8 @@ */ public FloatEqualsNode(ValueNode x, ValueNode y) { super(x, y); - assert x.kind() == Kind.Double || x.kind() == Kind.Float; - assert y.kind() == Kind.Double || y.kind() == Kind.Float; + assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp; + assert x.stamp().isCompatible(y.stamp()); } @Override diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,10 +22,10 @@ */ package com.oracle.graal.nodes.calc; -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.type.*; @NodeInfo(shortName = "<") public final class FloatLessThanNode extends CompareNode { @@ -42,8 +42,8 @@ */ public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) { super(x, y); - assert x.kind() == Kind.Double || x.kind() == Kind.Float; - assert y.kind() == Kind.Double || y.kind() == Kind.Float; + assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp; + assert x.stamp().isCompatible(y.stamp()); this.unorderedIsTrue = unorderedIsTrue; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,20 +27,22 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "*") public final class FloatMulNode extends FloatArithmeticNode implements Canonicalizable { - public FloatMulNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { - super(kind, x, y, isStrictFP); + public FloatMulNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) { + super(stamp, x, y, isStrictFP); } public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Float) { + assert inputs[0].getKind() == inputs[1].getKind(); + if (inputs[0].getKind() == Kind.Float) { return Constant.forFloat(inputs[0].asFloat() * inputs[1].asFloat()); } else { - assert kind() == Kind.Double; + assert inputs[0].getKind() == Kind.Double; return Constant.forDouble(inputs[0].asDouble() * inputs[1].asDouble()); } } @@ -48,7 +50,7 @@ @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { - return graph().unique(new FloatMulNode(kind(), y(), x(), isStrictFP())); + return graph().unique(new FloatMulNode(stamp(), y(), x(), isStrictFP())); } if (x().isConstant()) { return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,20 +27,22 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "%") public final class FloatRemNode extends FloatArithmeticNode implements Canonicalizable { - public FloatRemNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { - super(kind, x, y, isStrictFP); + public FloatRemNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) { + super(stamp, x, y, isStrictFP); } public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Float) { + assert inputs[0].getKind() == inputs[1].getKind(); + if (inputs[0].getKind() == Kind.Float) { return Constant.forFloat(inputs[0].asFloat() % inputs[1].asFloat()); } else { - assert kind() == Kind.Double; + assert inputs[0].getKind() == Kind.Double; return Constant.forDouble(inputs[0].asDouble() % inputs[1].asDouble()); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,20 +27,22 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "-") public final class FloatSubNode extends FloatArithmeticNode implements Canonicalizable { - public FloatSubNode(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { - super(kind, x, y, isStrictFP); + public FloatSubNode(Stamp stamp, ValueNode x, ValueNode y, boolean isStrictFP) { + super(stamp, x, y, isStrictFP); } public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - if (kind() == Kind.Float) { + assert inputs[0].getKind() == inputs[1].getKind(); + if (inputs[0].getKind() == Kind.Float) { return Constant.forFloat(inputs[0].asFloat() - inputs[1].asFloat()); } else { - assert kind() == Kind.Double; + assert inputs[0].getKind() == Kind.Double; return Constant.forDouble(inputs[0].asDouble() - inputs[1].asDouble()); } } @@ -48,24 +50,25 @@ @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { - return ConstantNode.forFloatingKind(kind(), 0.0f, graph()); + return ConstantNode.forFloatingStamp(stamp(), 0.0f, graph()); } if (x().isConstant() && y().isConstant()) { return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { - if (kind() == Kind.Float) { - float c = y().asConstant().asFloat(); - if (c == 0.0f) { + Constant c = y().asConstant(); + if (c.getKind() == Kind.Float) { + float f = c.asFloat(); + if (f == 0.0f) { return x(); } - return graph().unique(new FloatAddNode(kind(), x(), ConstantNode.forFloat(-c, graph()), isStrictFP())); + return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forFloat(-f, graph()), isStrictFP())); } else { - assert kind() == Kind.Double; - double c = y().asConstant().asDouble(); - if (c == 0.0) { + assert c.getKind() == Kind.Double; + double d = c.asDouble(); + if (d == 0.0) { return x(); } - return graph().unique(new FloatAddNode(kind(), x(), ConstantNode.forDouble(-c, graph()), isStrictFP())); + return graph().unique(new FloatAddNode(stamp(), x(), ConstantNode.forDouble(-d, graph()), isStrictFP())); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -30,10 +30,10 @@ import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "+") -public class IntegerAddNode extends IntegerArithmeticNode implements Canonicalizable { +public class IntegerAddNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode { - public IntegerAddNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public IntegerAddNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -44,13 +44,13 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - return Constant.forIntegerKind(kind(), inputs[0].asLong() + inputs[1].asLong(), null); + return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() + inputs[1].asLong()); } @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { - return graph().unique(new IntegerAddNode(kind(), y(), x())); + return graph().unique(new IntegerAddNode(stamp(), y(), x())); } if (x() instanceof IntegerSubNode) { IntegerSubNode sub = (IntegerSubNode) x(); @@ -79,12 +79,7 @@ return reassociated; } if (c < 0) { - if (kind() == Kind.Int) { - return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forInt((int) -c, graph())); - } else { - assert kind() == Kind.Long; - return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forLong(-c, graph())); - } + return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph())); } } if (x() instanceof NegateNode) { @@ -95,24 +90,6 @@ return this; } - public static boolean isIntegerAddition(ValueNode result, ValueNode a, ValueNode b) { - Kind kind = result.kind(); - if (kind != a.kind() || kind != b.kind() || !kind.isNumericInteger()) { - return false; - } - if (result.isConstant() && a.isConstant() && b.isConstant()) { - if (kind.getStackKind() == Kind.Int) { - return result.asConstant().asInt() == a.asConstant().asInt() + b.asConstant().asInt(); - } else if (kind == Kind.Long) { - return result.asConstant().asLong() == a.asConstant().asLong() + b.asConstant().asLong(); - } - } else if (result instanceof IntegerAddNode) { - IntegerAddNode add = (IntegerAddNode) result; - return (add.x() == a && add.y() == b) || (add.y() == a && add.x() == b); - } - return false; - } - @Override public void generate(ArithmeticLIRGenerator gen) { Value op1 = gen.operand(x()); diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,50 +22,27 @@ */ package com.oracle.graal.nodes.calc; -import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable { - public IntegerArithmeticNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); - assert kind.isNumericInteger(); + public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); + assert stamp instanceof IntegerStamp; } 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(StampTool.add(v1.stamp(), v2.stamp()), 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(); - } + assert v1.stamp().isCompatible(v2.stamp()); + return graph.unique(new IntegerMulNode(v1.stamp().unrestricted(), 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(StampTool.sub(v1.stamp(), v2.stamp()), v1, v2)); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,103 @@ +/* + * 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.nodes.calc; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * An {@code IntegerConvert} converts an integer to an integer of different width. + */ +public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable { + + private final int resultBits; + + protected IntegerConvertNode(Stamp stamp, ValueNode input, int resultBits) { + super(stamp, input); + this.resultBits = resultBits; + } + + public int getResultBits() { + return resultBits; + } + + public int getInputBits() { + if (getInput().stamp() instanceof IntegerStamp) { + return ((IntegerStamp) getInput().stamp()).getBits(); + } else { + return 0; + } + } + + public static long convert(long value, int bits, boolean unsigned) { + if (unsigned) { + return ZeroExtendNode.zeroExtend(value, bits); + } else { + return SignExtendNode.signExtend(value, bits); + } + } + + protected ValueNode canonicalConvert() { + if (getInput().stamp() instanceof IntegerStamp) { + int inputBits = ((IntegerStamp) getInput().stamp()).getBits(); + if (inputBits == resultBits) { + return getInput(); + } else if (getInput().isConstant()) { + Constant ret = evalConst(getInput().asConstant()); + return ConstantNode.forIntegerBits(resultBits, false, ret.asLong(), graph()); + } + } + + return null; + } + + public static ValueNode convert(ValueNode input, Stamp stamp) { + StructuredGraph graph = input.graph(); + IntegerStamp fromStamp = (IntegerStamp) input.stamp(); + IntegerStamp toStamp = (IntegerStamp) stamp; + + ValueNode result; + if (toStamp.getBits() == fromStamp.getBits()) { + result = input; + } else if (toStamp.getBits() < fromStamp.getBits()) { + result = graph.unique(new NarrowNode(input, toStamp.getBits())); + } else { + // toStamp.getBits() > fromStamp.getBits() + if (fromStamp.isUnsigned()) { + result = graph.unique(new ZeroExtendNode(input, toStamp.getBits())); + } else { + result = graph.unique(new SignExtendNode(input, toStamp.getBits())); + } + } + + IntegerStamp resultStamp = (IntegerStamp) result.stamp(); + assert toStamp.getBits() == resultStamp.getBits(); + if (toStamp.isUnsigned() == resultStamp.isUnsigned()) { + return result; + } else { + return graph.unique(new ReinterpretNode(toStamp, result)); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,7 +23,6 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; @@ -33,8 +32,8 @@ @NodeInfo(shortName = "/") public class IntegerDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable { - public IntegerDivNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public IntegerDivNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -45,16 +44,11 @@ @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && y().isConstant()) { - long yConst = y().asConstant().asLong(); - if (yConst == 0) { + long y = y().asConstant().asLong(); + if (y == 0) { return this; // this will trap, can not canonicalize } - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() / (int) yConst, graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() / yConst, graph()); - } + return ConstantNode.forIntegerStamp(stamp(), x().asConstant().asLong() / y, graph()); } else if (y().isConstant()) { long c = y().asConstant().asLong(); if (c == 1) { @@ -65,23 +59,18 @@ } long abs = Math.abs(c); if (CodeUtil.isPowerOf2(abs) && x().stamp() instanceof IntegerStamp) { + Stamp unrestricted = stamp().unrestricted(); ValueNode dividend = x(); IntegerStamp stampX = (IntegerStamp) x().stamp(); int log2 = CodeUtil.log2(abs); // no rounding if dividend is positive or if its low bits are always 0 if (stampX.canBeNegative() || (stampX.upMask() & (abs - 1)) != 0) { - int bits; - if (kind().getStackKind() == Kind.Int) { - bits = 32; - } else { - assert kind() == Kind.Long; - bits = 64; - } - RightShiftNode sign = graph().unique(new RightShiftNode(kind(), x(), ConstantNode.forInt(bits - 1, graph()))); - UnsignedRightShiftNode round = graph().unique(new UnsignedRightShiftNode(kind(), sign, ConstantNode.forInt(bits - log2, graph()))); + int bits = PrimitiveStamp.getBits(stamp()); + RightShiftNode sign = graph().unique(new RightShiftNode(unrestricted, x(), ConstantNode.forInt(bits - 1, graph()))); + UnsignedRightShiftNode round = graph().unique(new UnsignedRightShiftNode(unrestricted, sign, ConstantNode.forInt(bits - log2, graph()))); dividend = IntegerArithmeticNode.add(graph(), dividend, round); } - RightShiftNode shift = graph().unique(new RightShiftNode(kind(), dividend, ConstantNode.forInt(log2, graph()))); + RightShiftNode shift = graph().unique(new RightShiftNode(unrestricted, dividend, ConstantNode.forInt(log2, graph()))); if (c < 0) { return graph().unique(new NegateNode(shift)); } @@ -94,8 +83,9 @@ IntegerSubNode integerSubNode = (IntegerSubNode) x(); if (integerSubNode.y() instanceof IntegerRemNode) { IntegerRemNode integerRemNode = (IntegerRemNode) integerSubNode.y(); - if (integerSubNode.kind() == this.kind() && integerRemNode.kind() == this.kind() && integerSubNode.x() == integerRemNode.x() && this.y() == integerRemNode.y()) { - return graph().add(new IntegerDivNode(kind(), integerSubNode.x(), this.y())); + if (integerSubNode.stamp().isCompatible(this.stamp()) && integerRemNode.stamp().isCompatible(this.stamp()) && integerSubNode.x() == integerRemNode.x() && + this.y() == integerRemNode.y()) { + return graph().add(new IntegerDivNode(stamp(), integerSubNode.x(), this.y())); } } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,24 +28,25 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "*") -public class IntegerMulNode extends IntegerArithmeticNode implements Canonicalizable { +public class IntegerMulNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode { - public IntegerMulNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public IntegerMulNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - return Constant.forIntegerKind(kind(), inputs[0].asLong() * inputs[1].asLong(), null); + return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() * inputs[1].asLong()); } @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && !y().isConstant()) { - return graph().unique(new IntegerMulNode(kind(), y(), x())); + return graph().unique(new IntegerMulNode(stamp(), y(), x())); } if (x().isConstant()) { return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); @@ -55,11 +56,11 @@ return x(); } if (c == 0) { - return ConstantNode.defaultForKind(kind(), graph()); + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } long abs = Math.abs(c); if (abs > 0 && CodeUtil.isPowerOf2(abs)) { - LeftShiftNode shift = graph().unique(new LeftShiftNode(kind(), x(), ConstantNode.forInt(CodeUtil.log2(abs), graph()))); + LeftShiftNode shift = graph().unique(new LeftShiftNode(stamp().unrestricted(), x(), ConstantNode.forInt(CodeUtil.log2(abs), graph()))); if (c < 0) { return graph().unique(new NegateNode(shift)); } else { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,7 +23,6 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; @@ -33,29 +32,24 @@ @NodeInfo(shortName = "%") public class IntegerRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable { - public IntegerRemNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public IntegerRemNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override public Node canonical(CanonicalizerTool tool) { if (x().isConstant() && y().isConstant()) { - long yConst = y().asConstant().asLong(); - if (yConst == 0) { + long y = y().asConstant().asLong(); + if (y == 0) { return this; // this will trap, can not canonicalize } - if (kind() == Kind.Int) { - return ConstantNode.forInt(x().asConstant().asInt() % (int) yConst, graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(x().asConstant().asLong() % yConst, graph()); - } + return ConstantNode.forIntegerStamp(stamp(), x().asConstant().asLong() % y, graph()); } else if (y().isConstant()) { long c = y().asConstant().asLong(); if (c == 1 || c == -1) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } else if (c > 0 && CodeUtil.isPowerOf2(c) && x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) { - return graph().unique(new AndNode(kind(), x(), ConstantNode.forIntegerKind(kind(), c - 1, graph()))); + return graph().unique(new AndNode(stamp(), x(), ConstantNode.forIntegerStamp(stamp(), c - 1, graph()))); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -30,10 +30,10 @@ import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "-") -public class IntegerSubNode extends IntegerArithmeticNode implements Canonicalizable { +public class IntegerSubNode extends IntegerArithmeticNode implements Canonicalizable, NarrowableArithmeticNode { - public IntegerSubNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public IntegerSubNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -44,13 +44,13 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - return Constant.forIntegerKind(kind(), inputs[0].asLong() - inputs[1].asLong(), null); + return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() - inputs[1].asLong()); } @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } if (x() instanceof IntegerAddNode) { IntegerAddNode x = (IntegerAddNode) x(); @@ -98,12 +98,7 @@ return reassociated; } if (c < 0) { - if (kind() == Kind.Int) { - return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forInt((int) -c, graph())); - } else { - assert kind() == Kind.Long; - return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forLong(-c, graph())); - } + return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph())); } } else if (x().isConstant()) { long c = x().asConstant().asLong(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -53,7 +53,7 @@ * @param y the instruction that produces the second input to this instruction */ public IntegerTestNode(ValueNode x, ValueNode y) { - assert (x == null && y == null) || x.kind() == y.kind(); + assert (x == null && y == null) || x.stamp().isCompatible(y.stamp()); this.x = x; this.y = y; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,8 +32,8 @@ @NodeInfo(shortName = "<<") public final class LeftShiftNode extends ShiftNode implements Canonicalizable { - public LeftShiftNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public LeftShiftNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -79,19 +79,19 @@ if (total != (total & mask)) { return ConstantNode.forIntegerKind(kind(), 0, graph()); } - return graph().unique(new LeftShiftNode(kind(), other.x(), ConstantNode.forInt(total, graph()))); + return graph().unique(new LeftShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph()))); } else if ((other instanceof RightShiftNode || other instanceof UnsignedRightShiftNode) && otherAmount == amount) { if (kind() == Kind.Long) { - return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forLong(-1L << amount, graph()))); + return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L << amount, graph()))); } else { assert kind() == Kind.Int; - return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forInt(-1 << amount, graph()))); + return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 << amount, graph()))); } } } } if (originalAmout != amount) { - return graph().unique(new LeftShiftNode(kind(), x(), ConstantNode.forInt(amount, graph()))); + return graph().unique(new LeftShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph()))); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,142 @@ +/* + * 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.nodes.calc; + +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.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * The {@code NarrowNode} converts an integer to a narrower integer. + */ +public class NarrowNode extends IntegerConvertNode implements Simplifiable { + + public NarrowNode(ValueNode input, int resultBits) { + super(StampTool.narrowingConversion(input.stamp(), resultBits), input, resultBits); + } + + public static long narrow(long value, int resultBits) { + return value & IntegerStamp.defaultMask(resultBits); + } + + @Override + public Constant convert(Constant c) { + return Constant.forPrimitiveInt(getResultBits(), narrow(c.asLong(), getResultBits())); + } + + @Override + public Constant reverse(Constant input) { + IntegerStamp stamp = (IntegerStamp) stamp(); + long result; + if (stamp.isUnsigned()) { + result = ZeroExtendNode.zeroExtend(input.asLong(), getResultBits()); + } else { + result = SignExtendNode.signExtend(input.asLong(), getResultBits()); + } + return Constant.forPrimitiveInt(getInputBits(), result); + } + + @Override + public boolean isLossless() { + return false; + } + + private ValueNode tryCanonicalize() { + ValueNode ret = canonicalConvert(); + if (ret != null) { + return ret; + } + + if (getInput() instanceof NarrowNode) { + // zzzzzzzz yyyyxxxx -(narrow)-> yyyyxxxx -(narrow)-> xxxx + // ==> zzzzzzzz yyyyxxxx -(narrow)-> xxxx + NarrowNode other = (NarrowNode) getInput(); + return graph().unique(new NarrowNode(other.getInput(), getResultBits())); + } else if (getInput() instanceof IntegerConvertNode) { + // SignExtendNode or ZeroExtendNode + IntegerConvertNode other = (IntegerConvertNode) getInput(); + if (getResultBits() == other.getInputBits()) { + // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx + // ==> no-op + return other.getInput(); + } else if (getResultBits() < other.getInputBits()) { + // yyyyxxxx -(extend)-> zzzzzzzz yyyyxxxx -(narrow)-> xxxx + // ==> yyyyxxxx -(narrow)-> xxxx + return graph().unique(new NarrowNode(other.getInput(), getResultBits())); + } else { + if (other instanceof SignExtendNode) { + // sxxx -(sign-extend)-> ssssssss sssssxxx -(narrow)-> sssssxxx + // ==> sxxx -(sign-extend)-> sssssxxx + return graph().unique(new SignExtendNode(other.getInput(), getResultBits())); + } else if (other instanceof ZeroExtendNode) { + // xxxx -(zero-extend)-> 00000000 00000xxx -(narrow)-> 0000xxxx + // ==> xxxx -(zero-extend)-> 0000xxxx + return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits())); + } + } + } + + return null; + } + + private boolean tryNarrow(SimplifierTool tool, Stamp stamp, ValueNode node) { + boolean canNarrow = node instanceof NarrowableArithmeticNode && node.usages().count() == 1; + + if (canNarrow) { + for (Node inputNode : node.inputs().snapshot()) { + ValueNode input = (ValueNode) inputNode; + if (!tryNarrow(tool, stamp, input)) { + ValueNode narrow = graph().unique(new NarrowNode(input, getResultBits())); + node.replaceFirstInput(input, narrow); + tool.addToWorkList(narrow); + } + } + node.setStamp(stamp); + } + + return canNarrow; + } + + @Override + public void simplify(SimplifierTool tool) { + ValueNode ret = tryCanonicalize(); + if (ret != null) { + graph().replaceFloating(this, ret); + } else if (tryNarrow(tool, stamp().unrestricted(), getInput())) { + graph().replaceFloating(this, getInput()); + } + } + + @Override + public boolean inferStamp() { + return updateStamp(StampTool.narrowingConversion(getInput().stamp(), getResultBits())); + } + + @Override + public void generate(ArithmeticLIRGenerator gen) { + gen.setResult(this, gen.emitNarrow(gen.operand(getInput()), getResultBits())); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,31 @@ +/* + * 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.nodes.calc; + +/** + * Marker interface for nodes where it is valid to apply a {@link NarrowNode} to its inputs and do a + * narrow operation instead of doing the wide operation and applying the {@link NarrowNode} to the + * result. + */ +public interface NarrowableArithmeticNode { +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,7 +32,7 @@ /** * The {@code NegateNode} node negates its operand. */ -public final class NegateNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable { +public final class NegateNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode { @Input private ValueNode x; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -25,6 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; /** * Returns -1, 0, or 1 if either x < y, x == y, or x > y. If the comparison is undecided (one of the @@ -43,7 +44,7 @@ * less, false when greater. */ public NormalizeCompareNode(ValueNode x, ValueNode y, boolean isUnorderedLess) { - super(Kind.Int, x, y); + super(StampFactory.forKind(Kind.Int), x, y); this.isUnorderedLess = isUnorderedLess; } @@ -51,7 +52,7 @@ public void lower(LoweringTool tool) { LogicNode equalComp; LogicNode lessComp; - if (x().kind() == Kind.Double || x().kind() == Kind.Float) { + if (x().stamp() instanceof FloatStamp) { equalComp = graph().unique(new FloatEqualsNode(x(), y())); lessComp = graph().unique(new FloatLessThanNode(x(), y(), isUnorderedLess)); } else { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,7 +32,7 @@ /** * Binary negation of long or integer values. */ -public final class NotNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable { +public final class NotNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, NarrowableArithmeticNode { @Input private ValueNode x; @@ -48,7 +48,7 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 1; - return Constant.forIntegerKind(kind(), ~inputs[0].asLong(), null); + return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), ~inputs[0].asLong()); } /** @@ -58,7 +58,6 @@ */ public NotNode(ValueNode x) { super(StampTool.not(x.stamp())); - assert x.kind() == Kind.Int || x.kind() == Kind.Long; this.x = x; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,8 +32,8 @@ @NodeInfo(shortName = "|") public final class OrNode extends BitLogicNode implements Canonicalizable { - public OrNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public OrNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -44,7 +44,7 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - return Constant.forIntegerKind(kind(), inputs[0].asLong() | inputs[1].asLong(), null); + return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() | inputs[1].asLong()); } @Override @@ -53,28 +53,18 @@ return x(); } if (x().isConstant() && !y().isConstant()) { - return graph().unique(new OrNode(kind(), y(), x())); + return graph().unique(new OrNode(stamp(), y(), x())); } if (x().isConstant()) { - return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); + return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { - if (kind() == Kind.Int) { - int c = y().asConstant().asInt(); - if (c == -1) { - return ConstantNode.forInt(-1, graph()); - } - if (c == 0) { - return x(); - } - } else { - assert kind() == Kind.Long; - long c = y().asConstant().asLong(); - if (c == -1) { - return ConstantNode.forLong(-1, graph()); - } - if (c == 0) { - return x(); - } + long rawY = y().asConstant().asLong(); + long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp())); + if ((rawY & mask) == mask) { + return ConstantNode.forIntegerStamp(stamp(), mask, graph()); + } + if ((rawY & mask) == 0) { + return x(); } return BinaryNode.reassociate(this, ValueNode.isConstantPredicate()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,7 +30,9 @@ import com.oracle.graal.nodes.type.*; /** - * The {@code ReinterpretNode} class represents a reinterpreting conversion between primitive types. + * The {@code ReinterpretNode} class represents a reinterpreting conversion that changes the stamp + * of a primitive value to some other incompatible stamp. The new stamp must have the same width as + * the old stamp. */ public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable { @@ -40,64 +42,45 @@ return value; } - public ReinterpretNode(Kind to, ValueNode value) { - super(StampFactory.forKind(to.getStackKind())); + private ReinterpretNode(Kind to, ValueNode value) { + this(StampFactory.forKind(to), value); + } + + public ReinterpretNode(Stamp to, ValueNode value) { + super(to); + assert to instanceof PrimitiveStamp; this.value = value; } public Constant evalConst(Constant... inputs) { assert inputs.length == 1; Constant c = inputs[0]; - assert c.getKind() == value.kind(); + assert c.getKind().getBitCount() == ((PrimitiveStamp) stamp()).getBits(); switch (c.getKind()) { case Int: - switch (kind()) { - case Int: - return c; - case Long: - return Constant.forLong(c.asInt() & 0xFFFFFFFFL); - case Float: - return Constant.forFloat(Float.intBitsToFloat(c.asInt())); - case Double: - return Constant.forDouble(Double.longBitsToDouble(c.asInt() & 0xFFFFFFFFL)); + if (stamp() instanceof FloatStamp) { + return Constant.forFloat(Float.intBitsToFloat(c.asInt())); + } else { + return c; } - break; case Long: - switch (kind()) { - case Int: - return Constant.forInt((int) c.asLong()); - case Long: - return c; - case Float: - return Constant.forFloat(Float.intBitsToFloat((int) c.asLong())); - case Double: - return Constant.forDouble(Double.longBitsToDouble(c.asLong())); + if (stamp() instanceof FloatStamp) { + return Constant.forDouble(Double.longBitsToDouble(c.asLong())); + } else { + return c; } - break; case Float: - switch (kind()) { - case Int: - return Constant.forInt(Float.floatToRawIntBits(c.asFloat())); - case Long: - return Constant.forLong(Float.floatToRawIntBits(c.asFloat()) & 0xFFFFFFFFL); - case Float: - return c; - case Double: - return Constant.forDouble(Double.longBitsToDouble(Float.floatToRawIntBits(c.asFloat()) & 0xFFFFFFFFL)); + if (stamp() instanceof IntegerStamp) { + return Constant.forInt(Float.floatToRawIntBits(c.asFloat())); + } else { + return c; } - break; case Double: - switch (kind()) { - case Int: - return Constant.forInt((int) Double.doubleToRawLongBits(c.asDouble())); - case Long: - return Constant.forLong(Double.doubleToRawLongBits(c.asDouble())); - case Float: - return Constant.forFloat(Float.intBitsToFloat((int) Double.doubleToRawLongBits(c.asDouble()))); - case Double: - return c; + if (stamp() instanceof IntegerStamp) { + return Constant.forLong(Double.doubleToRawLongBits(c.asDouble())); + } else { + return c; } - break; } throw GraalInternalError.shouldNotReachHere(); } @@ -107,19 +90,19 @@ if (value.isConstant()) { return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph()); } + if (stamp().isCompatible(value.stamp())) { + return value; + } return this; } @Override public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitReinterpret(kind(), gen.operand(value()))); + PlatformKind kind = gen.getPlatformKind(stamp()); + gen.setResult(this, gen.emitReinterpret(kind, gen.operand(value()))); } public static ValueNode reinterpret(Kind toKind, ValueNode value) { - Kind fromKind = value.kind(); - if (fromKind == toKind) { - return value; - } return value.graph().unique(new ReinterpretNode(toKind, value)); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,8 +32,8 @@ @NodeInfo(shortName = ">>") public final class RightShiftNode extends ShiftNode implements Canonicalizable { - public RightShiftNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public RightShiftNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -50,7 +50,7 @@ @Override public Node canonical(CanonicalizerTool tool) { if (x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) { - return graph().unique(new UnsignedRightShiftNode(kind(), x(), y())); + return graph().unique(new UnsignedRightShiftNode(stamp(), x(), y())); } if (x().isConstant() && y().isConstant()) { return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); @@ -90,14 +90,14 @@ * full shift for this kind */ assert total >= mask; - return graph().unique(new RightShiftNode(kind(), other.x(), ConstantNode.forInt(mask, graph()))); + return graph().unique(new RightShiftNode(stamp(), other.x(), ConstantNode.forInt(mask, graph()))); } - return graph().unique(new RightShiftNode(kind(), other.x(), ConstantNode.forInt(total, graph()))); + return graph().unique(new RightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph()))); } } } if (originalAmout != amount) { - return graph().unique(new RightShiftNode(kind(), x(), ConstantNode.forInt(amount, graph()))); + return graph().unique(new RightShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph()))); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,9 +22,9 @@ */ package com.oracle.graal.nodes.calc; -import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; /** * The {@code ShiftOp} class represents shift operations. @@ -37,7 +37,7 @@ * @param x the first input value * @param s the second input value */ - public ShiftNode(Kind kind, ValueNode x, ValueNode s) { - super(kind, x, s); + public ShiftNode(Stamp stamp, ValueNode x, ValueNode s) { + super(stamp, x, s); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,110 @@ +/* + * 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.nodes.calc; + +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.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * The {@code SignExtendNode} converts an integer to a wider integer using sign extension. + */ +public class SignExtendNode extends IntegerConvertNode implements Canonicalizable { + + public SignExtendNode(ValueNode input, int resultBits) { + super(StampTool.signExtend(input.stamp(), resultBits), input, resultBits); + } + + public static long signExtend(long value, int inputBits) { + if (inputBits < 64) { + if ((value >>> (inputBits - 1) & 1) == 1) { + return value | (-1L << inputBits); + } else { + return value & ~(-1L << inputBits); + } + } else { + return value; + } + } + + @Override + public Constant convert(Constant c) { + return Constant.forPrimitiveInt(getResultBits(), signExtend(c.asLong(), getInputBits())); + } + + @Override + public Constant reverse(Constant c) { + return Constant.forPrimitiveInt(getInputBits(), NarrowNode.narrow(c.asLong(), getInputBits())); + } + + @Override + public boolean isLossless() { + return true; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + ValueNode ret = canonicalConvert(); + if (ret != null) { + return ret; + } + + if (getInput() instanceof SignExtendNode) { + // sxxx -(sign-extend)-> ssss sxxx -(sign-extend)-> ssssssss sssssxxx + // ==> sxxx -(sign-extend)-> ssssssss sssssxxx + SignExtendNode other = (SignExtendNode) getInput(); + return graph().unique(new SignExtendNode(other.getInput(), getResultBits())); + } else if (getInput() instanceof ZeroExtendNode) { + ZeroExtendNode other = (ZeroExtendNode) getInput(); + if (other.getResultBits() > other.getInputBits()) { + // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx + // ==> sxxx -(zero-extend)-> 00000000 0000sxxx + return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits())); + } + } + + if (getInput().stamp() instanceof IntegerStamp) { + IntegerStamp inputStamp = (IntegerStamp) getInput().stamp(); + if ((inputStamp.upMask() & (1L << (getInputBits() - 1))) == 0L) { + // 0xxx -(sign-extend)-> 0000 0xxx + // ==> 0xxx -(zero-extend)-> 0000 0xxx + return graph().unique(new ZeroExtendNode(getInput(), getResultBits())); + } + } + + return this; + } + + @Override + public boolean inferStamp() { + return updateStamp(StampTool.signExtend(getInput().stamp(), getResultBits())); + } + + @Override + public void generate(ArithmeticLIRGenerator gen) { + gen.setResult(this, gen.emitSignExtend(gen.operand(getInput()), getInputBits(), getResultBits())); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,8 +33,16 @@ @NodeInfo(shortName = "|/|") public class UnsignedDivNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable { - public UnsignedDivNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + /** + * Used by {@code NodeIntrinsic} in {@code UnsignedMathSubstitutions}. + */ + @SuppressWarnings("unused") + private UnsignedDivNode(Kind kind, ValueNode x, ValueNode y) { + this(StampFactory.forKind(kind), x, y); + } + + public UnsignedDivNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -44,19 +52,14 @@ if (yConst == 0) { return this; // this will trap, cannot canonicalize } - if (kind() == Kind.Int) { - return ConstantNode.forInt(UnsignedMath.divide(x().asConstant().asInt(), (int) yConst), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(UnsignedMath.divide(x().asConstant().asLong(), yConst), graph()); - } + return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.divide(x().asConstant().asLong(), yConst), graph()); } else if (y().isConstant()) { long c = y().asConstant().asLong(); if (c == 1) { return x(); } if (CodeUtil.isPowerOf2(c)) { - return graph().unique(new UnsignedRightShiftNode(kind(), x(), ConstantNode.forInt(CodeUtil.log2(c), graph()))); + return graph().unique(new UnsignedRightShiftNode(stamp(), x(), ConstantNode.forInt(CodeUtil.log2(c), graph()))); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,8 +33,16 @@ @NodeInfo(shortName = "|%|") public class UnsignedRemNode extends FixedBinaryNode implements Canonicalizable, Lowerable, LIRLowerable { - public UnsignedRemNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + /** + * Used by {@code NodeIntrinsic} in {@code UnsignedMathSubstitutions}. + */ + @SuppressWarnings("unused") + private UnsignedRemNode(Kind kind, ValueNode x, ValueNode y) { + this(StampFactory.forKind(kind), x, y); + } + + public UnsignedRemNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -44,18 +52,13 @@ if (yConst == 0) { return this; // this will trap, cannot canonicalize } - if (kind() == Kind.Int) { - return ConstantNode.forInt(UnsignedMath.remainder(x().asConstant().asInt(), (int) yConst), graph()); - } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(UnsignedMath.remainder(x().asConstant().asLong(), yConst), graph()); - } + return ConstantNode.forIntegerStamp(stamp(), UnsignedMath.remainder(x().asConstant().asLong(), yConst), graph()); } else if (y().isConstant()) { long c = y().asConstant().asLong(); if (c == 1) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } else if (CodeUtil.isPowerOf2(c)) { - return graph().unique(new AndNode(kind(), x(), ConstantNode.forIntegerKind(kind(), c - 1, graph()))); + return graph().unique(new AndNode(stamp(), x(), ConstantNode.forIntegerStamp(stamp(), c - 1, graph()))); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,8 +32,8 @@ @NodeInfo(shortName = ">>>") public final class UnsignedRightShiftNode extends ShiftNode implements Canonicalizable { - public UnsignedRightShiftNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public UnsignedRightShiftNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -79,19 +79,19 @@ if (total != (total & mask)) { return ConstantNode.forIntegerKind(kind(), 0, graph()); } - return graph().unique(new UnsignedRightShiftNode(kind(), other.x(), ConstantNode.forInt(total, graph()))); + return graph().unique(new UnsignedRightShiftNode(stamp(), other.x(), ConstantNode.forInt(total, graph()))); } else if (other instanceof LeftShiftNode && otherAmount == amount) { if (kind() == Kind.Long) { - return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forLong(-1L >>> amount, graph()))); + return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forLong(-1L >>> amount, graph()))); } else { assert kind() == Kind.Int; - return graph().unique(new AndNode(kind(), other.x(), ConstantNode.forInt(-1 >>> amount, graph()))); + return graph().unique(new AndNode(stamp(), other.x(), ConstantNode.forInt(-1 >>> amount, graph()))); } } } } if (originalAmout != amount) { - return graph().unique(new UnsignedRightShiftNode(kind(), x(), ConstantNode.forInt(amount, graph()))); + return graph().unique(new UnsignedRightShiftNode(stamp(), x(), ConstantNode.forInt(amount, graph()))); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,8 +32,8 @@ @NodeInfo(shortName = "^") public final class XorNode extends BitLogicNode implements Canonicalizable { - public XorNode(Kind kind, ValueNode x, ValueNode y) { - super(kind, x, y); + public XorNode(Stamp stamp, ValueNode x, ValueNode y) { + super(stamp, x, y); } @Override @@ -44,35 +44,26 @@ @Override public Constant evalConst(Constant... inputs) { assert inputs.length == 2; - return Constant.forIntegerKind(kind(), inputs[0].asLong() ^ inputs[1].asLong(), null); + return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() ^ inputs[1].asLong()); } @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } if (x().isConstant() && !y().isConstant()) { - return graph().unique(new XorNode(kind(), y(), x())); + return graph().unique(new XorNode(stamp(), y(), x())); } if (x().isConstant()) { - return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph()); + return ConstantNode.forPrimitive(stamp(), evalConst(x().asConstant(), y().asConstant()), graph()); } else if (y().isConstant()) { - if (kind() == Kind.Int) { - int c = y().asConstant().asInt(); - if (c == 0) { - return x(); - } else if (c == -1) { - return graph().unique(new NotNode(x())); - } - } else { - assert kind() == Kind.Long; - long c = y().asConstant().asLong(); - if (c == 0) { - return x(); - } else if (c == -1) { - return graph().unique(new NotNode(x())); - } + long rawY = y().asConstant().asLong(); + long mask = IntegerStamp.defaultMask(PrimitiveStamp.getBits(stamp())); + if ((rawY & mask) == 0) { + return x(); + } else if ((rawY & mask) == mask) { + return graph().unique(new NotNode(x())); } return BinaryNode.reassociate(this, ValueNode.isConstantPredicate()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,90 @@ +/* + * 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.nodes.calc; + +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.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * The {@code ZeroExtendNode} converts an integer to a wider integer using zero extension. + */ +public class ZeroExtendNode extends IntegerConvertNode implements Canonicalizable { + + public ZeroExtendNode(ValueNode input, int resultBits) { + super(StampTool.zeroExtend(input.stamp(), resultBits), input, resultBits); + } + + public static long zeroExtend(long value, int inputBits) { + if (inputBits < 64) { + return value & ~(-1L << inputBits); + } else { + return value; + } + } + + @Override + public Constant convert(Constant c) { + return Constant.forPrimitiveInt(getResultBits(), zeroExtend(c.asLong(), getInputBits())); + } + + @Override + public Constant reverse(Constant c) { + return Constant.forPrimitiveInt(getInputBits(), NarrowNode.narrow(c.asLong(), getInputBits())); + } + + @Override + public boolean isLossless() { + return true; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + ValueNode ret = canonicalConvert(); + if (ret != null) { + return ret; + } + + if (getInput() instanceof ZeroExtendNode) { + // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx + // ==> xxxx -(zero-extend)-> 00000000 0000xxxx + ZeroExtendNode other = (ZeroExtendNode) getInput(); + return graph().unique(new ZeroExtendNode(other.getInput(), getResultBits())); + } + + return this; + } + + @Override + public boolean inferStamp() { + return updateStamp(StampTool.zeroExtend(getInput().stamp(), getResultBits())); + } + + @Override + public void generate(ArithmeticLIRGenerator gen) { + gen.setResult(this, gen.emitZeroExtend(gen.operand(getInput()), getInputBits(), getResultBits())); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -51,7 +51,11 @@ } public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, List arguments) { - super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); + this(foreignCalls, descriptor, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())), arguments); + } + + public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List arguments) { + super(stamp); this.arguments = new NodeInputList<>(this, arguments); this.descriptor = descriptor; this.foreignCalls = foreignCalls; diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -71,29 +71,39 @@ 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()) { - if (location.getLocationIdentity() == LocationIdentity.FINAL_LOCATION && location instanceof ConstantLocationNode) { - long displacement = ((ConstantLocationNode) location).getDisplacement(); - Kind kind = location.getValueKind(); - if (object.kind() == Kind.Object) { - Object base = object.asConstant().asObject(); - if (base != null) { - Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, base, displacement, compressible); - if (constant != null) { - return ConstantNode.forConstant(constant, metaAccess, read.graph()); + if (tool.canonicalizeReads()) { + if (metaAccess != null && object != null && object.isConstant()) { + if ((location.getLocationIdentity() == LocationIdentity.FINAL_LOCATION || location.getLocationIdentity() == LocationIdentity.ARRAY_LENGTH_LOCATION) & + location instanceof ConstantLocationNode) { + long displacement = ((ConstantLocationNode) location).getDisplacement(); + Kind kind = location.getValueKind(); + if (object.kind() == Kind.Object) { + Object base = object.asConstant().asObject(); + if (base != null) { + Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, base, displacement, compressible); + if (constant != null) { + return ConstantNode.forConstant(constant, metaAccess, read.graph()); + } + } + } else if (object.kind().isNumericInteger()) { + long base = object.asConstant().asLong(); + if (base != 0L) { + Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, null, base + displacement, compressible); + if (constant != null) { + return ConstantNode.forConstant(constant, metaAccess, read.graph()); + } } } - } else if (object.kind().isNumericInteger()) { - long base = object.asConstant().asLong(); - if (base != 0L) { - Constant constant = tool.getConstantReflection().readUnsafeConstant(kind, null, base + displacement, compressible); - if (constant != null) { - return ConstantNode.forConstant(constant, metaAccess, read.graph()); - } - } + } + } + if (location.getLocationIdentity() == LocationIdentity.ARRAY_LENGTH_LOCATION && object instanceof ArrayLengthProvider) { + ValueNode length = ((ArrayLengthProvider) object).length(); + if (length != null) { + // TODO Does this need a PiCastNode to the positive range? + return length; } } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,11 +33,34 @@ * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and * throws a {@link BailoutException} instead during graph building. */ -public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint { +public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode { + @Input private FrameState deoptState; @Input private ValueNode object; @Input private MonitorIdNode monitorId; + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public FrameState getDeoptimizationState() { + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + updateUsages(deoptState, f); + deoptState = f; + } + + @Override + public FrameState getState() { + assert deoptState == null || stateAfter() == null; + return deoptState == null ? stateAfter() : deoptState; + } + public ValueNode object() { return object; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -76,7 +76,7 @@ if (ObjectStamp.isObjectAlwaysNull(object())) { return object(); } - if (hub.isConstant() && hub.kind() == Kind.Object && hub.asConstant().asObject() instanceof Class) { + if (hub.isConstant() && hub.asConstant().getKind() == Kind.Object && hub.asConstant().asObject() instanceof Class) { Class clazz = (Class) hub.asConstant().asObject(); ResolvedJavaType t = tool.getMetaAccess().lookupJavaType(clazz); return graph().add(new CheckCastNode(t, object(), null, forStoreCheck)); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -64,7 +64,7 @@ public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue) { super(StampFactory.forKind(Kind.Boolean.getStackKind())); - assert expected.kind() == newValue.kind(); + assert expected.stamp().isCompatible(newValue.stamp()); this.object = object; this.offset = offset; this.expected = expected; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -60,7 +60,7 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (usages().isEmpty() && (isStatic() || ObjectStamp.isObjectNonNull(object().stamp()))) { + if (usages().isEmpty() && !isVolatile() && (isStatic() || ObjectStamp.isObjectNonNull(object().stamp()))) { return null; } MetaAccessProvider metaAccess = tool.getMetaAccess(); @@ -74,6 +74,9 @@ return phi; } } + if (!isStatic() && object().isNullConstant()) { + return graph().add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.NullCheckException)); + } return this; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -160,7 +160,7 @@ if (targetMethod() == null) { return "??Invalid!"; } - return targetMethod().getName(); + return MetaUtil.format("%h.%n", targetMethod()); } public static MethodCallTargetNode find(StructuredGraph graph, ResolvedJavaMethod method) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.java; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @@ -30,7 +31,7 @@ /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. */ -public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single { +public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single { /** * Creates a new MonitorEnterNode. diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -58,7 +58,7 @@ @Override public void simplify(SimplifierTool tool) { - if (escapedReturnValue != null && stateAfter().bci != FrameState.AFTER_BCI) { + if (escapedReturnValue != null && stateAfter() != null && stateAfter().bci != FrameState.AFTER_BCI) { ValueNode returnValue = escapedReturnValue; setEscapedReturnValue(null); tool.removeIfUnused(returnValue); diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,8 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; +import com.oracle.graal.nodes.type.*; /** * This interface can be used to generate LIR for arithmetic operations (@see @@ -35,6 +37,8 @@ Value setResult(ValueNode x, Value operand); + PlatformKind getPlatformKind(Stamp stamp); + Value emitNegate(Value input); Value emitAdd(Value a, Value b); @@ -65,9 +69,15 @@ Value emitUShr(Value a, Value b); - Value emitConvert(Kind from, Kind to, Value inputVal); + Value emitFloatConvert(FloatConvert op, Value inputVal); + + Value emitReinterpret(PlatformKind to, Value inputVal); - Value emitReinterpret(Kind to, Value inputVal); + Value emitNarrow(Value inputVal, int bits); + + Value emitSignExtend(Value inputVal, int fromBits, int toBits); + + Value emitZeroExtend(Value inputVal, int fromBits, int toBits); Value emitMathAbs(Value input); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRTypeTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRTypeTool.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,37 @@ +/* + * 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.nodes.spi; + +import com.oracle.graal.api.meta.*; + +/** + * This interface can be used to access platform and VM specific kinds. + */ +public interface LIRTypeTool { + + PlatformKind getIntegerKind(int bits, boolean unsigned); + + PlatformKind getFloatingKind(int bits); + + PlatformKind getObjectKind(); +} diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/FloatStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/FloatStamp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/FloatStamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -23,20 +23,21 @@ package com.oracle.graal.nodes.type; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.spi.*; -public class FloatStamp extends Stamp { +public class FloatStamp extends PrimitiveStamp { private final double lowerBound; private final double upperBound; private final boolean nonNaN; - protected FloatStamp(Kind kind) { - this(kind, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false); - assert kind == Kind.Float || kind == Kind.Double; + protected FloatStamp(int bits) { + this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false); } - protected FloatStamp(Kind kind, double lowerBound, double upperBound, boolean nonNaN) { - super(kind); + protected FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) { + super(bits); assert (!nonNaN && Double.isNaN(lowerBound) && Double.isNaN(upperBound)) || lowerBound <= upperBound; this.lowerBound = lowerBound; this.upperBound = upperBound; @@ -44,8 +45,34 @@ } @Override + public Stamp unrestricted() { + return new FloatStamp(getBits()); + } + + @Override + public Kind getStackKind() { + if (getBits() > 32) { + return Kind.Double; + } else { + return Kind.Float; + } + } + + @Override + public PlatformKind getPlatformKind(LIRTypeTool tool) { + return tool.getFloatingKind(getBits()); + } + + @Override public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { - return metaAccess.lookupJavaType(kind().toJavaClass()); + switch (getBits()) { + case 32: + return metaAccess.lookupJavaType(Float.TYPE); + case 64: + return metaAccess.lookupJavaType(Double.TYPE); + default: + throw GraalInternalError.shouldNotReachHere(); + } } /** @@ -81,7 +108,8 @@ @Override public String toString() { StringBuilder str = new StringBuilder(); - str.append(kind().getTypeChar()); + str.append('f'); + str.append(getBits()); str.append(nonNaN ? "!" : ""); if (lowerBound == upperBound) { str.append(" [").append(lowerBound).append(']'); @@ -103,7 +131,7 @@ return StampFactory.illegal(Kind.Illegal); } FloatStamp other = (FloatStamp) otherStamp; - assert kind() == other.kind(); + assert getBits() == other.getBits(); double meetUpperBound = Math.max(upperBound, other.upperBound); double meetLowerBound = Math.min(lowerBound, other.lowerBound); boolean meetNonNaN = nonNaN && other.nonNaN; @@ -112,7 +140,7 @@ } else if (meetLowerBound == other.lowerBound && meetUpperBound == other.upperBound && meetNonNaN == other.nonNaN) { return other; } else { - return new FloatStamp(kind(), meetLowerBound, meetUpperBound, meetNonNaN); + return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN); } } @@ -128,7 +156,7 @@ return StampFactory.illegal(Kind.Illegal); } FloatStamp other = (FloatStamp) otherStamp; - assert kind() == other.kind(); + assert getBits() == other.getBits(); double joinUpperBound = Math.min(upperBound, other.upperBound); double joinLowerBound = Math.max(lowerBound, other.lowerBound); boolean joinNonNaN = nonNaN || other.nonNaN; @@ -137,9 +165,9 @@ } else if (joinLowerBound == other.lowerBound && joinUpperBound == other.upperBound && joinNonNaN == other.nonNaN) { return other; } else if (joinLowerBound > joinUpperBound) { - return StampFactory.illegal(kind()); + return illegal(); } else { - return new FloatStamp(kind(), joinLowerBound, joinUpperBound, joinNonNaN); + return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN); } } @@ -148,7 +176,7 @@ final int prime = 31; int result = 1; long temp; - result = prime * result + kind().hashCode(); + result = prime * result + super.hashCode(); temp = Double.doubleToLongBits(lowerBound); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + (nonNaN ? 1231 : 1237); @@ -158,17 +186,26 @@ } @Override + public boolean isCompatible(Stamp stamp) { + if (this == stamp) { + return true; + } + if (stamp instanceof FloatStamp) { + FloatStamp other = (FloatStamp) stamp; + return getBits() == other.getBits(); + } + return false; + } + + @Override public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj == null || getClass() != obj.getClass()) { + if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) { return false; } FloatStamp other = (FloatStamp) obj; - if (kind() != other.kind()) { - return false; - } if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) { return false; } @@ -184,10 +221,10 @@ @Override public Constant asConstant() { if (nonNaN && lowerBound == upperBound) { - switch (kind()) { - case Float: + switch (getBits()) { + case 32: return Constant.forFloat((float) lowerBound); - case Double: + case 64: return Constant.forDouble(lowerBound); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -23,17 +23,18 @@ package com.oracle.graal.nodes.type; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.spi.*; public final class GenericStamp extends Stamp { public enum GenericStampType { - Dependency, Extension, Condition, Void + Dependency, Extension, Condition } private final GenericStampType type; protected GenericStamp(GenericStampType type) { - super(type == GenericStampType.Void ? Kind.Void : Kind.Illegal); this.type = type; } @@ -42,8 +43,23 @@ } @Override + public Stamp unrestricted() { + return this; + } + + @Override + public Kind getStackKind() { + return Kind.Illegal; + } + + @Override + public PlatformKind getPlatformKind(LIRTypeTool tool) { + throw GraalInternalError.shouldNotReachHere(type + " stamp has no value"); + } + + @Override public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { - return metaAccess.lookupJavaType(kind().toJavaClass()); + throw GraalInternalError.shouldNotReachHere(type + " stamp has not Java type"); } @Override @@ -79,6 +95,18 @@ } @Override + public boolean isCompatible(Stamp stamp) { + if (this == stamp) { + return true; + } + if (stamp instanceof GenericStamp) { + GenericStamp other = (GenericStamp) stamp; + return type == other.type; + } + return false; + } + + @Override public int hashCode() { return 31 + ((type == null) ? 0 : type.hashCode()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IllegalStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IllegalStamp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IllegalStamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -23,15 +23,43 @@ package com.oracle.graal.nodes.type; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.spi.*; /** * This stamp represents the illegal type. Values with this type can not exist at run time. - * */ -public final class IllegalStamp extends Stamp { +public final class IllegalStamp extends PrimitiveStamp { + + private final Kind kind; public IllegalStamp(Kind kind) { - super(kind); + super(0); + this.kind = kind; + } + + public Kind kind() { + return kind; + } + + @Override + public Kind getStackKind() { + return kind; + } + + @Override + public PlatformKind getPlatformKind(LIRTypeTool tool) { + throw GraalInternalError.shouldNotReachHere("illegal stamp should not reach backend"); + } + + @Override + public Stamp unrestricted() { + return this; + } + + @Override + public Stamp illegal() { + return this; } @Override @@ -50,6 +78,18 @@ } @Override + public boolean isCompatible(Stamp stamp) { + if (this == stamp) { + return true; + } + if (stamp instanceof IllegalStamp) { + IllegalStamp other = (IllegalStamp) stamp; + return kind == other.kind; + } + return false; + } + + @Override public String toString() { return "ILLEGAL"; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -27,42 +27,89 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; /** * Describes the possible values of a {@link ValueNode} that produces an int or long result. * - * The description consists of (inclusive, signed) lower and upper bounds and up (may be set) and - * down (always set) bit-masks. + * The description consists of (inclusive) lower and upper bounds and up (may be set) and down + * (always set) bit-masks. */ -public class IntegerStamp extends Stamp { +public class IntegerStamp extends PrimitiveStamp { + + private final boolean unsigned; private final long lowerBound; private final long upperBound; private final long downMask; private final long upMask; - public IntegerStamp(Kind kind) { - this(kind.getStackKind(), kind.getMinValue(), kind.getMaxValue(), 0, defaultMask(isUnsignedKind(kind) ? kind : kind.getStackKind())); - } - - public IntegerStamp(Kind kind, long lowerBound, long upperBound, long downMask, long upMask) { - super(kind); + public IntegerStamp(int bits, boolean unsigned, long lowerBound, long upperBound, long downMask, long upMask) { + super(bits); + this.unsigned = unsigned; this.lowerBound = lowerBound; this.upperBound = upperBound; this.downMask = downMask; this.upMask = upMask; assert lowerBound <= upperBound : this; - assert lowerBound >= kind.getMinValue() : this; - assert upperBound <= kind.getMaxValue() : this; - assert (downMask & defaultMask(kind)) == downMask : this; - assert (upMask & defaultMask(kind)) == upMask : this; + assert lowerBound >= defaultMinValue(bits, unsigned) : this; + assert upperBound <= defaultMaxValue(bits, unsigned) : this; + assert (downMask & defaultMask(bits)) == downMask : this; + assert (upMask & defaultMask(bits)) == upMask : this; assert (lowerBound & downMask) == downMask : this; assert (upperBound & downMask) == downMask : this; } @Override + public Stamp unrestricted() { + return new IntegerStamp(getBits(), unsigned, defaultMinValue(getBits(), unsigned), defaultMaxValue(getBits(), unsigned), 0, defaultMask(getBits())); + } + + @Override + public Kind getStackKind() { + if (getBits() > 32) { + return Kind.Long; + } else { + return Kind.Int; + } + } + + @Override + public PlatformKind getPlatformKind(LIRTypeTool tool) { + return tool.getIntegerKind(getBits(), unsigned); + } + + @Override public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { - return metaAccess.lookupJavaType(kind().toJavaClass()); + switch (getBits()) { + case 1: + assert unsigned; + return metaAccess.lookupJavaType(Boolean.TYPE); + case 8: + assert !unsigned; + return metaAccess.lookupJavaType(Byte.TYPE); + case 16: + if (unsigned) { + return metaAccess.lookupJavaType(Character.TYPE); + } else { + return metaAccess.lookupJavaType(Short.TYPE); + } + case 32: + assert !unsigned; + return metaAccess.lookupJavaType(Integer.TYPE); + case 64: + assert !unsigned; + return metaAccess.lookupJavaType(Long.TYPE); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + /** + * Check whether the value described by this stamp is unsigned. + */ + public boolean isUnsigned() { + return unsigned; } /** @@ -94,11 +141,11 @@ } public boolean isUnrestricted() { - return lowerBound == kind().getMinValue() && upperBound == kind().getMaxValue() && downMask == 0 && upMask == defaultMask(kind()); + return lowerBound == defaultMinValue(getBits(), unsigned) && upperBound == defaultMaxValue(getBits(), unsigned) && downMask == 0 && upMask == defaultMask(getBits()); } public boolean contains(long value) { - return value >= lowerBound && value <= upperBound && (value & downMask) == downMask && (value & upMask) == (value & defaultMask(kind())); + return value >= lowerBound && value <= upperBound && (value & downMask) == downMask && (value & upMask) == (value & defaultMask(getBits())); } public boolean isPositive() { @@ -128,17 +175,18 @@ @Override public String toString() { StringBuilder str = new StringBuilder(); - str.append(kind().getTypeChar()); + str.append(unsigned ? 'u' : 'i'); + str.append(getBits()); if (lowerBound == upperBound) { str.append(" [").append(lowerBound).append(']'); - } else if (lowerBound != kind().getMinValue() || upperBound != kind().getMaxValue()) { + } else if (lowerBound != defaultMinValue(getBits(), unsigned) || upperBound != defaultMaxValue(getBits(), unsigned)) { str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']'); } if (downMask != 0) { str.append(" \u21ca"); new Formatter(str).format("%016x", downMask); } - if (upMask != defaultMask(kind())) { + if (upMask != defaultMask(getBits())) { str.append(" \u21c8"); new Formatter(str).format("%016x", upMask); } @@ -146,15 +194,15 @@ } private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) { - assert kind() == other.kind(); + assert getBits() == other.getBits() && unsigned == other.unsigned; if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0) { - return StampFactory.illegal(kind()); + return illegal(); } else if (newLowerBound == lowerBound && newUpperBound == upperBound && newDownMask == downMask && newUpMask == upMask) { return this; } else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) { return other; } else { - return new IntegerStamp(kind(), newLowerBound, newUpperBound, newDownMask, newUpMask); + return new IntegerStamp(getBits(), unsigned, newLowerBound, newUpperBound, newDownMask, newUpMask); } } @@ -191,10 +239,22 @@ } @Override + public boolean isCompatible(Stamp stamp) { + if (this == stamp) { + return true; + } + if (stamp instanceof IntegerStamp) { + IntegerStamp other = (IntegerStamp) stamp; + return getBits() == other.getBits() && unsigned == other.unsigned; + } + return false; + } + + @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + kind().hashCode(); + result = prime * result + super.hashCode(); result = prime * result + (int) (lowerBound ^ (lowerBound >>> 32)); result = prime * result + (int) (upperBound ^ (upperBound >>> 32)); result = prime * result + (int) (downMask ^ (downMask >>> 32)); @@ -207,41 +267,43 @@ if (this == obj) { return true; } - if (obj == null || getClass() != obj.getClass()) { + if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) { return false; } IntegerStamp other = (IntegerStamp) obj; - if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask || kind() != other.kind()) { + if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask) { return false; } return true; } - public static long defaultMask(Kind kind) { - switch (kind) { - case Boolean: - return 0x01L; - case Byte: - return 0xffL; - case Char: - return 0xffffL; - case Short: - return 0xffffL; - case Int: - return 0xffffffffL; - case Long: - return 0xffffffffffffffffL; - default: - throw GraalInternalError.shouldNotReachHere(); + public static long defaultMask(int bits) { + assert 0 < bits && bits <= 64; + if (bits == 64) { + return 0xffffffffffffffffL; + } else { + return (1L << bits) - 1; } } - public static long upMaskFor(Kind kind, long lowerBound, long upperBound) { + public static long defaultMinValue(int bits, boolean unsigned) { + if (unsigned) { + return 0; + } else { + return -1L << (bits - 1); + } + } + + public static long defaultMaxValue(int bits, boolean unsigned) { + return defaultMask(unsigned ? bits : bits - 1); + } + + public static long upMaskFor(int bits, long lowerBound, long upperBound) { long mask = lowerBound | upperBound; if (mask == 0) { return 0; } else { - return ((-1L) >>> Long.numberOfLeadingZeros(mask)) & defaultMask(kind); + return ((-1L) >>> Long.numberOfLeadingZeros(mask)) & defaultMask(bits); } } @@ -259,12 +321,23 @@ @Override public Constant asConstant() { if (lowerBound == upperBound) { - return Constant.forIntegerKind(kind(), lowerBound, null); + switch (getBits()) { + case 1: + return Constant.forBoolean(lowerBound != 0); + case 8: + return Constant.forByte((byte) lowerBound); + case 16: + if (unsigned) { + return Constant.forChar((char) lowerBound); + } else { + return Constant.forShort((short) lowerBound); + } + case 32: + return Constant.forInt((int) lowerBound); + case 64: + return Constant.forLong(lowerBound); + } } return null; } - - private static boolean isUnsignedKind(Kind kind) { - return kind == Kind.Char; - } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; public class ObjectStamp extends Stamp { @@ -36,7 +37,6 @@ private final boolean alwaysNull; public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) { - super(Kind.Object); assert !exactType || (type != null && (isConcreteType(type))); this.type = type; this.exactType = exactType; @@ -45,6 +45,21 @@ } @Override + public Stamp unrestricted() { + return StampFactory.object(); + } + + @Override + public Kind getStackKind() { + return Kind.Object; + } + + @Override + public PlatformKind getPlatformKind(LIRTypeTool tool) { + return tool.getObjectKind(); + } + + @Override public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { if (type != null) { return type; @@ -71,7 +86,7 @@ @Override public String toString() { StringBuilder str = new StringBuilder(); - str.append(kind().getTypeChar()); + str.append('a'); str.append(nonNull ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.getName()).append(alwaysNull ? " NULL" : ""); return str.toString(); } @@ -123,6 +138,20 @@ return join0(otherStamp, false); } + @Override + public boolean isCompatible(Stamp other) { + if (this == other) { + return true; + } + if (other instanceof ObjectStamp) { + return true; + } + if (other instanceof IllegalStamp) { + return ((IllegalStamp) other).kind() == Kind.Object; + } + return false; + } + /** * Returns the stamp representing the type of this stamp after a cast to the type represented by * the {@code to} stamp. While this is very similar to a {@link #join} operation, in the case @@ -294,4 +323,14 @@ } return false; } + + public static boolean isObject(Stamp stamp) { + if (stamp instanceof ObjectStamp) { + return true; + } else if (stamp instanceof IllegalStamp) { + return ((IllegalStamp) stamp).kind() == Kind.Object; + } else { + return false; + } + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/PrimitiveStamp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/PrimitiveStamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,72 @@ +/* + * 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.nodes.type; + +import com.oracle.graal.nodes.*; + +/** + * Describes the possible values of a {@link ValueNode} that produces a primitive value as result. + */ +public abstract class PrimitiveStamp extends Stamp { + + private final int bits; + + protected PrimitiveStamp(int bits) { + this.bits = bits; + } + + /** + * The width in bits of the value described by this stamp. + */ + public int getBits() { + return bits; + } + + public static int getBits(Stamp stamp) { + if (stamp instanceof PrimitiveStamp) { + return ((PrimitiveStamp) stamp).getBits(); + } else { + return 0; + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + bits; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof PrimitiveStamp) { + PrimitiveStamp other = (PrimitiveStamp) obj; + return bits == other.bits; + } + return false; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/Stamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/Stamp.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/Stamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -24,20 +24,14 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; /** * A stamp is the basis for a type system over the nodes in a graph. */ public abstract class Stamp { - private final Kind kind; - - protected Stamp(Kind kind) { - this.kind = kind; - } - - public Kind kind() { - return kind; + protected Stamp() { } /** @@ -51,6 +45,19 @@ } /** + * Gets a Java {@link Kind} that can be used to store a value of this stamp on the Java bytecode + * stack. Returns {@link Kind#Illegal} if a value of this stamp can not be stored on the + * bytecode stack. + */ + public abstract Kind getStackKind(); + + /** + * Gets a platform dependend {@link PlatformKind} that can be used to store a value of this + * stamp. + */ + public abstract PlatformKind getPlatformKind(LIRTypeTool tool); + + /** * Returns the union of this stamp and the given stamp. Typically used to create stamps for * {@link PhiNode}s. * @@ -68,6 +75,23 @@ public abstract Stamp join(Stamp other); /** + * Returns a stamp of the same kind, but allowing the full value range of the kind. + */ + public abstract Stamp unrestricted(); + + /** + * Returns an illegal stamp that has the same kind, but no valid values. + */ + public Stamp illegal() { + return StampFactory.illegal(getStackKind()); + } + + /** + * Test whether two stamps have the same base type. + */ + public abstract boolean isCompatible(Stamp other); + + /** * If this stamp represents a single value, the methods returns this single value. It returns * null otherwise. * diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Wed Mar 05 19:40:15 2014 -0800 @@ -38,7 +38,6 @@ private static final Stamp dependencyStamp = new GenericStamp(GenericStampType.Dependency); private static final Stamp extensionStamp = new GenericStamp(GenericStampType.Extension); private static final Stamp conditionStamp = new GenericStamp(GenericStampType.Condition); - private static final Stamp voidStamp = new GenericStamp(GenericStampType.Void); private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false); private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); @@ -46,31 +45,53 @@ stampCache[kind.ordinal()] = stamp; } + private static void setIntCache(Kind kind) { + int bits = kind.getStackKind().getBitCount(); + long mask; + if (kind.isUnsigned()) { + mask = IntegerStamp.defaultMask(kind.getBitCount()); + } else { + mask = IntegerStamp.defaultMask(bits); + } + setCache(kind, new IntegerStamp(bits, false, kind.getMinValue(), kind.getMaxValue(), 0, mask)); + } + + private static void setFloatCache(Kind kind) { + setCache(kind, new FloatStamp(kind.getBitCount())); + } + static { - setCache(Kind.Boolean, new IntegerStamp(Kind.Boolean)); - setCache(Kind.Byte, new IntegerStamp(Kind.Byte)); - setCache(Kind.Short, new IntegerStamp(Kind.Short)); - setCache(Kind.Char, new IntegerStamp(Kind.Char)); - setCache(Kind.Int, new IntegerStamp(Kind.Int)); - setCache(Kind.Long, new IntegerStamp(Kind.Long)); + setIntCache(Kind.Boolean); + setIntCache(Kind.Byte); + setIntCache(Kind.Short); + setIntCache(Kind.Char); + setIntCache(Kind.Int); + setIntCache(Kind.Long); - setCache(Kind.Float, new FloatStamp(Kind.Float)); - setCache(Kind.Double, new FloatStamp(Kind.Double)); + setFloatCache(Kind.Float); + setFloatCache(Kind.Double); setCache(Kind.Object, objectStamp); - setCache(Kind.Void, voidStamp); + setCache(Kind.Void, VoidStamp.getInstance()); for (Kind k : Kind.values()) { illegalStampCache[k.ordinal()] = new IllegalStamp(k); } } + /** + * Return a stamp for a Java kind, as it would be represented on the bytecode stack. + */ public static Stamp forKind(Kind kind) { assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")"; return stampCache[kind.ordinal()]; } + /** + * Return the stamp for the {@code void} type. This will return a singleton instance than can be + * compared using {@code ==}. + */ public static Stamp forVoid() { - return voidStamp; + return VoidStamp.getInstance(); } /** @@ -106,13 +127,21 @@ } public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound, long downMask, long upMask) { - return new IntegerStamp(kind, lowerBound, upperBound, downMask, upMask); + return new IntegerStamp(kind.getBitCount(), kind.isUnsigned(), lowerBound, upperBound, downMask, upMask); } public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound) { - long defaultMask = IntegerStamp.defaultMask(kind); + return forInteger(kind.getBitCount(), kind.isUnsigned(), lowerBound, upperBound); + } + + public static IntegerStamp forInteger(int bits, boolean unsigned) { + return new IntegerStamp(bits, unsigned, IntegerStamp.defaultMinValue(bits, unsigned), IntegerStamp.defaultMaxValue(bits, unsigned), 0, IntegerStamp.defaultMask(bits)); + } + + public static IntegerStamp forInteger(int bits, boolean unsigned, long lowerBound, long upperBound) { + long defaultMask = IntegerStamp.defaultMask(bits); if (lowerBound == upperBound) { - return new IntegerStamp(kind, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask); + return new IntegerStamp(bits, unsigned, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask); } final long downMask; final long upMask; @@ -136,11 +165,12 @@ downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes); } } - return forInteger(kind, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask); + return new IntegerStamp(bits, unsigned, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask); } public static FloatStamp forFloat(Kind kind, double lowerBound, double upperBound, boolean nonNaN) { - return new FloatStamp(kind, lowerBound, upperBound, nonNaN); + assert kind.isNumericFloat(); + return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN); } public static Stamp forConstant(Constant value) { @@ -152,7 +182,7 @@ case Short: case Int: case Long: - long mask = value.asLong() & IntegerStamp.defaultMask(kind); + long mask = value.asLong() & IntegerStamp.defaultMask(kind.getBitCount()); return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask); case Float: return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Wed Mar 05 19:40:15 2014 -0800 @@ -25,47 +25,55 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.calc.*; /** * Helper class that is used to keep all stamp-related operations in one place. */ public class StampTool { - public static Kind joinKind(Kind a, Kind b) { + private static Kind joinKind(Kind a, Kind b) { if (a == b) { return a; } return Kind.Illegal; } - public static Kind joinKind(Stamp a, Stamp b) { - return joinKind(a.kind(), b.kind()); + /** + * Create an {@link IllegalStamp} from two incompatible input stamps, joining the kind of the + * input stamps if possible. + */ + private static Stamp joinIllegal(Stamp a, Stamp b) { + IllegalStamp ia = (IllegalStamp) a.illegal(); + IllegalStamp ib = (IllegalStamp) b.illegal(); + return StampFactory.illegal(joinKind(ia.kind(), ib.kind())); } public static Stamp negate(Stamp stamp) { - Kind kind = stamp.kind(); if (stamp instanceof IntegerStamp) { IntegerStamp integerStamp = (IntegerStamp) stamp; - if (integerStamp.lowerBound() != kind.getMinValue()) { + int bits = integerStamp.getBits(); + if (integerStamp.lowerBound() != IntegerStamp.defaultMinValue(bits, false)) { // TODO(ls) check if the mask calculation is correct... - return StampFactory.forInteger(kind, -integerStamp.upperBound(), -integerStamp.lowerBound()); + return StampFactory.forInteger(bits, false, -integerStamp.upperBound(), -integerStamp.lowerBound()); } } else if (stamp instanceof FloatStamp) { FloatStamp floatStamp = (FloatStamp) stamp; - return new FloatStamp(kind, -floatStamp.upperBound(), -floatStamp.lowerBound(), floatStamp.isNonNaN()); + return new FloatStamp(floatStamp.getBits(), -floatStamp.upperBound(), -floatStamp.lowerBound(), floatStamp.isNonNaN()); } - return StampFactory.forKind(kind); + return stamp.unrestricted(); } public static Stamp not(Stamp stamp) { if (stamp instanceof IntegerStamp) { IntegerStamp integerStamp = (IntegerStamp) stamp; - assert stamp.kind() == Kind.Int || stamp.kind() == Kind.Long; - long defaultMask = IntegerStamp.defaultMask(stamp.kind()); - return new IntegerStamp(stamp.kind(), ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask); + int bits = integerStamp.getBits(); + long defaultMask = IntegerStamp.defaultMask(bits); + return new IntegerStamp(bits, integerStamp.isUnsigned(), ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & + defaultMask); } - return StampFactory.forKind(stamp.kind()); + return stamp.unrestricted(); } public static Stamp meet(Collection values) { @@ -85,7 +93,7 @@ if (stamp1 instanceof IntegerStamp && stamp2 instanceof IntegerStamp) { return add((IntegerStamp) stamp1, (IntegerStamp) stamp2); } - return StampFactory.illegal(joinKind(stamp1, stamp2)); + return joinIllegal(stamp1, stamp2); } private static long carryBits(long x, long y) { @@ -100,47 +108,56 @@ if (stamp1 instanceof IntegerStamp && stamp2 instanceof IntegerStamp) { return div((IntegerStamp) stamp1, (IntegerStamp) stamp2); } - return StampFactory.illegal(joinKind(stamp1, stamp2)); + return joinIllegal(stamp1, stamp2); } public static Stamp div(IntegerStamp stamp1, IntegerStamp stamp2) { - assert stamp1.kind() == stamp2.kind(); - Kind kind = stamp1.kind(); + assert stamp1.getBits() == stamp2.getBits() && stamp1.isUnsigned() == stamp2.isUnsigned(); if (stamp2.isStrictlyPositive()) { long lowerBound = stamp1.lowerBound() / stamp2.lowerBound(); long upperBound = stamp1.upperBound() / stamp2.lowerBound(); - return StampFactory.forInteger(kind, lowerBound, upperBound); + return StampFactory.forInteger(stamp1.getBits(), stamp1.isUnsigned(), lowerBound, upperBound); } - return StampFactory.forKind(kind); + return stamp1.unrestricted(); } - private static boolean addOverflowsPositively(long x, long y, Kind kind) { + private static boolean addOverflowsPositively(long x, long y, int bits, boolean unsigned) { long result = x + y; - if (kind == Kind.Long) { - return (~x & ~y & result) < 0; + if (bits == 64) { + if (unsigned) { + return ((x | y) & ~result) < 0; + } else { + return (~x & ~y & result) < 0; + } } else { - assert kind == Kind.Int; - return result > Integer.MAX_VALUE; + return result > IntegerStamp.defaultMaxValue(bits, unsigned); } } - private static boolean addOverflowsNegatively(long x, long y, Kind kind) { + private static boolean addOverflowsNegatively(long x, long y, int bits, boolean unsigned) { + if (unsigned) { + return false; + } + long result = x + y; - if (kind == Kind.Long) { + if (bits == 64) { return (x & y & ~result) < 0; } else { - assert kind == Kind.Int; - return result < Integer.MIN_VALUE; + return result < IntegerStamp.defaultMinValue(bits, unsigned); } } public static IntegerStamp add(IntegerStamp stamp1, IntegerStamp stamp2) { - if (stamp1.isUnrestricted() || stamp2.isUnrestricted()) { - return (IntegerStamp) StampFactory.forKind(stamp1.kind()); + int bits = stamp1.getBits(); + boolean unsigned = stamp1.isUnsigned(); + assert bits == stamp2.getBits() && unsigned == stamp2.isUnsigned(); + + if (stamp1.isUnrestricted()) { + return stamp1; + } else if (stamp2.isUnrestricted()) { + return stamp2; } - Kind kind = stamp1.kind(); - assert stamp1.kind() == stamp2.kind(); - long defaultMask = IntegerStamp.defaultMask(kind); + long defaultMask = IntegerStamp.defaultMask(bits); long variableBits = (stamp1.downMask() ^ stamp1.upMask()) | (stamp2.downMask() ^ stamp2.upMask()); long variableBitsWithCarry = variableBits | (carryBits(stamp1.downMask(), stamp2.downMask()) ^ carryBits(stamp1.upMask(), stamp2.upMask())); long newDownMask = (stamp1.downMask() + stamp2.downMask()) & ~variableBitsWithCarry; @@ -151,102 +168,107 @@ long lowerBound; long upperBound; - boolean lowerOverflowsPositively = addOverflowsPositively(stamp1.lowerBound(), stamp2.lowerBound(), kind); - boolean upperOverflowsPositively = addOverflowsPositively(stamp1.upperBound(), stamp2.upperBound(), kind); - boolean lowerOverflowsNegatively = addOverflowsNegatively(stamp1.lowerBound(), stamp2.lowerBound(), kind); - boolean upperOverflowsNegatively = addOverflowsNegatively(stamp1.upperBound(), stamp2.upperBound(), kind); + boolean lowerOverflowsPositively = addOverflowsPositively(stamp1.lowerBound(), stamp2.lowerBound(), bits, unsigned); + boolean upperOverflowsPositively = addOverflowsPositively(stamp1.upperBound(), stamp2.upperBound(), bits, unsigned); + boolean lowerOverflowsNegatively = addOverflowsNegatively(stamp1.lowerBound(), stamp2.lowerBound(), bits, unsigned); + boolean upperOverflowsNegatively = addOverflowsNegatively(stamp1.upperBound(), stamp2.upperBound(), bits, unsigned); if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsPositively && upperOverflowsPositively)) { - lowerBound = kind.getMinValue(); - upperBound = kind.getMaxValue(); + lowerBound = IntegerStamp.defaultMinValue(bits, unsigned); + upperBound = IntegerStamp.defaultMaxValue(bits, unsigned); } else { - lowerBound = signExtend((stamp1.lowerBound() + stamp2.lowerBound()) & defaultMask, kind); - upperBound = signExtend((stamp1.upperBound() + stamp2.upperBound()) & defaultMask, kind); + lowerBound = (stamp1.lowerBound() + stamp2.lowerBound()) & defaultMask; + upperBound = (stamp1.upperBound() + stamp2.upperBound()) & defaultMask; + if (!unsigned) { + lowerBound = SignExtendNode.signExtend(lowerBound, bits); + upperBound = SignExtendNode.signExtend(upperBound, bits); + } } - IntegerStamp limit = StampFactory.forInteger(kind, lowerBound, upperBound); + IntegerStamp limit = StampFactory.forInteger(bits, unsigned, lowerBound, upperBound); newUpMask &= limit.upMask(); - upperBound = signExtend(upperBound & newUpMask, kind); + upperBound &= newUpMask; + if (!unsigned) { + upperBound = SignExtendNode.signExtend(upperBound, bits); + } newDownMask |= limit.downMask(); lowerBound |= newDownMask; - return new IntegerStamp(kind, lowerBound, upperBound, newDownMask, newUpMask); + return new IntegerStamp(bits, unsigned, lowerBound, upperBound, newDownMask, newUpMask); } public static Stamp sub(IntegerStamp stamp1, IntegerStamp stamp2) { if (stamp1.isUnrestricted() || stamp2.isUnrestricted()) { - return StampFactory.forKind(stamp1.kind()); + return stamp1.unrestricted(); } return add(stamp1, (IntegerStamp) StampTool.negate(stamp2)); } - private static Stamp stampForMask(Kind kind, long downMask, long upMask) { + private static Stamp stampForMask(int bits, long downMask, long upMask) { long lowerBound; long upperBound; - if (((upMask >>> (kind.getBitCount() - 1)) & 1) == 0) { + if (((upMask >>> (bits - 1)) & 1) == 0) { lowerBound = downMask; upperBound = upMask; - } else if (((downMask >>> (kind.getBitCount() - 1)) & 1) == 1) { + } else if (((downMask >>> (bits - 1)) & 1) == 1) { lowerBound = downMask; upperBound = upMask; } else { - lowerBound = downMask | (-1L << (kind.getBitCount() - 1)); - upperBound = kind.getMaxValue() & upMask; + lowerBound = downMask | (-1L << (bits - 1)); + upperBound = IntegerStamp.defaultMaxValue(bits, false) & upMask; } - if (kind == Kind.Int) { - return StampFactory.forInteger(kind, (int) lowerBound, (int) upperBound, downMask, upMask); - } else { - return StampFactory.forInteger(kind, lowerBound, upperBound, downMask, upMask); - } + lowerBound = IntegerConvertNode.convert(lowerBound, bits, false); + upperBound = IntegerConvertNode.convert(upperBound, bits, false); + return new IntegerStamp(bits, false, lowerBound, upperBound, downMask, upMask); } public static Stamp and(Stamp stamp1, Stamp stamp2) { if (stamp1 instanceof IntegerStamp && stamp2 instanceof IntegerStamp) { return and((IntegerStamp) stamp1, (IntegerStamp) stamp2); } - return StampFactory.illegal(joinKind(stamp1, stamp2)); + return joinIllegal(stamp1, stamp2); } public static Stamp and(IntegerStamp stamp1, IntegerStamp stamp2) { - assert stamp1.kind() == stamp2.kind(); - return stampForMask(stamp1.kind(), stamp1.downMask() & stamp2.downMask(), stamp1.upMask() & stamp2.upMask()); + assert stamp1.getBits() == stamp2.getBits(); + return stampForMask(stamp1.getBits(), stamp1.downMask() & stamp2.downMask(), stamp1.upMask() & stamp2.upMask()); } public static Stamp or(Stamp stamp1, Stamp stamp2) { if (stamp1 instanceof IntegerStamp && stamp2 instanceof IntegerStamp) { return or((IntegerStamp) stamp1, (IntegerStamp) stamp2); } - return StampFactory.illegal(joinKind(stamp1, stamp2)); + return joinIllegal(stamp1, stamp2); } public static Stamp or(IntegerStamp stamp1, IntegerStamp stamp2) { - assert stamp1.kind() == stamp2.kind(); - return stampForMask(stamp1.kind(), stamp1.downMask() | stamp2.downMask(), stamp1.upMask() | stamp2.upMask()); + assert stamp1.getBits() == stamp2.getBits(); + return stampForMask(stamp1.getBits(), stamp1.downMask() | stamp2.downMask(), stamp1.upMask() | stamp2.upMask()); } public static Stamp xor(Stamp stamp1, Stamp stamp2) { if (stamp1 instanceof IntegerStamp && stamp2 instanceof IntegerStamp) { return xor((IntegerStamp) stamp1, (IntegerStamp) stamp2); } - return StampFactory.illegal(joinKind(stamp1, stamp2)); + return joinIllegal(stamp1, stamp2); } public static Stamp xor(IntegerStamp stamp1, IntegerStamp stamp2) { - assert stamp1.kind() == stamp2.kind(); + assert stamp1.getBits() == stamp2.getBits(); long variableBits = (stamp1.downMask() ^ stamp1.upMask()) | (stamp2.downMask() ^ stamp2.upMask()); long newDownMask = (stamp1.downMask() ^ stamp2.downMask()) & ~variableBits; long newUpMask = (stamp1.downMask() ^ stamp2.downMask()) | variableBits; - return stampForMask(stamp1.kind(), newDownMask, newUpMask); + return stampForMask(stamp1.getBits(), newDownMask, newUpMask); } public static Stamp unsignedRightShift(Stamp value, Stamp shift) { if (value instanceof IntegerStamp && shift instanceof IntegerStamp) { return unsignedRightShift((IntegerStamp) value, (IntegerStamp) shift); } - return StampFactory.illegal(value.kind()); + return value.illegal(); } public static Stamp unsignedRightShift(IntegerStamp value, IntegerStamp shift) { - Kind kind = value.kind(); + int bits = value.getBits(); if (shift.lowerBound() == shift.upperBound()) { - long shiftMask = kind == Kind.Int ? 0x1FL : 0x3FL; + long shiftMask = bits > 32 ? 0x3FL : 0x1FL; long shiftCount = shift.lowerBound() & shiftMask; if (shiftCount != 0) { long lowerBound; @@ -260,28 +282,28 @@ lowerBound = value.lowerBound() >>> shiftCount; upperBound = value.upperBound() >>> shiftCount; } - return new IntegerStamp(kind, lowerBound, upperBound, downMask, upMask); + return new IntegerStamp(bits, value.isUnsigned(), lowerBound, upperBound, downMask, upMask); } } - long mask = IntegerStamp.upMaskFor(kind, value.lowerBound(), value.upperBound()); - return stampForMask(kind, 0, mask); + long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound()); + return stampForMask(bits, 0, mask); } public static Stamp leftShift(Stamp value, Stamp shift) { if (value instanceof IntegerStamp && shift instanceof IntegerStamp) { return leftShift((IntegerStamp) value, (IntegerStamp) shift); } - return StampFactory.illegal(value.kind()); + return value.illegal(); } public static Stamp leftShift(IntegerStamp value, IntegerStamp shift) { - Kind kind = value.kind(); - long defaultMask = IntegerStamp.defaultMask(kind); + int bits = value.getBits(); + long defaultMask = IntegerStamp.defaultMask(bits); if (value.upMask() == 0) { return value; } - int shiftBits = kind == Kind.Int ? 5 : 6; - long shiftMask = kind == Kind.Int ? 0x1FL : 0x3FL; + int shiftBits = bits > 32 ? 6 : 5; + long shiftMask = bits > 32 ? 0x3FL : 0x1FL; if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) { long downMask = defaultMask; long upMask = 0; @@ -291,14 +313,98 @@ upMask |= value.upMask() << (i & shiftMask); } } - Stamp result = stampForMask(kind, downMask, upMask & IntegerStamp.defaultMask(kind)); + Stamp result = stampForMask(bits, downMask, upMask & defaultMask); return result; } - return StampFactory.forKind(kind); + return value.unrestricted(); + } + + public static Stamp signExtend(Stamp input, int resultBits) { + if (input instanceof IntegerStamp) { + IntegerStamp inputStamp = (IntegerStamp) input; + int inputBits = inputStamp.getBits(); + assert inputBits <= resultBits; + + long defaultMask = IntegerStamp.defaultMask(resultBits); + long downMask = SignExtendNode.signExtend(inputStamp.downMask(), inputBits) & defaultMask; + long upMask = SignExtendNode.signExtend(inputStamp.upMask(), inputBits) & defaultMask; + + long lowerBound; + long upperBound; + if (inputStamp.isUnsigned()) { + lowerBound = SignExtendNode.signExtend(inputStamp.lowerBound(), inputBits) & defaultMask; + upperBound = SignExtendNode.signExtend(inputStamp.upperBound(), inputBits) & defaultMask; + } else { + lowerBound = inputStamp.lowerBound(); + upperBound = inputStamp.upperBound(); + } + + return new IntegerStamp(resultBits, inputStamp.isUnsigned(), lowerBound, upperBound, downMask, upMask); + } else { + return input.illegal(); + } } - public static Stamp intToLong(IntegerStamp intStamp) { - return StampFactory.forInteger(Kind.Long, intStamp.lowerBound(), intStamp.upperBound(), signExtend(intStamp.downMask(), Kind.Int), signExtend(intStamp.upMask(), Kind.Int)); + public static Stamp zeroExtend(Stamp input, int resultBits) { + if (input instanceof IntegerStamp) { + IntegerStamp inputStamp = (IntegerStamp) input; + int inputBits = inputStamp.getBits(); + assert inputBits <= resultBits; + + long downMask = ZeroExtendNode.zeroExtend(inputStamp.downMask(), inputBits); + long upMask = ZeroExtendNode.zeroExtend(inputStamp.upMask(), inputBits); + + if (inputStamp.lowerBound() < 0 && inputStamp.upperBound() >= 0) { + // signed range including 0 and -1 + // after sign extension, the whole range from 0 to MAX_INT is possible + return stampForMask(resultBits, downMask, upMask); + } + + long lowerBound = ZeroExtendNode.zeroExtend(inputStamp.lowerBound(), inputBits); + long upperBound = ZeroExtendNode.zeroExtend(inputStamp.upperBound(), inputBits); + + return new IntegerStamp(resultBits, inputStamp.isUnsigned(), lowerBound, upperBound, downMask, upMask); + } else { + return input.illegal(); + } + } + + public static Stamp narrowingConversion(Stamp input, int resultBits) { + if (input instanceof IntegerStamp) { + IntegerStamp inputStamp = (IntegerStamp) input; + boolean unsigned = inputStamp.isUnsigned(); + int inputBits = inputStamp.getBits(); + assert resultBits <= inputBits; + if (resultBits == inputBits) { + return inputStamp; + } + + final long upperBound; + if (inputStamp.lowerBound() < IntegerStamp.defaultMinValue(resultBits, unsigned)) { + upperBound = IntegerStamp.defaultMaxValue(resultBits, unsigned); + } else { + upperBound = saturate(inputStamp.upperBound(), resultBits, unsigned); + } + final long lowerBound; + if (inputStamp.upperBound() > IntegerStamp.defaultMaxValue(resultBits, unsigned)) { + lowerBound = IntegerStamp.defaultMinValue(resultBits, unsigned); + } else { + lowerBound = saturate(inputStamp.lowerBound(), resultBits, unsigned); + } + + long defaultMask = IntegerStamp.defaultMask(resultBits); + long newDownMask = inputStamp.downMask() & defaultMask; + long newUpMask = inputStamp.upMask() & defaultMask; + long newLowerBound = (lowerBound | newDownMask) & newUpMask; + long newUpperBound = (upperBound | newDownMask) & newUpMask; + if (!unsigned) { + newLowerBound = SignExtendNode.signExtend(newLowerBound, resultBits); + newUpperBound = SignExtendNode.signExtend(newUpperBound, resultBits); + } + return new IntegerStamp(resultBits, unsigned, newLowerBound, newUpperBound, newDownMask, newUpMask); + } else { + return input.illegal(); + } } public static IntegerStamp narrowingKindConversion(IntegerStamp fromStamp, Kind toKind) { @@ -316,11 +422,11 @@ lowerBound = saturate(fromStamp.lowerBound(), toKind); } - long defaultMask = IntegerStamp.defaultMask(toKind); - long intMask = IntegerStamp.defaultMask(Kind.Int); + long defaultMask = IntegerStamp.defaultMask(toKind.getBitCount()); + long intMask = IntegerStamp.defaultMask(32); long newUpMask = signExtend(fromStamp.upMask() & defaultMask, toKind) & intMask; long newDownMask = signExtend(fromStamp.downMask() & defaultMask, toKind) & intMask; - return new IntegerStamp(toKind.getStackKind(), (int) ((lowerBound | newDownMask) & newUpMask), (int) ((upperBound | newDownMask) & newUpMask), newDownMask, newUpMask); + return new IntegerStamp(toKind.getStackKind().getBitCount(), false, (int) ((lowerBound | newDownMask) & newUpMask), (int) ((upperBound | newDownMask) & newUpMask), newDownMask, newUpMask); } private static long signExtend(long value, Kind valueKind) { @@ -331,7 +437,21 @@ } } - public static long saturate(long v, Kind kind) { + private static long saturate(long v, int bits, boolean unsigned) { + if (bits < 64) { + long max = IntegerStamp.defaultMaxValue(bits, unsigned); + if (v > max) { + return max; + } + long min = IntegerStamp.defaultMinValue(bits, unsigned); + if (v < min) { + return min; + } + } + return v; + } + + private static long saturate(long v, Kind kind) { long max = kind.getMaxValue(); if (v > max) { return max; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/VoidStamp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/VoidStamp.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,99 @@ +/* + * 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.nodes.type; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.spi.*; + +/** + * Singleton stamp representing the value of type {@code void}. + */ +public final class VoidStamp extends Stamp { + + private VoidStamp() { + } + + @Override + public Stamp unrestricted() { + return this; + } + + @Override + public Kind getStackKind() { + return Kind.Void; + } + + @Override + public PlatformKind getPlatformKind(LIRTypeTool tool) { + throw GraalInternalError.shouldNotReachHere("void stamp has no value"); + } + + @Override + public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { + return metaAccess.lookupJavaType(Void.TYPE); + } + + @Override + public String toString() { + return "void"; + } + + @Override + public boolean alwaysDistinct(Stamp other) { + return this != other; + } + + @Override + public Stamp meet(Stamp other) { + if (other instanceof IllegalStamp) { + return other.join(this); + } + if (this == other) { + return this; + } + return StampFactory.illegal(Kind.Illegal); + } + + @Override + public Stamp join(Stamp other) { + if (other instanceof IllegalStamp) { + return other.join(this); + } + if (this == other) { + return this; + } + return StampFactory.illegal(Kind.Illegal); + } + + @Override + public boolean isCompatible(Stamp stamp) { + return this == stamp; + } + + private static VoidStamp instance = new VoidStamp(); + + static VoidStamp getInstance() { + return instance; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Wed Mar 05 19:40:15 2014 -0800 @@ -137,6 +137,13 @@ } } + public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) { + FixedNode next = fixed.next(); + fixed.setNext(null); + fixed.replaceAtPredecessor(next); + killWithUnusedFloatingInputs(fixed); + } + public static void checkRedundantPhi(PhiNode phiNode) { if (phiNode.isDeleted() || phiNode.valueCount() == 1) { return; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.virtual; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -30,7 +31,7 @@ * Selects one object from a {@link CommitAllocationNode}. The object is identified by its * {@link VirtualObjectNode}. */ -public class AllocatedObjectNode extends FloatingNode implements Virtualizable { +public class AllocatedObjectNode extends FloatingNode implements Virtualizable, ArrayLengthProvider { @Input private VirtualObjectNode virtualObject; @Input private CommitAllocationNode commit; @@ -57,4 +58,11 @@ public void virtualize(VirtualizerTool tool) { tool.replaceWithVirtual(getVirtualObject()); } + + public ValueNode length() { + if (virtualObject instanceof ArrayLengthProvider) { + return ((ArrayLengthProvider) virtualObject).length(); + } + return null; + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -30,7 +30,7 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]") -public class VirtualArrayNode extends VirtualObjectNode { +public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider { private final ResolvedJavaType componentType; private final int length; @@ -144,4 +144,8 @@ public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) { return new AllocatedObjectNode(this); } + + public ValueNode length() { + return ConstantNode.forInt(length, graph()); + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Wed Mar 05 19:40:15 2014 -0800 @@ -128,7 +128,7 @@ return new MultipleOverridesScope(current, map); } - private static ThreadLocal overrideScopes = new ThreadLocal<>(); + private static final ThreadLocal overrideScopes = new ThreadLocal<>(); /** * The raw option value. diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -185,7 +185,7 @@ boolean improvedStamp = tryInferStamp(valueNode); Constant constant = valueNode.stamp().asConstant(); if (constant != null && !(node instanceof ConstantNode)) { - performReplacement(valueNode, ConstantNode.forConstant(constant, context.getMetaAccess(), valueNode.graph())); + performReplacement(valueNode, ConstantNode.forConstant(valueNode.stamp(), constant, context.getMetaAccess(), valueNode.graph())); } else if (improvedStamp) { // the improved stamp may enable additional canonicalization tryCanonicalize(valueNode, nodeClass); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -315,9 +315,18 @@ private void registerCondition(boolean isTrue, LogicNode condition, ValueNode anchor) { if (!isTrue && condition instanceof ShortCircuitOrNode) { - ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition; - registerCondition(disjunction.isXNegated(), disjunction.getX(), anchor); - registerCondition(disjunction.isYNegated(), disjunction.getY(), anchor); + /* + * We can only do this for fixed nodes, because floating guards will be registered + * at a BeginNode but might be "valid" only later due to data flow dependencies. + * Therefore, registering both conditions of a ShortCircuitOrNode for a floating + * guard could lead to cycles in data flow, because the guard will be used as anchor + * for both conditions, and one condition could be depending on the other. + */ + if (anchor instanceof FixedNode) { + ShortCircuitOrNode disjunction = (ShortCircuitOrNode) condition; + registerCondition(disjunction.isXNegated(), disjunction.getX(), anchor); + registerCondition(disjunction.isYNegated(), disjunction.getY(), anchor); + } } state.addCondition(isTrue, condition, anchor); @@ -617,7 +626,7 @@ if (type != ObjectStamp.typeOrNull(receiver)) { ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod()); if (method != null) { - if ((method.getModifiers() & Modifier.FINAL) != 0 || (type.getModifiers() & Modifier.FINAL) != 0) { + if (Modifier.isFinal(method.getModifiers()) || Modifier.isFinal(type.getModifiers())) { callTarget.setInvokeKind(InvokeKind.Special); callTarget.setTargetMethod(method); } @@ -630,6 +639,9 @@ } private GuardingNode searchAnchor(ValueNode value, ResolvedJavaType type) { + if (!value.recordsUsages()) { + return null; + } for (Node n : value.usages()) { if (n instanceof InstanceOfNode) { InstanceOfNode instanceOfNode = (InstanceOfNode) n; diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -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); @@ -857,7 +861,7 @@ @Override public String toString() { - return MetaUtil.format("%H.%n(%p)", method()) + remainingInvokes; + return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "") + remainingInvokes; } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Mar 05 19:40:15 2014 -0800 @@ -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(); } @@ -1298,6 +1317,8 @@ FixedNode invokeNode = invoke.asNode(); StructuredGraph graph = invokeNode.graph(); assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal(); + assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase"; + Kind returnKind = invokeNode.kind(); FrameState stateAfter = invoke.stateAfter(); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -36,19 +36,8 @@ if (next instanceof MonitorEnterNode) { MonitorEnterNode monitorEnterNode = (MonitorEnterNode) next; if (monitorEnterNode.object() == node.object()) { - FixedNode monitorEnterSuccessor = monitorEnterNode.next(); - monitorEnterNode.setNext(null); - ((FixedWithNextNode) node.predecessor()).setNext(monitorEnterSuccessor); - FrameState stateAfterFirst = node.stateAfter(); - FrameState stateAfterSecond = monitorEnterNode.stateAfter(); - node.safeDelete(); - monitorEnterNode.safeDelete(); - if (stateAfterFirst.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(stateAfterFirst); - } - if (stateAfterSecond.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(stateAfterSecond); - } + GraphUtil.removeFixedWithUnusedInputs(monitorEnterNode); + GraphUtil.removeFixedWithUnusedInputs(node); } } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,43 @@ +/* + * 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.common; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; + +/** + * Modifies the stamp of all object {@linkplain ParameterNode parameters} in a graph to denote they + * are non-null. This can be used for graphs where the caller null checks all arguments. + */ +public class NonNullParametersPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (ParameterNode param : graph.getNodes(ParameterNode.class)) { + if (param.stamp() instanceof ObjectStamp) { + param.setStamp(StampFactory.declaredNonNull(((ObjectStamp) param.stamp()).type())); + } + } + } +} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -30,6 +30,8 @@ // @formatter:off public final class GraalOptions { + @Option(help = "Use baseline compiler configuration") + public static final OptionValue UseBaselineCompiler = new OptionValue<>(false); @Option(help = "Enable use of compiler intrinsics") public static final OptionValue Intrinsify = new OptionValue<>(true); @Option(help = "Enable inlining of monomorphic calls") @@ -232,6 +234,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); @@ -251,8 +256,6 @@ @Option(help = "") public static final OptionValue OptEliminateGuards = new OptionValue<>(true); @Option(help = "") - public static final OptionValue OptEliminateSafepoints = new OptionValue<>(true); - @Option(help = "") public static final OptionValue OptImplicitNullChecks = new OptionValue<>(true); @Option(help = "") public static final OptionValue OptLivenessAnalysis = new OptionValue<>(true); diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,95 @@ +/* + * 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.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 (ObjectStamp.isObject(node.stamp())) { + assert !(node.stamp() instanceof IllegalStamp) : "We assume all Phi and Proxy stamps are legal before the analysis"; + node.setStamp(node.stamp().illegal()); + } + } + } + + 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 (ObjectStamp.isObject(node.stamp())) { + 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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Wed Mar 05 19:40:15 2014 -0800 @@ -55,7 +55,7 @@ if (input instanceof FrameState && node instanceof StateSplit && input == ((StateSplit) node).stateAfter()) { // nothing to do - after frame states are known, allowed cycles } else { - assert false : "cycle detected: " + node + " -> " + input; + assert false : "unexpected cycle detected at input " + node + " -> " + input; } } } @@ -81,7 +81,7 @@ private static void visitForward(ArrayList nodes, NodeBitMap visited, Node node, boolean floatingOnly) { if (node != null && !visited.isMarked(node)) { - assert !floatingOnly || !(node instanceof FixedNode) : "unexpected reference to fixed node: " + node; + assert !floatingOnly || !(node instanceof FixedNode) : "unexpected reference to fixed node: " + node + " (this indicates an unexpected cycle)"; visited.mark(node); FrameState stateAfter = null; if (node instanceof StateSplit) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.replacements.amd64; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * This node has the semantics of the AMD64 conversions. It is used in the lowering of the - * {@link ConvertNode} which, on AMD64 needs a {@link AMD64ConvertNode} plus some fixup code that - * handles the corner cases that differ between AMD64 and Java. - */ -public class AMD64ConvertNode extends FloatingNode implements ArithmeticLIRLowerable { - - @Input private ValueNode value; - private final Kind from; - private final Kind to; - - public AMD64ConvertNode(Kind from, Kind to, ValueNode value) { - super(StampFactory.forKind(to.getStackKind())); - this.value = value; - this.from = from; - this.to = to; - } - - public Constant evalConst(Constant... inputs) { - // this node should never have been created if its input is constant - assert false; - return null; - } - - public void generate(ArithmeticLIRGenerator gen) { - gen.setResult(this, gen.emitConvert(from, to, gen.operand(value))); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Wed Mar 05 19:40:15 2014 -0800 @@ -158,42 +158,33 @@ d2l = snippet(AMD64ConvertSnippets.class, "d2l"); } - public void lower(ConvertNode convert, LoweringTool tool) { - SnippetInfo key = null; - switch (convert.getFromKind()) { - case Float: - switch (convert.getToKind()) { - case Int: - key = f2i; - break; - case Long: - key = f2l; - break; - } + public void lower(FloatConvertNode convert, LoweringTool tool) { + SnippetInfo key; + switch (convert.getOp()) { + case F2I: + key = f2i; + break; + case F2L: + key = f2l; break; - case Double: - switch (convert.getToKind()) { - case Int: - key = d2i; - break; - case Long: - key = d2l; - break; - } + case D2I: + key = d2i; break; - } - if (key == null) { - return; + case D2L: + key = d2l; + break; + default: + return; } StructuredGraph graph = convert.graph(); Arguments args = new Arguments(key, graph.getGuardsStage(), tool.getLoweringStage()); - args.add("input", convert.value()); - args.add("result", graph.unique(new AMD64ConvertNode(convert.getFromKind(), convert.getToKind(), convert.value()))); + args.add("input", convert.getInput()); + args.add("result", graph.unique(new AMD64FloatConvertNode(convert.stamp(), convert.getOp(), convert.getInput()))); SnippetTemplate template = template(args); - Debug.log("Lowering %c2%c in %s: node=%s, template=%s, arguments=%s", convert.getFromKind().getTypeChar(), convert.getToKind().getTypeChar(), graph, convert, template, args); + Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getOp(), graph, convert, template, args); template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args); graph.removeFloating(convert); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 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.replacements.amd64; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * This node has the semantics of the AMD64 floating point conversions. It is used in the lowering + * of the {@link FloatConvertNode} which, on AMD64 needs a {@link AMD64FloatConvertNode} plus some + * fixup code that handles the corner cases that differ between AMD64 and Java. + */ +public class AMD64FloatConvertNode extends FloatingNode implements ArithmeticLIRLowerable { + + private final FloatConvert op; + @Input private ValueNode value; + + public AMD64FloatConvertNode(Stamp stamp, FloatConvert op, ValueNode value) { + super(stamp); + this.op = op; + this.value = value; + } + + public Constant evalConst(Constant... inputs) { + // this node should never have been created if its input is constant + throw GraalInternalError.shouldNotReachHere(); + } + + public void generate(ArithmeticLIRGenerator gen) { + gen.setResult(this, gen.emitFloatConvert(op, gen.operand(value))); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,6 +39,7 @@ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target) { if (Intrinsify.getValue()) { + replacements.registerSubstitutions(ArraysSubstitutions.class); replacements.registerSubstitutions(StringSubstitutions.class); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,332 @@ +/* + * 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.replacements.test; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Tests {@link ArraysSubstitutions}. + */ +public class ArraysSubstitutionsTest extends MethodSubstitutionTest { + + private static Object executeVarargsSafe(InstalledCode code, Object... args) { + try { + return code.executeVarargs(args); + } catch (InvalidInstalledCodeException e) { + throw new RuntimeException(e); + } + } + + private static Object invokeSafe(Method method, Object receiver, Object... args) { + method.setAccessible(true); + try { + Object result = method.invoke(receiver, args); + return result; + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, Class[] parameterTypes, boolean optional, Object[] args1, Object[] args2) { + Method realMethod = getMethod(holder, methodName, parameterTypes); + Method testMethod = getMethod(testMethodName); + StructuredGraph graph = test(testMethodName); + + // Check to see if the resulting graph contains the expected node + StructuredGraph replacement = getReplacements().getMethodSubstitution(getMetaAccess().lookupJavaMethod(realMethod)); + if (replacement == null && !optional) { + assertInGraph(graph, intrinsicClass); + } + + // Force compilation + InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(testMethod), parse(testMethod)); + assert optional || code != null; + + for (int i = 0; i < args1.length; i++) { + Object arg1 = args1[i]; + Object arg2 = args2[i]; + // Verify that the original method and the substitution produce the same value + assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2)); + // Verify that the generated code and the original produce the same value + assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2)); + } + } + + private static final int N = 10; + + @Test + public void testEqualsBoolean() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new boolean[i]; + args2[n] = new boolean[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + boolean[] a2 = new boolean[i]; + if (i > 0) { + a2[i - 1] = true; + } + args1[n] = new boolean[i]; + args2[n] = a2; + } + Class[] parameterTypes = new Class[]{boolean[].class, boolean[].class}; + testSubstitution("arraysEqualsBoolean", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsBoolean(boolean[] a, boolean[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsByte() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new byte[i]; + args2[n] = new byte[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + byte[] a2 = new byte[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new byte[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{byte[].class, byte[].class}; + testSubstitution("arraysEqualsByte", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsByte(byte[] a, byte[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsChar() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new char[i]; + args2[n] = new char[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + char[] a2 = new char[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new char[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{char[].class, char[].class}; + testSubstitution("arraysEqualsChar", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsChar(char[] a, char[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsShort() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new short[i]; + args2[n] = new short[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + short[] a2 = new short[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new short[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{short[].class, short[].class}; + testSubstitution("arraysEqualsShort", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsShort(short[] a, short[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsInt() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new int[i]; + args2[n] = new int[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + int[] a2 = new int[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new int[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{int[].class, int[].class}; + testSubstitution("arraysEqualsInt", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsInt(int[] a, int[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsLong() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new long[i]; + args2[n] = new long[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + long[] a2 = new long[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new long[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{long[].class, long[].class}; + testSubstitution("arraysEqualsLong", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsLong(long[] a, long[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsFloat() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new float[i]; + args2[n] = new float[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + float[] a2 = new float[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new float[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{float[].class, float[].class}; + testSubstitution("arraysEqualsFloat", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsFloat(float[] a, float[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsDouble() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new double[i]; + args2[n] = new double[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + double[] a2 = new double[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new double[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{double[].class, double[].class}; + testSubstitution("arraysEqualsDouble", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsDouble(double[] a, double[] b) { + return Arrays.equals(a, b); + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -102,7 +102,7 @@ private static void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) { ReadNode read = (ReadNode) graph.start().next(); - Assert.assertEquals(kind.getStackKind(), read.kind()); + Assert.assertEquals(kind.getStackKind(), read.stamp().getStackKind()); Assert.assertEquals(graph.getParameter(0), read.object()); IndexedLocationNode location = (IndexedLocationNode) read.location(); @@ -111,10 +111,10 @@ Assert.assertEquals(1, location.getIndexScaling()); if (indexConvert) { - ConvertNode convert = (ConvertNode) location.getIndex(); - Assert.assertEquals(Kind.Int, convert.getFromKind()); - Assert.assertEquals(Kind.Long, convert.getToKind()); - Assert.assertEquals(graph.getParameter(1), convert.value()); + SignExtendNode convert = (SignExtendNode) location.getIndex(); + Assert.assertEquals(convert.getInputBits(), 32); + Assert.assertEquals(convert.getResultBits(), 64); + Assert.assertEquals(graph.getParameter(1), convert.getInput()); } else { Assert.assertEquals(graph.getParameter(1), location.getIndex()); } @@ -127,7 +127,6 @@ WriteNode write = (WriteNode) graph.start().next(); Assert.assertEquals(graph.getParameter(2), write.value()); Assert.assertEquals(graph.getParameter(0), write.object()); - Assert.assertEquals(Kind.Void, write.kind()); Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci); IndexedLocationNode location = (IndexedLocationNode) write.location(); @@ -136,10 +135,10 @@ Assert.assertEquals(1, location.getIndexScaling()); if (indexConvert) { - ConvertNode convert = (ConvertNode) location.getIndex(); - Assert.assertEquals(Kind.Int, convert.getFromKind()); - Assert.assertEquals(Kind.Long, convert.getToKind()); - Assert.assertEquals(graph.getParameter(1), convert.value()); + SignExtendNode convert = (SignExtendNode) location.getIndex(); + Assert.assertEquals(convert.getInputBits(), 32); + Assert.assertEquals(convert.getResultBits(), 64); + Assert.assertEquals(graph.getParameter(1), convert.getInput()); } else { Assert.assertEquals(graph.getParameter(1), location.getIndex()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -110,11 +110,11 @@ WordCastNode cast = (WordCastNode) graph.start().next(); ReadNode read = (ReadNode) cast.next(); - Assert.assertEquals(kind.getStackKind(), read.kind()); + Assert.assertEquals(kind.getStackKind(), read.stamp().getStackKind()); Assert.assertEquals(cast, read.object()); Assert.assertEquals(graph.getParameter(0), cast.getInput()); - Assert.assertEquals(target.wordKind, cast.kind()); + Assert.assertEquals(target.wordKind, cast.stamp().getStackKind()); IndexedLocationNode location = (IndexedLocationNode) read.location(); Assert.assertEquals(kind, location.getValueKind()); @@ -122,10 +122,10 @@ Assert.assertEquals(1, location.getIndexScaling()); if (indexConvert) { - ConvertNode convert = (ConvertNode) location.getIndex(); - Assert.assertEquals(Kind.Int, convert.getFromKind()); - Assert.assertEquals(Kind.Long, convert.getToKind()); - Assert.assertEquals(graph.getParameter(1), convert.value()); + SignExtendNode convert = (SignExtendNode) location.getIndex(); + Assert.assertEquals(convert.getInputBits(), 32); + Assert.assertEquals(convert.getResultBits(), 64); + Assert.assertEquals(graph.getParameter(1), convert.getInput()); } else { Assert.assertEquals(graph.getParameter(1), location.getIndex()); } @@ -139,12 +139,11 @@ WriteNode write = (WriteNode) cast.next(); Assert.assertEquals(graph.getParameter(2), write.value()); - Assert.assertEquals(Kind.Void, write.kind()); Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci); Assert.assertEquals(cast, write.object()); Assert.assertEquals(graph.getParameter(0), cast.getInput()); - Assert.assertEquals(target.wordKind, cast.kind()); + Assert.assertEquals(target.wordKind, cast.stamp().getStackKind()); IndexedLocationNode location = (IndexedLocationNode) write.location(); Assert.assertEquals(kind, location.getValueKind()); @@ -152,10 +151,10 @@ Assert.assertEquals(1, location.getIndexScaling()); if (indexConvert) { - ConvertNode convert = (ConvertNode) location.getIndex(); - Assert.assertEquals(Kind.Int, convert.getFromKind()); - Assert.assertEquals(Kind.Long, convert.getToKind()); - Assert.assertEquals(graph.getParameter(1), convert.value()); + SignExtendNode convert = (SignExtendNode) location.getIndex(); + Assert.assertEquals(convert.getInputBits(), 32); + Assert.assertEquals(convert.getResultBits(), 64); + Assert.assertEquals(graph.getParameter(1), convert.getInput()); } else { Assert.assertEquals(graph.getParameter(1), location.getIndex()); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,6 +32,7 @@ import sun.misc.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -350,19 +351,54 @@ // Math.pow(value, 13); } + private static Object executeVarargsSafe(InstalledCode code, Object... args) { + try { + return code.executeVarargs(args); + } catch (InvalidInstalledCodeException e) { + throw new RuntimeException(e); + } + } + + private static Object invokeSafe(Method method, Object... args) { + method.setAccessible(true); + try { + Object result = method.invoke(null, args); + return result; + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, boolean optional, Object... args) { + Method realMethod = getMethod(holder, methodName); + Method testMethod = getMethod(testMethodName); + StructuredGraph graph = test(testMethodName); + + // Check to see if the resulting graph contains the expected node + StructuredGraph replacement = getReplacements().getMethodSubstitution(getMetaAccess().lookupJavaMethod(realMethod)); + if (replacement == null && !optional) { + assertInGraph(graph, intrinsicClass); + } + + // Force compilation + InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(testMethod), parse(testMethod)); + assert optional || code != null; + for (Object l : args) { + // Verify that the original method and the substitution produce the same value + assertEquals(invokeSafe(testMethod, l), invokeSafe(realMethod, l)); + // Verify that the generated code and the original produce the same value + assertEquals(executeVarargsSafe(code, l), invokeSafe(realMethod, l)); + } + } + @Test public void testIntegerSubstitutions() { - assertInGraph(test("integerReverseBytes"), ReverseBytesNode.class); // Java - assertInGraph(test("integerNumberOfLeadingZeros"), BitScanReverseNode.class); // Java - assertInGraph(test("integerNumberOfTrailingZeros"), BitScanForwardNode.class); // Java - assertInGraph(test("integerBitCount"), BitCountNode.class); // Java + Object[] args = new Object[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE}; - for (int i : new int[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE}) { - assertEquals(Integer.reverseBytes(i), IntegerSubstitutions.reverseBytes(i)); - assertEquals(Integer.numberOfLeadingZeros(i), IntegerSubstitutions.numberOfLeadingZeros(i)); - assertEquals(Integer.numberOfTrailingZeros(i), IntegerSubstitutions.numberOfTrailingZeros(i)); - assertEquals(Integer.bitCount(i), IntegerSubstitutions.bitCount(i)); - } + testSubstitution("integerReverseBytes", ReverseBytesNode.class, Integer.class, "reverseBytes", false, args); + testSubstitution("integerNumberOfLeadingZeros", BitScanReverseNode.class, Integer.class, "numberOfLeadingZeros", true, args); + testSubstitution("integerNumberOfTrailingZeros", BitScanForwardNode.class, Integer.class, "numberOfTrailingZeros", false, args); + testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args); } @SuppressWarnings("all") @@ -387,17 +423,12 @@ @Test public void testLongSubstitutions() { - assertInGraph(test("longReverseBytes"), ReverseBytesNode.class); // Java - assertInGraph(test("longNumberOfLeadingZeros"), BitScanReverseNode.class); // Java - assertInGraph(test("longNumberOfTrailingZeros"), BitScanForwardNode.class); // Java - assertInGraph(test("longBitCount"), BitCountNode.class); // Java + Object[] args = new Object[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE}; - for (long l : new long[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE}) { - assertEquals(Long.reverseBytes(l), LongSubstitutions.reverseBytes(l)); - assertEquals(Long.numberOfLeadingZeros(l), LongSubstitutions.numberOfLeadingZeros(l)); - assertEquals(Long.numberOfTrailingZeros(l), LongSubstitutions.numberOfTrailingZeros(l)); - assertEquals(Long.bitCount(l), LongSubstitutions.bitCount(l)); - } + testSubstitution("longReverseBytes", ReverseBytesNode.class, Long.class, "reverseBytes", false, args); + testSubstitution("longNumberOfLeadingZeros", BitScanReverseNode.class, Long.class, "numberOfLeadingZeros", true, args); + testSubstitution("longNumberOfTrailingZeros", BitScanForwardNode.class, Long.class, "numberOfTrailingZeros", false, args); + testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args); } @SuppressWarnings("all") @@ -406,12 +437,12 @@ } @SuppressWarnings("all") - public static long longNumberOfLeadingZeros(long value) { + public static int longNumberOfLeadingZeros(long value) { return Long.numberOfLeadingZeros(value); } @SuppressWarnings("all") - public static long longNumberOfTrailingZeros(long value) { + public static int longNumberOfTrailingZeros(long value) { return Long.numberOfTrailingZeros(value); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,116 @@ +/* + * 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.replacements.test; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Tests {@link StringSubstitutions}. + */ +public class StringSubstitutionsTest extends MethodSubstitutionTest { + + private static Object executeVarargsSafe(InstalledCode code, Object... args) { + try { + return code.executeVarargs(args); + } catch (InvalidInstalledCodeException e) { + throw new RuntimeException(e); + } + } + + private static Object invokeSafe(Method method, Object receiver, Object... args) { + method.setAccessible(true); + try { + Object result = method.invoke(receiver, args); + return result; + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, boolean optional, Object[] args1, Object[] args2) { + Method realMethod = getMethod(holder, methodName); + Method testMethod = getMethod(testMethodName); + StructuredGraph graph = test(testMethodName); + + // Check to see if the resulting graph contains the expected node + StructuredGraph replacement = getReplacements().getMethodSubstitution(getMetaAccess().lookupJavaMethod(realMethod)); + if (replacement == null && !optional) { + assertInGraph(graph, intrinsicClass); + } + + // Force compilation + InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(testMethod), parse(testMethod)); + assert optional || code != null; + + for (int i = 0; i < args1.length; i++) { + Object arg1 = args1[i]; + Object arg2 = args2[i]; + // Verify that the original method and the substitution produce the same value + assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, arg1, arg2)); + // Verify that the generated code and the original produce the same value + assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, arg1, arg2)); + } + } + + @Test + public void testEquals() { + final int n = 1000; + Object[] args1 = new Object[n]; + Object[] args2 = new Object[n]; + + // equal strings + String s1 = ""; + String s2 = ""; + for (int i = 0; i < n / 2; i++) { + args1[i] = s1; + args2[i] = s2; + s1 = s1 + "0"; + s2 = s2 + "0"; + } + + // non-equal strings + s1 = ""; + s2 = ""; + for (int i = n / 2; i < n; i++) { + args1[i] = s1; + args2[i] = s2; + s2 = s1 + "1"; + s1 = s1 + "0"; + } + + testSubstitution("stringEquals", ArrayEqualsNode.class, String.class, "equals", false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean stringEquals(String a, String b) { + return a.equals(b); + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsignedMathTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsignedMathTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,116 @@ +/* + * 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.replacements.test; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; + +/** + * Tests the substitutions for the {@link UnsignedMath} class. + */ +public class UnsignedMathTest extends GraalCompilerTest { + + public static boolean aboveThanInt(int a, int b) { + return UnsignedMath.aboveThan(a, b); + } + + public static boolean aboveOrEqualInt(int a, int b) { + return UnsignedMath.aboveOrEqual(a, b); + } + + public static boolean belowThanInt(int a, int b) { + return UnsignedMath.belowThan(a, b); + } + + public static boolean belowOrEqualInt(int a, int b) { + return UnsignedMath.belowOrEqual(a, b); + } + + public static int divideInt(int a, int b) { + return UnsignedMath.divide(a, b); + } + + public static int remainderInt(int a, int b) { + return UnsignedMath.remainder(a, b); + } + + public static boolean aboveThanLong(long a, long b) { + return UnsignedMath.aboveThan(a, b); + } + + public static boolean aboveOrEqualLong(long a, long b) { + return UnsignedMath.aboveOrEqual(a, b); + } + + public static boolean belowThanLong(long a, long b) { + return UnsignedMath.belowThan(a, b); + } + + public static boolean belowOrEqualLong(long a, long b) { + return UnsignedMath.belowOrEqual(a, b); + } + + public static long divideLong(long a, long b) { + return UnsignedMath.divide(a, b); + } + + public static long remainderLong(long a, long b) { + return UnsignedMath.remainder(a, b); + } + + private void testInt(int a, int b) { + test("aboveThanInt", a, b); + test("aboveOrEqualInt", a, b); + test("belowThanInt", a, b); + test("belowOrEqualInt", a, b); + test("divideInt", a, b); + test("remainderInt", a, b); + } + + private void testLong(long a, long b) { + test("aboveThanLong", a, b); + test("aboveOrEqualLong", a, b); + test("belowThanLong", a, b); + test("belowOrEqualLong", a, b); + test("divideLong", a, b); + test("remainderLong", a, b); + } + + @Test + public void testInt() { + testInt(5, 7); + testInt(-3, -7); + testInt(-3, 7); + testInt(42, -5); + } + + @Test + public void testLong() { + testLong(5, 7); + testLong(-3, -7); + testLong(-3, 7); + testLong(42, -5); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,4 +36,13 @@ public static Object newInstance(Class componentType, int length) throws NegativeArraySizeException { return DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(componentType), length); } + + @MethodSubstitution + public static int getLength(Object array) { + if (!array.getClass().isArray()) { + throw new IllegalArgumentException("Argument is not an array"); + } + return ArrayLengthNode.arrayLength(array); + } + } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraysSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraysSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,121 @@ +/* + * 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.graal.replacements; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Substitutions for {@link java.util.Arrays} methods. + */ +@ClassSubstitution(java.util.Arrays.class) +public class ArraysSubstitutions { + + @MethodSubstitution + public static boolean equals(boolean[] a, boolean[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(byte[] a, byte[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(char[] a, char[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(short[] a, short[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(int[] a, int[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(long[] a, long[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(float[] a, float[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(double[] a, double[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -42,25 +43,94 @@ * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. */ public class CollapseFrameForSingleSideEffectPhase extends Phase { - @Override - protected void run(StructuredGraph graph) { - ReentrantNodeIterator.apply(new CollapseFrameForSingleSideEffectClosure(), graph.start(), null, null); + + private static class IterationState { + public final IterationState previous; + public final Node node; + public final Collection merge; + public final boolean invalid; + + private IterationState(IterationState previous, Node node, Collection merge, boolean invalid) { + this.previous = previous; + this.node = node; + this.merge = merge; + this.invalid = invalid; + } + + public IterationState() { + this(null, null, null, false); + } + + public IterationState addSideEffect(StateSplit sideEffect) { + return new IterationState(this, sideEffect.asNode(), null, true); + } + + public IterationState addBranch(AbstractBeginNode begin) { + return new IterationState(this, begin, null, this.invalid); + } + + public static IterationState merge(MergeNode merge, Collection before, boolean invalid) { + return new IterationState(null, merge, before, invalid); + } + + public void markAll(NodeBitMap set) { + IterationState state = this; + while (state != null && state.node != null && !set.contains(state.node)) { + set.mark(state.node); + if (state.merge != null) { + for (IterationState branch : state.merge) { + branch.markAll(set); + } + } + state = state.previous; + } + } + + public void markMasked(NodeBitMap unmasked, NodeBitMap masked) { + IterationState state = this; + while (state != null && state.node != null && !masked.contains(state.node)) { + if (state.node instanceof StateSplit) { + unmasked.mark(state.node); + StateSplit split = (StateSplit) state.node; + if (split.hasSideEffect() && state.previous != null) { + state.previous.markAll(masked); + return; + } + } + + if (state.merge != null) { + for (IterationState branch : state.merge) { + branch.markMasked(unmasked, masked); + } + } + state = state.previous; + } + } } - private static class CollapseFrameForSingleSideEffectClosure extends NodeIteratorClosure { + @Override + protected void run(StructuredGraph graph) { + CollapseFrameForSingleSideEffectClosure closure = new CollapseFrameForSingleSideEffectClosure(); + ReentrantNodeIterator.apply(closure, graph.start(), new IterationState(), null); + closure.finishProcessing(graph); + } + + private static class CollapseFrameForSingleSideEffectClosure extends NodeIteratorClosure { + + private List returnStates = new ArrayList<>(); + private List unwindStates = new ArrayList<>(); @Override - protected StateSplit processNode(FixedNode node, StateSplit currentState) { - StateSplit state = currentState; + protected IterationState processNode(FixedNode node, IterationState currentState) { + IterationState state = currentState; if (node instanceof StateSplit) { StateSplit stateSplit = (StateSplit) node; FrameState frameState = stateSplit.stateAfter(); if (frameState != null) { - // the stateSplit == currentState case comes from merge handling - if (stateSplit.hasSideEffect() || stateSplit == currentState) { + if (stateSplit.hasSideEffect()) { stateSplit.setStateAfter(createInvalidFrameState(node)); - state = stateSplit; - } else if (hasInvalidState(state)) { + state = state.addSideEffect(stateSplit); + } else if (currentState.invalid) { stateSplit.setStateAfter(createInvalidFrameState(node)); } else { stateSplit.setStateAfter(null); @@ -70,53 +140,77 @@ } } } - if (node instanceof ControlSinkNode && state != null) { - state.setStateAfter(node.graph().add(new FrameState(FrameState.AFTER_BCI))); + if (node instanceof ReturnNode) { + returnStates.add(currentState); + } else if (node instanceof UnwindNode) { + unwindStates.add(currentState); } return state; } @Override - protected StateSplit merge(MergeNode merge, List states) { + protected IterationState merge(MergeNode merge, List states) { boolean invalid = false; - for (StateSplit state : states) { - if (state != null && state.stateAfter() != null && state.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) { + for (IterationState state : states) { + if (state.invalid) { invalid = true; - state.setStateAfter(merge.graph().add(new FrameState(FrameState.AFTER_BCI))); + break; } } - if (invalid) { - // at the next processNode call, stateSplit == currentState == merge - return merge; - } else { - return null; + return IterationState.merge(merge, states, invalid); + } + + public void finishProcessing(StructuredGraph graph) { + NodeBitMap maskedSideEffects = new NodeBitMap(graph); + NodeBitMap returnSideEffects = new NodeBitMap(graph); + NodeBitMap unwindSideEffects = new NodeBitMap(graph); + + for (IterationState returnState : returnStates) { + returnState.markMasked(returnSideEffects, maskedSideEffects); + } + for (IterationState unwindState : unwindStates) { + unwindState.markMasked(unwindSideEffects, maskedSideEffects); + } + + for (Node returnSideEffect : returnSideEffects) { + if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) { + StateSplit split = (StateSplit) returnSideEffect; + if (split.getState() != null) { + split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI))); + } + } + } + + for (Node unwindSideEffect : unwindSideEffects) { + if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) { + StateSplit split = (StateSplit) unwindSideEffect; + if (split.getState() != null) { + split.setStateAfter(graph.add(new FrameState(FrameState.AFTER_EXCEPTION_BCI))); + } + } } } @Override - protected StateSplit afterSplit(AbstractBeginNode node, StateSplit oldState) { - return oldState; + protected IterationState afterSplit(AbstractBeginNode node, IterationState oldState) { + return oldState.addBranch(node); } @Override - protected Map processLoop(LoopBeginNode loop, StateSplit initialState) { - LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, initialState); - if (!hasInvalidState(initialState)) { - boolean isNowInvalid = false; - for (StateSplit endState : info.endStates.values()) { - isNowInvalid |= hasInvalidState(endState); - } - if (isNowInvalid) { - loop.setStateAfter(createInvalidFrameState(loop)); - info = ReentrantNodeIterator.processLoop(this, loop, loop); - } + protected Map processLoop(LoopBeginNode loop, IterationState initialState) { + LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, initialState); + + boolean isNowInvalid = initialState.invalid; + for (IterationState endState : info.endStates.values()) { + isNowInvalid |= endState.invalid; } - return info.exitStates; - } - private static boolean hasInvalidState(StateSplit state) { - assert state == null || (state.stateAfter() != null && state.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) : state + " " + state.stateAfter(); - return state != null; + if (isNowInvalid) { + loop.setStateAfter(createInvalidFrameState(loop)); + } + + IterationState endState = IterationState.merge(loop, info.endStates.values(), isNowInvalid); + return ReentrantNodeIterator.processLoop(this, loop, endState).exitStates; } private static FrameState createInvalidFrameState(FixedNode node) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,321 @@ +/* + * 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.replacements; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; +import com.oracle.graal.word.phases.*; + +/** + * A utility for manually creating a graph. This will be expanded as necessary to support all + * subsystems that employ manual graph creation (as opposed to {@linkplain GraphBuilderPhase + * bytecode parsing} based graph creation). + */ +public class GraphKit { + + protected final Providers providers; + protected final StructuredGraph graph; + protected FixedWithNextNode lastFixedNode; + + private final List structures; + + abstract static class Structure { + } + + public GraphKit(StructuredGraph graph, Providers providers) { + this.providers = providers; + this.graph = graph; + this.lastFixedNode = graph.start(); + + structures = new ArrayList<>(); + /* Add a dummy element, so that the access of the last element never leads to an exception. */ + structures.add(new Structure() { + }); + } + + public StructuredGraph getGraph() { + return graph; + } + + /** + * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}. + * + * @return a node similar to {@code node} if one exists, otherwise {@code node} + */ + public T unique(T node) { + return graph.unique(node); + } + + /** + * Appends a fixed node to the graph. + */ + public T append(T node) { + T result = graph.add(node); + assert lastFixedNode != null; + assert result.predecessor() == null; + graph.addAfterFixed(lastFixedNode, result); + if (result instanceof FixedWithNextNode) { + lastFixedNode = (FixedWithNextNode) result; + } else { + lastFixedNode = null; + } + return result; + } + + public InvokeNode createInvoke(Class declaringClass, String name, ValueNode... args) { + return createInvoke(declaringClass, name, InvokeKind.Static, null, FrameState.UNKNOWN_BCI, args); + } + + /** + * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of + * arguments. The method is looked up via reflection based on the declaring class and name. + * + * @param declaringClass the class declaring the invoked method + * @param name the name of the invoked method + * @param args the arguments to the invocation + */ + public InvokeNode createInvoke(Class declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + boolean isStatic = invokeKind == InvokeKind.Static; + ResolvedJavaMethod method = null; + for (Method m : declaringClass.getDeclaredMethods()) { + if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) { + assert method == null : "found more than one method in " + declaringClass + " named " + name; + method = providers.getMetaAccess().lookupJavaMethod(m); + } + } + assert method != null : "did not find method in " + declaringClass + " named " + name; + return createInvoke(method, invokeKind, frameStateBuilder, bci, args); + } + + /** + * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of + * arguments. + */ + public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + assert Modifier.isStatic(method.getModifiers()) == (invokeKind == InvokeKind.Static); + Signature signature = method.getSignature(); + JavaType returnType = signature.getReturnType(null); + assert checkArgs(method, args); + MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnType, bci)); + InvokeNode invoke = append(new InvokeNode(callTarget, bci)); + + if (frameStateBuilder != null) { + if (invoke.kind() != Kind.Void) { + frameStateBuilder.push(invoke.kind(), invoke); + } + invoke.setStateAfter(frameStateBuilder.create(0)); + if (invoke.kind() != Kind.Void) { + frameStateBuilder.pop(invoke.kind()); + } + } + return invoke; + } + + protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType, @SuppressWarnings("unused") int bci) { + return new MethodCallTargetNode(invokeKind, targetMethod, args, returnType); + } + + /** + * Determines if a given set of arguments is compatible with the signature of a given method. + * + * @return true if {@code args} are compatible with the signature if {@code method} + * @throws AssertionError if {@code args} are not compatible with the signature if + * {@code method} + */ + public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) { + Signature signature = method.getSignature(); + boolean isStatic = Modifier.isStatic(method.getModifiers()); + if (signature.getParameterCount(!isStatic) != args.length) { + throw new AssertionError(graph + ": wrong number of arguments to " + method); + } + int paramNum = 0; + for (int i = 0; i != args.length; i++) { + Kind expected; + if (i == 0 && !isStatic) { + expected = Kind.Object; + } else { + expected = signature.getParameterKind(paramNum++).getStackKind(); + } + Kind actual = args[i].stamp().getStackKind(); + if (expected != actual) { + throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]"); + } + } + return true; + } + + /** + * Rewrite all word types in the graph. + */ + public void rewriteWordTypes() { + new WordTypeRewriterPhase(providers.getMetaAccess(), providers.getCodeCache().getTarget().wordKind).apply(graph); + } + + /** + * {@linkplain #inline(InvokeNode) Inlines} all invocations currently in the graph. + */ + public void inlineInvokes() { + for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) { + inline(invoke); + } + + // Clean up all code that is now dead after inlining. + new DeadCodeEliminationPhase().apply(graph); + assert graph.getNodes().filter(InvokeNode.class).isEmpty(); + } + + /** + * Inlines a given invocation to a method. The graph of the inlined method is + * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and + * method substitutions. + */ + public void inline(InvokeNode invoke) { + ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); + ReplacementsImpl repl = new ReplacementsImpl(providers, new Assumptions(false), providers.getCodeCache().getTarget()); + StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + InliningUtil.inline(invoke, calleeGraph, false); + } + + protected void pushStructure(Structure structure) { + structures.add(structure); + } + + protected T getTopStructure(Class expectedClass) { + return expectedClass.cast(structures.get(structures.size() - 1)); + } + + protected void popStructure() { + structures.remove(structures.size() - 1); + } + + protected enum IfState { + CONDITION, THEN_PART, ELSE_PART, FINISHED + } + + static class IfStructure extends Structure { + protected IfState state; + protected FixedNode thenPart; + protected FixedNode elsePart; + } + + /** + * Starts an if-block. This call can be followed by a call to {@link #thenPart} to start + * emitting the code executed when the condition hold; and a call to {@link #elsePart} to start + * emititng the code when the condition does not hold. It must be followed by a call to + * {@link #endIf} to close the if-block. + * + * @param condition The condition for the if-block + * @param trueProbability The estimated probability the the condition is true + */ + public void startIf(LogicNode condition, double trueProbability) { + BeginNode thenSuccessor = graph.add(new BeginNode()); + BeginNode elseSuccessor = graph.add(new BeginNode()); + append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability)); + lastFixedNode = null; + + IfStructure s = new IfStructure(); + s.state = IfState.CONDITION; + s.thenPart = thenSuccessor; + s.elsePart = elseSuccessor; + pushStructure(s); + } + + private IfStructure saveLastNode() { + IfStructure s = getTopStructure(IfStructure.class); + switch (s.state) { + case CONDITION: + assert lastFixedNode == null; + break; + case THEN_PART: + s.thenPart = lastFixedNode; + break; + case ELSE_PART: + s.elsePart = lastFixedNode; + break; + case FINISHED: + assert false; + break; + } + lastFixedNode = null; + return s; + } + + public void thenPart() { + IfStructure s = saveLastNode(); + lastFixedNode = (FixedWithNextNode) s.thenPart; + s.state = IfState.THEN_PART; + } + + public void elsePart() { + IfStructure s = saveLastNode(); + lastFixedNode = (FixedWithNextNode) s.elsePart; + s.state = IfState.ELSE_PART; + } + + public void endIf() { + IfStructure s = saveLastNode(); + + FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null; + FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null; + + if (thenPart != null && elsePart != null) { + /* Both parts are alive, we need a real merge. */ + EndNode thenEnd = graph.add(new EndNode()); + graph.addAfterFixed(thenPart, thenEnd); + EndNode elseEnd = graph.add(new EndNode()); + graph.addAfterFixed(elsePart, elseEnd); + + MergeNode merge = graph.add(new MergeNode()); + merge.addForwardEnd(thenEnd); + merge.addForwardEnd(elseEnd); + + lastFixedNode = merge; + + } else if (thenPart != null) { + /* elsePart ended with a control sink, so we can continue with thenPart. */ + lastFixedNode = thenPart; + + } else if (elsePart != null) { + /* thenPart ended with a control sink, so we can continue with elsePart. */ + lastFixedNode = elsePart; + + } else { + /* Both parts ended with a control sink, so no nodes can be added after the if. */ + assert lastFixedNode == null; + } + s.state = IfState.FINISHED; + popStructure(); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -64,12 +64,12 @@ @MethodSubstitution private static Node getNode(Node node, long offset) { - return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), Node.class, false, false); + return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), Node.class); } @MethodSubstitution private static NodeList getNodeList(Node node, long offset) { - return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), NodeList.class, false, false); + return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), NodeList.class); } @MethodSubstitution diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Mar 05 19:40:15 2014 -0800 @@ -133,9 +133,12 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graphs.putIfAbsent(substitute, makeGraph(substitute, original, substitute, inliningPolicy(substitute), FrameStateProcessing.None)); + graph = makeGraph(substitute, original, substitute, inliningPolicy(substitute), FrameStateProcessing.None); + graph.freeze(); + graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); } + assert graph.isFrozen(); return graph; } @@ -198,7 +201,9 @@ } } } - if (macroSubstitution != null) { + // We don't have per method guards for macro substitutions but at least respect the + // defaultGuard if there is one. + if (macroSubstitution != null && (defaultGuard == null || defaultGuard.execute())) { String originalName = originalName(substituteMethod, macroSubstitution.value()); JavaSignature originalSignature = originalSignature(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalSignature); diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 { @@ -569,11 +576,7 @@ LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase(true)); new CanonicalizerPhase(true).applyIncremental(snippetCopy, phaseContext, mark); } - FixedNode explodeLoopNext = explodeLoop.next(); - explodeLoop.clearSuccessors(); - explodeLoop.replaceAtPredecessor(explodeLoopNext); - explodeLoop.replaceAtUsages(null); - GraphUtil.killCFG(explodeLoop); + GraphUtil.removeFixedWithUnusedInputs(explodeLoop); exploded = true; } } while (exploded); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -66,9 +66,9 @@ return true; } - final char[] thisArray = (char[]) unsafe.getObject(thisString, valueOffset); - final char[] thatArray = (char[]) unsafe.getObject(thatString, valueOffset); + final char[] array1 = (char[]) unsafe.getObject(thisString, valueOffset); + final char[] array2 = (char[]) unsafe.getObject(thatString, valueOffset); - return CharArrayEqualsNode.equals(thisArray, thatArray, thisArray.length); + return ArrayEqualsNode.equals(array1, array2, array1.length); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,137 @@ +/* + * 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.graal.replacements.nodes; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; + +/** + * Compares two arrays with the same length. + */ +public class ArrayEqualsNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + /** {@link Kind} of the arrays to compare. */ + private final Kind kind; + + /** One array to be tested for equality. */ + @Input private ValueNode array1; + + /** The other array to be tested for equality. */ + @Input private ValueNode array2; + + /** Length of both arrays. */ + @Input private ValueNode length; + + public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length) { + super(StampFactory.forKind(Kind.Boolean)); + + assert array1.stamp().equals(array2.stamp()); + ObjectStamp stamp = (ObjectStamp) array1.stamp(); + ResolvedJavaType componentType = stamp.type().getComponentType(); + this.kind = componentType.getKind(); + + this.array1 = array1; + this.array2 = array2; + this.length = length; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (!array1.isConstant() || !array2.isConstant()) { + return this; + } + + Object a1 = array1.asConstant().asObject(); + Object a2 = array2.asConstant().asObject(); + boolean x; + switch (kind) { + case Boolean: + x = Arrays.equals((boolean[]) a1, (boolean[]) a2); + break; + case Byte: + x = Arrays.equals((byte[]) a1, (byte[]) a2); + break; + case Char: + x = Arrays.equals((char[]) a1, (char[]) a2); + break; + case Short: + x = Arrays.equals((short[]) a1, (short[]) a2); + break; + case Int: + x = Arrays.equals((int[]) a1, (int[]) a2); + break; + case Long: + x = Arrays.equals((long[]) a1, (long[]) a2); + break; + case Float: + x = Arrays.equals((float[]) a1, (float[]) a2); + break; + case Double: + x = Arrays.equals((double[]) a1, (double[]) a2); + break; + default: + throw GraalInternalError.shouldNotReachHere("unknown kind " + kind); + } + return ConstantNode.forBoolean(x, graph()); + } + + @NodeIntrinsic + public static native boolean equals(boolean[] array1, boolean[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(byte[] array1, byte[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(char[] array1, char[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(short[] array1, short[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(int[] array1, int[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(long[] array1, long[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(float[] array1, float[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(double[] array1, double[] array2, int length); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Int); + gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length)); + gen.setResult(this, result); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -37,18 +37,18 @@ @Input private ValueNode value; public BitCountNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits())); this.value = value; } @Override public Node canonical(CanonicalizerTool tool) { if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.bitCount((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(Long.bitCount(v), graph()); + Constant c = value.asConstant(); + if (c.getKind() == Kind.Int) { + return ConstantNode.forInt(Integer.bitCount(c.asInt()), graph()); + } else if (c.getKind() == Kind.Long) { + return ConstantNode.forInt(Long.bitCount(c.asLong()), graph()); } } return this; diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -37,18 +37,18 @@ @Input private ValueNode value; public BitScanForwardNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits())); this.value = value; } @Override public Node canonical(CanonicalizerTool tool) { if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.numberOfTrailingZeros((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(Long.numberOfTrailingZeros(v), graph()); + Constant c = value.asConstant(); + if (c.getKind() == Kind.Int) { + return ConstantNode.forInt(Integer.numberOfTrailingZeros(c.asInt()), graph()); + } else if (c.getKind() == Kind.Long) { + return ConstantNode.forInt(Long.numberOfTrailingZeros(c.asLong()), graph()); } } return this; @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -37,18 +37,18 @@ @Input private ValueNode value; public BitScanReverseNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits())); this.value = value; } @Override public Node canonical(CanonicalizerTool tool) { if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(v), graph()); + Constant c = value.asConstant(); + if (c.getKind() == Kind.Int) { + return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros(c.asInt()), graph()); + } else if (c.getKind() == Kind.Long) { + return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(c.asLong()), graph()); } } return this; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/CharArrayEqualsNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/CharArrayEqualsNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +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.graal.replacements.nodes; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.type.*; - -/** - * Compares two {@code char} arrays with the same length. - */ -public class CharArrayEqualsNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode thisArray; - @Input private ValueNode thatArray; - @Input private ValueNode length; - - public CharArrayEqualsNode(ValueNode thisArray, ValueNode thatArray, ValueNode length) { - super(StampFactory.forKind(Kind.Boolean)); - this.thisArray = thisArray; - this.thatArray = thatArray; - this.length = length; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (thisArray.isConstant() && thatArray.isConstant()) { - char[] array1 = (char[]) thisArray.asConstant().asObject(); - char[] array2 = (char[]) thatArray.asConstant().asObject(); - final boolean result = Arrays.equals(array1, array2); - return ConstantNode.forBoolean(result, graph()); - } - return this; - } - - @NodeIntrinsic - public static native boolean equals(char[] thisArray, char[] thatArray, int length); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Boolean); - gen.emitCharArrayEquals(result, gen.operand(thisArray), gen.operand(thatArray), gen.operand(length)); - gen.setResult(this, result); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,8 +24,6 @@ import static java.lang.reflect.Modifier.*; -import java.lang.reflect.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -47,6 +45,7 @@ private final int bci; private final ResolvedJavaMethod targetMethod; private final JavaType returnType; + private final InvokeKind invokeKind; protected MacroNode(Invoke invoke) { super(invoke.asNode().stamp(), invoke.stateAfter()); @@ -55,6 +54,7 @@ this.bci = invoke.bci(); this.targetMethod = methodCallTarget.targetMethod(); this.returnType = methodCallTarget.returnType(); + this.invokeKind = methodCallTarget.invokeKind(); } public int getBci() { @@ -148,17 +148,21 @@ } } - private InvokeNode replaceWithInvoke() { + protected InvokeNode replaceWithInvoke() { InvokeNode invoke = createInvoke(); graph().replaceFixedWithFixed(this, invoke); return invoke; } protected InvokeNode createInvoke() { - InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special; MethodCallTargetNode callTarget = graph().add(new MethodCallTargetNode(invokeKind, targetMethod, arguments.toArray(new ValueNode[arguments.size()]), returnType)); InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci)); - invoke.setStateAfter(stateAfter()); + if (stateAfter() != null) { + invoke.setStateAfter(stateAfter().duplicate()); + if (kind() != Kind.Void) { + invoke.stateAfter().replaceFirstInput(this, invoke); + } + } return invoke; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -48,8 +48,8 @@ } public MathIntrinsicNode(ValueNode x, Operation op) { - super(StampFactory.forKind(x.kind())); - assert x.kind() == Kind.Double; + super(StampFactory.forKind(Kind.Double)); + assert x.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(x.stamp()) == 64; this.x = x; this.operation = op; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java --- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.test; import java.lang.reflect.*; +import java.util.*; import org.junit.*; import org.junit.runner.*; @@ -36,8 +37,12 @@ public class GraalTest { protected Method getMethod(String methodName) { + return getMethod(getClass(), methodName); + } + + protected Method getMethod(Class clazz, String methodName) { Method found = null; - for (Method m : this.getClass().getMethods()) { + for (Method m : clazz.getMethods()) { if (m.getName().equals(methodName)) { Assert.assertNull(found); found = m; @@ -49,4 +54,12 @@ throw new RuntimeException("method not found: " + methodName); } } + + protected Method getMethod(Class clazz, String methodName, Class[] parameterTypes) { + try { + return clazz.getMethod(methodName, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("method not found: " + methodName + "" + Arrays.toString(parameterTypes)); + } + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java Wed Mar 05 19:40:15 2014 -0800 @@ -41,7 +41,7 @@ @ServiceProvider(OptimizedCallTargetInstrumentationFactory.class) public class AMD64OptimizedCallTargetInstrumentationFactory implements OptimizedCallTargetInstrumentationFactory { - public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, + public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext, CompilationResult compilationResult) { return new OptimizedCallTargetInstrumentation(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult) { @Override @@ -51,14 +51,14 @@ Register thisRegister = codeCache.getRegisterConfig().getCallingConventionRegisters(Type.JavaCall, Kind.Object)[0]; Register spillRegister = AMD64.r10; // TODO(mg): fix me AMD64Address nMethodAddress = new AMD64Address(thisRegister, getFieldOffset("installedCode", OptimizedCallTarget.class)); - int verifiedEntryPoint = asm.codeBuffer.position(); + int verifiedEntryPoint = asm.position(); if (config.useCompressedOops) { asm.movl(spillRegister, nMethodAddress); - asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.codeBuffer.position() - verifiedEntryPoint)); + asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.position() - verifiedEntryPoint)); AMD64HotSpotMove.decodePointer(asm, spillRegister, registers.getHeapBaseRegister(), config.getOopEncoding()); } else { asm.movq(spillRegister, nMethodAddress); - asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.codeBuffer.position() - verifiedEntryPoint)); + asm.nop(AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE - (asm.position() - verifiedEntryPoint)); } Label doProlog = new Label(); @@ -81,7 +81,7 @@ public void setInstrumentedMethod(ResolvedJavaMethod method) { HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; - hsMethod.setDontInline(); + hsMethod.setNotInlineable(); } public String getArchitecture() { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java Wed Mar 05 19:40:15 2014 -0800 @@ -43,7 +43,7 @@ */ public abstract class OptimizedCallTargetInstrumentation extends CompilationResultBuilder { - public OptimizedCallTargetInstrumentation(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, + public OptimizedCallTargetInstrumentation(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, FrameContext frameContext, CompilationResult compilationResult) { super(codeCache, foreignCalls, frameMap, asm, frameContext, compilationResult); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,102 @@ +/* + * 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.test; + +import org.junit.*; + +import com.oracle.graal.truffle.test.nodes.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +@Ignore("Currently ignored due to problems with code coverage tools.") +public class ControlFlowExceptionPartialEvaluationTest extends PartialEvaluationTest { + + public static Object constant42() { + return 42; + } + + @Test + public void catchControlFlowException() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new CatchControlFlowExceptionTestNode(new ThrowControlFlowExceptionTestNode()); + assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchControlFlowException", result)); + } + + @Test + public void catchSlowPathAndControlFlowException() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new CatchSlowPathAndControlFlowExceptionTestNode(new ThrowControlFlowExceptionTestNode()); + assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchSlowPathAndControlFlowException", result)); + } + + public static class ThrowControlFlowExceptionTestNode extends AbstractTestNode { + + @Override + public int execute(VirtualFrame frame) { + throw new ControlFlowException(); + } + } + + public static class CatchControlFlowExceptionTestNode extends AbstractTestNode { + + @Child private AbstractTestNode child; + + public CatchControlFlowExceptionTestNode(AbstractTestNode child) { + this.child = adoptChild(child); + } + + @Override + public int execute(VirtualFrame frame) { + try { + return child.execute(frame); + } catch (ControlFlowException e) { + return 42; + } + } + } + + public static class CatchSlowPathAndControlFlowExceptionTestNode extends AbstractTestNode { + + @Child private AbstractTestNode child; + + public CatchSlowPathAndControlFlowExceptionTestNode(AbstractTestNode child) { + this.child = adoptChild(child); + } + + @Override + public int execute(VirtualFrame frame) { + try { + return executeChild(frame); + } catch (SlowPathException spe) { + return -1; + } catch (ControlFlowException e) { + return 42; + } + } + + @SuppressWarnings("unused") + private int executeChild(VirtualFrame frame) throws SlowPathException { + return child.execute(frame); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,7 +27,6 @@ import org.junit.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -39,9 +38,7 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; import com.oracle.graal.printer.*; -import com.oracle.graal.runtime.*; import com.oracle.graal.truffle.*; import com.oracle.graal.virtual.phases.ea.*; import com.oracle.truffle.api.*; @@ -50,15 +47,12 @@ public class PartialEvaluationTest extends GraalCompilerTest { private static final long UNROLL_LIMIT = 100; - private final PartialEvaluator partialEvaluator; + private final TruffleCompilerImpl truffleCompiler; public PartialEvaluationTest() { // Make sure Truffle runtime is initialized. Assert.assertTrue(Truffle.getRuntime() instanceof GraalTruffleRuntime); - Replacements truffleReplacements = ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements(); - Providers providers = getProviders().copyWith(truffleReplacements); - TruffleCache truffleCache = new TruffleCache(providers, GraphBuilderConfiguration.getDefault(), TruffleCompilerImpl.Optimizations); - this.partialEvaluator = new PartialEvaluator(Graal.getRequiredCapability(RuntimeProvider.class), providers, truffleCache); + this.truffleCompiler = new TruffleCompilerImpl(); DebugEnvironment.initialize(System.out); } @@ -70,7 +64,7 @@ protected InstalledCode assertPartialEvalEquals(String methodName, RootNode root, Arguments arguments) { Assumptions assumptions = new Assumptions(true); StructuredGraph actual = partialEval(root, arguments, assumptions, true); - InstalledCode result = new TruffleCompilerImpl().compileMethodHelper(actual, GraphBuilderConfiguration.getDefault(), assumptions, root.toString()); + InstalledCode result = truffleCompiler.compileMethodHelper(actual, assumptions, root.toString(), getSpeculationLog()); StructuredGraph expected = parseForComparison(methodName); removeFrameStates(actual); Assert.assertEquals(getCanonicalGraphString(expected, true), getCanonicalGraphString(actual, true)); @@ -94,15 +88,14 @@ final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root); // Executed AST so that all classes are loaded and initialized. - do { - compilable.call(null, arguments); - compilable.call(null, arguments); - compilable.call(null, arguments); - } while (compilable.inline()); + compilable.call(null, arguments); + compilable.call(null, arguments); + compilable.call(null, arguments); + compilable.performInlining(); try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) { - StructuredGraph resultGraph = partialEvaluator.createGraph(compilable, assumptions); + StructuredGraph resultGraph = truffleCompiler.getPartialEvaluator().createGraph(compilable, assumptions); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(canonicalizeReads); PhaseContext context = new PhaseContext(getProviders(), assumptions); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,11 +24,10 @@ import static com.oracle.graal.truffle.TruffleCompilerOptions.*; +import java.util.*; + public class CompilationProfile { - private int invokeCounter; - private int originalInvokeCounter; - private int loopAndInvokeCounter; /** * Number of times an installed code for this tree was invalidated. */ @@ -41,17 +40,41 @@ private long previousTimestamp; - private final int compilationThreshold; private final String name; + private int callCount; + private int callAndLoopCount; + private int compilationCallThreshold; + private int compilationCallAndLoopThreshold; + + private final int originalInvokeCounter; + private final int originalCompilationThreshold; + public CompilationProfile(final int compilationThreshold, final int initialInvokeCounter, final String name) { - this.invokeCounter = initialInvokeCounter; - this.loopAndInvokeCounter = compilationThreshold; - this.originalInvokeCounter = compilationThreshold; this.previousTimestamp = System.nanoTime(); + this.compilationCallThreshold = initialInvokeCounter; + this.compilationCallAndLoopThreshold = compilationThreshold; + this.originalInvokeCounter = initialInvokeCounter; + this.originalCompilationThreshold = compilationThreshold; + this.name = name; + } - this.compilationThreshold = compilationThreshold; - this.name = name; + public Map getDebugProperties() { + Map properties = new LinkedHashMap<>(); + String callsThreshold = String.format("%7d/%5d", getCallCount(), getCompilationCallThreshold()); + String loopsThreshold = String.format("%7d/%5d", getCallAndLoopCount(), getCompilationCallAndLoopThreshold()); + String invalidationReplace = String.format("%5d/%5d", invalidationCount, nodeReplaceCount); + properties.put("C/T", callsThreshold); + properties.put("L/T", loopsThreshold); + properties.put("Inval#/Replace#", invalidationReplace); + return properties; + } + + public void reset() { + callCount = 0; + callAndLoopCount = 0; + compilationCallAndLoopThreshold = originalCompilationThreshold; + compilationCallThreshold = originalInvokeCounter; } public long getPreviousTimestamp() { @@ -70,54 +93,64 @@ return nodeReplaceCount; } - public int getInvokeCounter() { - return invokeCounter; + public int getCallAndLoopCount() { + return callAndLoopCount; + } + + public int getCallCount() { + return callCount; + } + + public int getCompilationCallAndLoopThreshold() { + return compilationCallAndLoopThreshold; } - public int getOriginalInvokeCounter() { - return originalInvokeCounter; + public int getCompilationCallThreshold() { + return compilationCallThreshold; } - public int getLoopAndInvokeCounter() { - return loopAndInvokeCounter; + void ensureProfiling(int calls, int callsAndLoop) { + int increaseCallAndLoopThreshold = callsAndLoop - (this.compilationCallAndLoopThreshold - this.callAndLoopCount); + if (increaseCallAndLoopThreshold > 0) { + this.compilationCallAndLoopThreshold += increaseCallAndLoopThreshold; + } + + int increaseCallsThreshold = calls - (this.compilationCallThreshold - this.callCount); + if (increaseCallsThreshold > 0) { + this.compilationCallThreshold += increaseCallsThreshold; + } } void reportTiminingFailed(long timestamp) { - this.loopAndInvokeCounter = compilationThreshold; - this.originalInvokeCounter = compilationThreshold; + ensureProfiling(0, originalCompilationThreshold); this.previousTimestamp = timestamp; } void reportInvalidated() { invalidationCount++; - int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue(); - invokeCounter = invalidationReprofileCount; - originalInvokeCounter += invalidationReprofileCount; + int reprofile = TruffleInvalidationReprofileCount.getValue(); + ensureProfiling(reprofile, reprofile); } void reportInterpreterCall() { - invokeCounter--; - loopAndInvokeCounter--; + callCount++; + callAndLoopCount++; } - void reportInliningPerformed(TruffleInlining inlining) { - invokeCounter = inlining.getInvocationReprofileCount(); - int inliningReprofileCount = inlining.getReprofileCount(); - loopAndInvokeCounter = inliningReprofileCount; - originalInvokeCounter = inliningReprofileCount; + void reportInterpreterCalls(int calls) { + this.callCount += calls; + this.callAndLoopCount += calls; } void reportLoopCount(int count) { - loopAndInvokeCounter = Math.max(0, loopAndInvokeCounter - count); + callAndLoopCount += count; } void reportNodeReplaced() { nodeReplaceCount++; // delay compilation until tree is deemed stable enough int replaceBackoff = TruffleReplaceReprofileCount.getValue(); - if (loopAndInvokeCounter < replaceBackoff) { - loopAndInvokeCounter = replaceBackoff; - } + ensureProfiling(1, replaceBackoff); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultCompilationPolicy.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultCompilationPolicy.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultCompilationPolicy.java Wed Mar 05 19:40:15 2014 -0800 @@ -25,7 +25,7 @@ public class DefaultCompilationPolicy implements CompilationPolicy { public boolean shouldCompile(CompilationProfile profile) { - return profile.getInvokeCounter() <= 0 && profile.getLoopAndInvokeCounter() <= 0; + return profile.getCallCount() >= profile.getCompilationCallThreshold() && profile.getCallAndLoopCount() >= profile.getCompilationCallAndLoopThreshold(); } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Wed Mar 05 19:40:15 2014 -0800 @@ -73,14 +73,19 @@ return "Graal Truffle Runtime"; } - public CallTarget createCallTarget(RootNode rootNode) { - if (!acceptForCompilation(rootNode)) { - return new DefaultCallTarget(rootNode); - } + public RootCallTarget createCallTarget(RootNode 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)); + } + + public CallNode createCallNode(CallTarget target) { + if (target instanceof OptimizedCallTarget) { + return OptimizedCallNode.create((OptimizedCallTarget) target); + } else { + return new DefaultCallNode(target); + } } @Override @@ -198,8 +203,8 @@ CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); CompilationResultBuilderFactory factory = getOptimizedCallTargetInstrumentationFactory(backend.getTarget().arch.getName(), javaMethod); - return compileGraph(graph, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), - new SpeculationLog(), suites, true, new CompilationResult(), factory); + return compileGraph(graph, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null, + suites, true, new CompilationResult(), factory); } private static Providers getGraalProviders() { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,292 @@ +/* + * 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 java.util.concurrent.atomic.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; + +/** + * Call target that is optimized by Graal upon surpassing a specific invocation threshold. + */ +abstract class OptimizedCallNode extends DefaultCallNode { + + protected int callCount; + + private OptimizedCallNode(OptimizedCallTarget target) { + super(target); + } + + @Override + public final boolean isSplittable() { + return getCallTarget().getRootNode().isSplittable(); + } + + @Override + public final OptimizedCallTarget getCallTarget() { + return (OptimizedCallTarget) super.getCallTarget(); + } + + public final int getCallCount() { + return callCount; + } + + public TruffleInliningProfile createInliningProfile(OptimizedCallTarget target) { + return new OptimizedCallNodeProfile(target, this); + } + + @SuppressWarnings("unused") + public void nodeReplaced(Node oldNode, Node newNode, String reason) { + } + + @Override + public final OptimizedCallTarget getCurrentCallTarget() { + return (OptimizedCallTarget) super.getCurrentCallTarget(); + } + + @Override + public OptimizedCallTarget getSplitCallTarget() { + return null; + } + + protected OptimizedCallNode inlineImpl() { + if (getParent() == null) { + throw new IllegalStateException("CallNode must be adopted before it is split."); + } + + return replace(new InlinedOptimizedCallNode(getCallTarget(), getSplitCallTarget(), getCurrentCallTarget().getRootNode(), callCount)); + } + + public static OptimizedCallNode create(OptimizedCallTarget target) { + return new DefaultOptimizedCallNode(target); + } + + private static final class DefaultOptimizedCallNode extends OptimizedCallNode { + + private boolean trySplit = true; + + DefaultOptimizedCallNode(OptimizedCallTarget target) { + super(target); + registerCallTarget(this); + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + if (CompilerDirectives.inInterpreter()) { + callCount++; + if (trySplit && callCount > 1) { + trySplit = false; + return trySplit(caller, arguments); + } + } + return callTarget.call(caller, arguments); + } + + private Object trySplit(PackedFrame caller, Arguments arguments) { + if (shouldSplit()) { + return splitImpl(true).call(caller, arguments); + } + return callTarget.call(caller, arguments); + } + + private boolean shouldSplit() { + if (!TruffleCompilerOptions.TruffleSplittingEnabled.getValue()) { + return false; + } + if (!isSplittable()) { + return false; + } + int nodeCount = NodeUtil.countNodes(getCallTarget().getRootNode(), null, false); + if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { + return false; + } + + // // is the only call target -> do not split + // if (getCallTarget().getRootNode().getCachedCallNodes().size() == 1 && + // getCallTarget().getRootNode().getCachedCallNodes().contains(this)) { + // return false; + // } + + // max one child call and callCount > 2 and kind of small number of nodes + if (isMaxSingleCall()) { + return true; + } + return countPolymorphic() >= 1 || countGeneric() > 0; + } + + @Override + public void nodeReplaced(Node oldNode, Node newNode, String reason) { + trySplit = true; + } + + @Override + protected void notifyCallNodeAdded() { + trySplit = true; + } + + private boolean isMaxSingleCall() { + final AtomicInteger count = new AtomicInteger(0); + getCurrentCallTarget().getRootNode().accept(new NodeVisitor() { + + public boolean visit(Node node) { + if (node instanceof CallNode) { + return count.incrementAndGet() > 1; + } + return true; + } + }); + return count.get() <= 1; + } + + private int countPolymorphic() { + return NodeUtil.countNodes(getCallTarget().getRootNode(), null, Kind.POLYMORPHIC, false); + } + + private int countGeneric() { + return NodeUtil.countNodes(getCallTarget().getRootNode(), null, Kind.GENERIC, false); + } + + @Override + public boolean isInlined() { + return false; + } + + @Override + public boolean split() { + if (!isSplittable()) { + // split is only allowed once and if the root node supports it + return false; + } + if (getParent() == null) { + throw new IllegalStateException("CallNode must be adopted before it is split."); + } + splitImpl(false); + return true; + } + + private OptimizedCallNode splitImpl(boolean heuristic) { + OptimizedCallTarget splitCallTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(getCallTarget().getRootNode().split()); + splitCallTarget.setSplitSource(getCallTarget()); + if (heuristic) { + OptimizedCallTarget.logSplit(this, getCallTarget(), splitCallTarget); + } + return replace(new SplitOptimizedCallNode(getCallTarget(), splitCallTarget, callCount)); + } + + @Override + public void inline() { + inlineImpl(); + } + + @Override + public OptimizedCallTarget getSplitCallTarget() { + return null; + } + + } + + private static final class InlinedOptimizedCallNode extends OptimizedCallNode { + + private final RootNode inlinedRoot; + private final OptimizedCallTarget splittedTarget; + + public InlinedOptimizedCallNode(OptimizedCallTarget target, OptimizedCallTarget splittedTarget, RootNode inlinedRoot, int callCount) { + super(target); + this.inlinedRoot = inlinedRoot; + this.splittedTarget = splittedTarget; + this.callCount = callCount; + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + if (CompilerDirectives.inInterpreter()) { + callCount++; + } + return inlinedRoot.execute(Truffle.getRuntime().createVirtualFrame(caller, arguments, inlinedRoot.getFrameDescriptor())); + } + + @Override + public void inline() { + } + + @Override + public boolean split() { + return false; + } + + @Override + public boolean isInlined() { + return true; + } + + @Override + public OptimizedCallTarget getSplitCallTarget() { + return splittedTarget; + } + } + + private static class SplitOptimizedCallNode extends OptimizedCallNode { + + private final OptimizedCallTarget splittedTarget; + + public SplitOptimizedCallNode(OptimizedCallTarget target, OptimizedCallTarget splittedTarget, int callCount) { + super(target); + this.callCount = callCount; + this.splittedTarget = splittedTarget; + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + if (CompilerDirectives.inInterpreter()) { + callCount++; + } + return splittedTarget.call(caller, arguments); + } + + @Override + public boolean isInlined() { + return false; + } + + @Override + public final boolean split() { + return false; + } + + @Override + public void inline() { + inlineImpl(); + } + + @Override + public final OptimizedCallTarget getSplitCallTarget() { + return splittedTarget; + } + + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNodeProfile.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,229 @@ +/* + * 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 static com.oracle.graal.truffle.TruffleCompilerOptions.*; + +import java.util.*; + +import com.oracle.truffle.api.nodes.*; + +public class OptimizedCallNodeProfile implements TruffleInliningProfile { + + private static final String REASON_RECURSION = "recursion"; + private static final String REASON_FREQUENCY_CUTOFF = "frequency < " + TruffleInliningMinFrequency.getValue(); + private static final String REASON_MAXIMUM_NODE_COUNT = "shallowTargetCount > " + TruffleInliningMaxCalleeSize.getValue(); + private static final String REASON_MAXIMUM_TOTAL_NODE_COUNT = "inlinedTotalCount > " + TruffleInliningMaxCallerSize.getValue(); + + private final OptimizedCallTarget callTarget; + private final OptimizedCallNode callNode; + + private int targetDeepNodeCount; + private List compilationRoots; + private final int targetShallowNodeCount; + private final double averageFrequency; + private final double score; + private String reason; + + public OptimizedCallNodeProfile(OptimizedCallTarget target, OptimizedCallNode callNode) { + this.callNode = callNode; + RootNode inlineRoot = callNode.getCurrentCallTarget().getRootNode(); + this.callTarget = target; + this.targetShallowNodeCount = NodeUtil.countNodes(inlineRoot, null, false); + this.targetDeepNodeCount = NodeUtil.countNodes(inlineRoot, null, true); + this.compilationRoots = findCompilationRoots(callNode); + this.averageFrequency = calculateFrequency(); + this.score = calculateScore(); + } + + private double calculateFrequency() { + return calculateAdvancedFrequency(); + } + + public OptimizedCallNode getCallNode() { + return callNode; + } + + public double getScore() { + return score; + } + + public double calculateScore() { + return averageFrequency / targetDeepNodeCount; + } + + public boolean isInliningAllowed() { + this.compilationRoots = findCompilationRoots(getCallNode()); + + OptimizedCallTarget inlineTarget = callNode.getCurrentCallTarget(); + for (OptimizedCallTarget compilationRoot : compilationRoots) { + if (compilationRoot == inlineTarget) { + // recursive call found + reason = REASON_RECURSION; + return false; + } + } + + // frequency cut-off + if (averageFrequency < TruffleInliningMinFrequency.getValue() && targetDeepNodeCount > TruffleInliningTrivialSize.getValue()) { + reason = REASON_FREQUENCY_CUTOFF; + return false; + } + + if (targetShallowNodeCount > TruffleInliningMaxCalleeSize.getValue()) { + reason = REASON_MAXIMUM_NODE_COUNT; + return false; + } + + this.targetDeepNodeCount = NodeUtil.countNodes(inlineTarget.getRootNode(), null, true); + // The maximum total node count cannot be cached since it may change during inlining. + int nextNodeCount = calculateInlinedTotalNodeCount(getCallNode()); + if (nextNodeCount > TruffleInliningMaxCallerSize.getValue()) { + reason = REASON_MAXIMUM_TOTAL_NODE_COUNT; + return false; + } + + return true; + } + + private int calculateInlinedTotalNodeCount(OptimizedCallNode node) { + int currentNodeCount = 0; + for (OptimizedCallTarget compilationRoot : compilationRoots) { + TotalNodeCountVisitor visitor = new TotalNodeCountVisitor(node, targetDeepNodeCount); + compilationRoot.getRootNode().accept(visitor); + currentNodeCount = Math.max(currentNodeCount, visitor.count); + } + return currentNodeCount; + } + + private static class TotalNodeCountVisitor implements NodeVisitor { + + private final OptimizedCallNode inlinedNode; + private final int inlinedNodeCount; + + private int count; + + public TotalNodeCountVisitor(OptimizedCallNode inlinedNode, int inlinedNodeCount) { + this.inlinedNode = inlinedNode; + this.inlinedNodeCount = inlinedNodeCount; + } + + public boolean visit(Node node) { + count++; + if (node instanceof OptimizedCallNode) { + OptimizedCallNode callNode = ((OptimizedCallNode) node); + if (callNode == inlinedNode) { + count += inlinedNodeCount; + } else if (callNode.isInlined()) { + callNode.getCurrentRootNode().accept(this); + } + } + return true; + } + + } + + double calculateAdvancedFrequency() { + // get the call hierarchy from call target to the call node + final ArrayDeque callStack = new ArrayDeque<>(); + callTarget.getRootNode().accept(new NodeVisitor() { + private boolean found = false; + + public boolean visit(Node node) { + if (node == callNode) { + // found our call + callStack.push((OptimizedCallNode) node); + found = true; + return false; + } + + if (node instanceof OptimizedCallNode) { + OptimizedCallNode c = ((OptimizedCallNode) node); + if (c.isInlined()) { + if (!found) { + callStack.push(c); + } + c.getCurrentRootNode().accept(this); + if (!found) { + callStack.pop(); + } + } + } + return !found; + } + }); + + int parentCallCount = callTarget.getCompilationProfile().getCallCount(); + double frequency = 1.0d; + for (OptimizedCallNode c : callStack) { + int childCallCount = c.getCallCount(); + frequency *= childCallCount / (double) parentCallCount; + if (c.isInlined() || c.isSplit()) { + parentCallCount = childCallCount; + } else { + parentCallCount = c.getCurrentCallTarget().getCompilationProfile().getCallCount(); + } + } + return frequency; + } + + double calculateSimpleFrequency() { + return callNode.getCallCount() / (double) callTarget.getCompilationProfile().getCallCount(); + } + + private static List findCompilationRoots(Node call) { + RootNode root = call.getRootNode(); + if (root == null) { + return Collections.emptyList(); + } + List roots = new ArrayList<>(); + roots.add((OptimizedCallTarget) root.getCallTarget()); + for (CallNode callNode : root.getCachedCallNodes()) { + if (callNode.isInlined()) { + roots.addAll(findCompilationRoots(callNode)); + } + } + return roots; + } + + public int compareTo(TruffleInliningProfile o) { + if (o instanceof OptimizedCallNodeProfile) { + return Double.compare(((OptimizedCallNodeProfile) o).getScore(), getScore()); + } + return 0; + } + + public Map getDebugProperties() { + Map properties = new LinkedHashMap<>(); + OptimizedCallTarget.addASTSizeProperty(getCallNode().getCurrentRootNode().getRootNode(), properties); + properties.put("shallowCount", targetShallowNodeCount); + properties.put("currentCount", calculateInlinedTotalNodeCount(null)); + properties.put("inlinedTotalCount", calculateInlinedTotalNodeCount(getCallNode())); + properties.put("score", score); + properties.put("frequency", averageFrequency); + properties.put("callCount", callNode.getCallCount()); + properties.put("reason", reason); + return properties; + } + +} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,41 +34,66 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * 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(); private InstalledCode installedCode; private Future installedCodeTask; + private boolean compilationEnabled; + private boolean inlined; + private int callCount; + private final TruffleCompiler compiler; private final CompilationProfile compilationProfile; private final CompilationPolicy compilationPolicy; - private final TruffleInlining inlining; - private boolean compilationEnabled; - private int callCount; + private final SpeculationLog speculationLog = new SpeculationLog(); + private OptimizedCallTarget splitSource; - 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()); - this.rootNode.setCallTarget(this); if (TruffleUseTimeForCompilationDecision.getValue()) { compilationPolicy = new TimedCompilationPolicy(); } else { compilationPolicy = new DefaultCompilationPolicy(); } - this.compilationEnabled = true; + this.compilationEnabled = compilationEnabled; if (TruffleCallTargetProfiling.getValue()) { registerCallTarget(this); } - this.inlining = new TruffleInliningImpl(); + } + + public OptimizedCallTarget getSplitSource() { + return splitSource; + } + + public void setSplitSource(OptimizedCallTarget splitSource) { + this.splitSource = splitSource; + } + @Override + public String toString() { + String superString = super.toString(); + if (installedCode != null) { + superString += " "; + } + if (splitSource != null) { + superString += " "; + } + return superString; + } + + public boolean isOptimized() { + return installedCode != null || installedCodeTask != null; } @CompilerDirectives.SlowPath @@ -79,13 +104,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,31 +120,39 @@ } } + 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; } private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { - invalidate(); + invalidate(null, null, "Compiled code invalidated"); return call(caller, args); } - private void invalidate() { + private void invalidate(Node oldNode, Node newNode, String reason) { InstalledCode m = this.installedCode; if (m != null) { CompilerAsserts.neverPartOfCompilation(); installedCode = null; compilationProfile.reportInvalidated(); - if (TraceTruffleCompilation.getValue()) { - OUT.printf("[truffle] invalidated %-48s |Inv# %d |Replace# %d\n", rootNode, compilationProfile.getInvalidationCount(), - compilationProfile.getNodeReplaceCount()); - } + logOptimizedInvalidated(this, oldNode, newNode, reason); } + cancelInstalledTask(oldNode, newNode, reason); + } + private void cancelInstalledTask(Node oldNode, Node newNode, String reason) { Future task = this.installedCodeTask; if (task != null) { task.cancel(true); this.installedCodeTask = null; + logOptimizingUnqueued(this, oldNode, newNode, reason); compilationProfile.reportInvalidated(); } } @@ -133,29 +160,77 @@ private Object interpreterCall(PackedFrame caller, Arguments args) { CompilerAsserts.neverPartOfCompilation(); compilationProfile.reportInterpreterCall(); - if (compilationEnabled && shouldCompile()) { - if (isCompiling()) { - return waitForCompilation(caller, args); - } - boolean inlined = shouldInline() && inline(); - if (!inlined) { - compile(); + + if (compilationEnabled && compilationPolicy.shouldCompile(compilationProfile)) { + InstalledCode code = compile(); + if (code != null && code.isValid()) { + this.installedCode = code; + try { + return code.execute(this, caller, args); + } catch (InvalidInstalledCodeException ex) { + return compiledCodeInvalidated(caller, args); + } } } return executeHelper(caller, args); } - private boolean shouldCompile() { - return compilationPolicy.shouldCompile(compilationProfile); + public void performInlining() { + if (!TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { + return; + } + if (inlined) { + return; + } + inlined = true; + + logInliningStart(this); + PriorityQueue queue = new PriorityQueue<>(); + + // Used to avoid running in cycles or inline nodes in Truffle trees + // which do not suffice the tree property. + Set visitedCallNodes = new HashSet<>(); + + queueCallSitesForInlining(this, getRootNode(), visitedCallNodes, queue); + TruffleInliningProfile callSite = queue.poll(); + while (callSite != null) { + if (callSite.isInliningAllowed()) { + OptimizedCallNode callNode = callSite.getCallNode(); + logInlined(this, callSite); + RootNode inlinedRoot = callNode.inlineImpl().getCurrentRootNode(); + assert inlinedRoot != null; + queueCallSitesForInlining(this, inlinedRoot, visitedCallNodes, queue); + } else { + logInliningFailed(callSite); + } + callSite = queue.poll(); + } + logInliningDone(this); } - private static boolean shouldInline() { - return TruffleFunctionInlining.getValue(); + private static void queueCallSitesForInlining(final OptimizedCallTarget target, RootNode rootNode, final Set visitedCallSites, final PriorityQueue queue) { + rootNode.accept(new NodeVisitor() { + public boolean visit(Node node) { + if (node instanceof OptimizedCallNode) { + OptimizedCallNode call = ((OptimizedCallNode) node); + if (!call.isInlined() && !visitedCallSites.contains(call)) { + queue.add(call.createInliningProfile(target)); + visitedCallSites.add(call); + } + RootNode root = call.getCurrentRootNode(); + if (root != null && call.isInlined()) { + root.accept(this); + } + } + return true; + } + }); } private boolean isCompiling() { - if (installedCodeTask != null) { - if (installedCodeTask.isCancelled()) { + Future codeTask = this.installedCodeTask; + if (codeTask != null) { + if (codeTask.isCancelled()) { installedCodeTask = null; return false; } @@ -164,18 +239,21 @@ return false; } - public void compile() { - this.installedCodeTask = compiler.compile(this); - if (!TruffleBackgroundCompilation.getValue()) { - installedCode = receiveInstalledCode(); + public InstalledCode compile() { + if (isCompiling()) { + if (installedCodeTask.isDone()) { + return receiveInstalledCode(); + } + return null; + } else { + performInlining(); + logOptimizingQueued(this); + this.installedCodeTask = compiler.compile(this); + if (!TruffleBackgroundCompilation.getValue()) { + return receiveInstalledCode(); + } } - } - - private Object waitForCompilation(PackedFrame caller, Arguments args) { - if (installedCodeTask.isDone()) { - installedCode = receiveInstalledCode(); - } - return executeHelper(caller, args); + return null; } private InstalledCode receiveInstalledCode() { @@ -183,7 +261,7 @@ return installedCodeTask.get(); } catch (InterruptedException | ExecutionException e) { compilationEnabled = false; - OUT.printf("[truffle] opt failed %-48s %s\n", rootNode, e.getMessage()); + logOptimizingFailed(this, e.getMessage()); if (e.getCause() instanceof BailoutException) { // Bailout => move on. } else { @@ -198,22 +276,9 @@ } } - /** - * Forces inlining whether or not function inlining is enabled. - * - * @return true if an inlining was performed - */ - public boolean inline() { - boolean result = inlining.performInlining(this); - if (result) { - compilationProfile.reportInliningPerformed(inlining); - } - return result; - } - public Object executeHelper(PackedFrame caller, Arguments args) { - VirtualFrame frame = createFrame(rootNode.getFrameDescriptor(), caller, args); - return rootNode.execute(frame); + VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), caller, args); + return getRootNode().execute(frame); } protected static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { @@ -221,19 +286,216 @@ } @Override - public VirtualFrame create(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { - return createFrame(descriptor, caller, args); + public void reportLoopCount(int count) { + compilationProfile.reportLoopCount(count); + + // delegate to inlined call sites + for (CallNode callNode : getRootNode().getCachedCallNodes()) { + if (callNode.isInlined()) { + callNode.getRootNode().reportLoopCount(count); + } + } } @Override - public void reportLoopCount(int count) { - compilationProfile.reportLoopCount(count); + public void nodeReplaced(Node oldNode, Node newNode, String reason) { + compilationProfile.reportNodeReplaced(); + invalidate(oldNode, newNode, reason); + + // delegate to inlined call sites + for (CallNode callNode : getRootNode().getCachedCallNodes()) { + if (callNode.isInlined()) { + CallTarget target = callNode.getRootNode().getCallTarget(); + if (target instanceof ReplaceObserver) { + ((ReplaceObserver) target).nodeReplaced(oldNode, newNode, reason); + } + } + if (callNode instanceof OptimizedCallNode) { + ((OptimizedCallNode) callNode).nodeReplaced(oldNode, newNode, reason); + } + } + } + + public SpeculationLog getSpeculationLog() { + return speculationLog; + } + + public Map getDebugProperties() { + Map properties = new LinkedHashMap<>(); + addASTSizeProperty(getRootNode(), properties); + properties.putAll(getCompilationProfile().getDebugProperties()); + return properties; + + } + + private static void logInliningFailed(TruffleInliningProfile callSite) { + if (TraceTruffleInliningDetails.getValue()) { + log(2, "inline failed", callSite.getCallNode().getCurrentCallTarget().toString(), callSite.getDebugProperties()); + } + } + + private static void logInlined(@SuppressWarnings("unused") final OptimizedCallTarget target, TruffleInliningProfile callSite) { + if (TraceTruffleInliningDetails.getValue() || TraceTruffleInlining.getValue()) { + log(2, "inline success", callSite.getCallNode().getCurrentCallTarget().toString(), callSite.getDebugProperties()); + + if (TraceTruffleInliningDetails.getValue()) { + RootNode root = callSite.getCallNode().getCurrentCallTarget().getRootNode(); + root.accept(new NodeVisitor() { + int depth = 1; + + public boolean visit(Node node) { + if (node instanceof OptimizedCallNode) { + OptimizedCallNode callNode = ((OptimizedCallNode) node); + RootNode inlinedRoot = callNode.getCurrentRootNode(); + + if (inlinedRoot != null && callNode.isInlined()) { + Map properties = new LinkedHashMap<>(); + addASTSizeProperty(callNode.getCurrentRootNode(), properties); + log(2 + (depth * 2), "inline success", callNode.getCurrentCallTarget().toString(), properties); + depth++; + inlinedRoot.accept(this); + depth--; + } + } + return true; + } + }); + } + } + } + + private static void logInliningStart(OptimizedCallTarget target) { + if (TraceTruffleInliningDetails.getValue()) { + log(0, "inline start", target.toString(), target.getDebugProperties()); + } + } + + private static void logInliningDone(OptimizedCallTarget target) { + if (TraceTruffleInliningDetails.getValue()) { + log(0, "inline done", target.toString(), target.getDebugProperties()); + } + } + + private static void logOptimizingQueued(OptimizedCallTarget target) { + if (TraceTruffleCompilationDetails.getValue()) { + log(0, "opt queued", target.toString(), target.getDebugProperties()); + } + } + + private static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, String reason) { + if (TraceTruffleCompilationDetails.getValue()) { + Map properties = new LinkedHashMap<>(); + addReplaceProperties(properties, oldNode, newNode); + properties.put("Reason", reason); + log(0, "opt unqueued", target.toString(), properties); + } } - @Override - public void nodeReplaced() { - compilationProfile.reportNodeReplaced(); - invalidate(); + private static void addReplaceProperties(Map properties, Node oldNode, Node newNode) { + if (oldNode != null && newNode != null) { + properties.put("OldClass", oldNode.getClass().getSimpleName()); + properties.put("NewClass", newNode.getClass().getSimpleName()); + properties.put("Node", newNode); + } + } + + static void logOptimizingStart(OptimizedCallTarget target) { + if (TraceTruffleCompilationDetails.getValue()) { + log(0, "opt start", target.toString(), target.getDebugProperties()); + } + } + + private static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, String reason) { + if (TraceTruffleCompilation.getValue()) { + Map properties = new LinkedHashMap<>(); + addReplaceProperties(properties, oldNode, newNode); + properties.put("Reason", reason); + log(0, "opt invalidated", target.toString(), properties); + } + } + + private static void logOptimizingFailed(OptimizedCallTarget callSite, String reason) { + Map properties = new LinkedHashMap<>(); + properties.put("Reason", reason); + log(0, "opt fail", callSite.toString(), properties); + } + + static void logOptimizingDone(OptimizedCallTarget target, Map properties) { + if (TraceTruffleCompilationDetails.getValue() || TraceTruffleCompilation.getValue()) { + log(0, "opt done", target.toString(), properties); + } + if (TraceTruffleCompilationPolymorphism.getValue()) { + + target.getRootNode().accept(new NodeVisitor() { + public boolean visit(Node node) { + Kind kind = node.getKind(); + if (kind == Kind.POLYMORPHIC || kind == Kind.GENERIC) { + Map props = new LinkedHashMap<>(); + props.put("simpleName", node.getClass().getSimpleName()); + String msg = kind == Kind.GENERIC ? "generic" : "polymorphic"; + log(0, msg, node.toString(), props); + } + if (node instanceof CallNode) { + CallNode callNode = (CallNode) node; + if (callNode.isInlined()) { + callNode.getCurrentRootNode().accept(this); + } + } + return true; + } + }); + + } + } + + private static int splitCount = 0; + + static void logSplit(OptimizedCallNode callNode, OptimizedCallTarget target, OptimizedCallTarget newTarget) { + if (TraceTruffleSplitting.getValue()) { + Map properties = new LinkedHashMap<>(); + addASTSizeProperty(target.getRootNode(), properties); + properties.put("Split#", ++splitCount); + properties.put("Source", callNode.getEncapsulatingSourceSection()); + log(0, "split", newTarget.toString(), properties); + } + } + + static void addASTSizeProperty(RootNode target, Map properties) { + String value = String.format("%4d (%d/%d)", NodeUtil.countNodes(target.getRootNode(), null, true), // + NodeUtil.countNodes(target.getRootNode(), null, Kind.POLYMORPHIC, true), NodeUtil.countNodes(target.getRootNode(), null, Kind.GENERIC, true)); // + + properties.put("ASTSize", value); + } + + static synchronized void log(int indent, String msg, String details, Map properties) { + OUT.printf("[truffle] %-16s ", msg); + for (int i = 0; i < indent; i++) { + OUT.print(" "); + } + OUT.printf("%-" + (60 - indent) + "s", details); + if (properties != null) { + for (String property : properties.keySet()) { + Object value = properties.get(property); + if (value == null) { + continue; + } + OUT.print("|"); + OUT.print(property); + + StringBuilder propertyBuilder = new StringBuilder(); + if (value instanceof Integer) { + propertyBuilder.append(String.format("%6d", value)); + } else if (value instanceof Double) { + propertyBuilder.append(String.format("%8.2f", value)); + } else { + propertyBuilder.append(value); + } + + int length = Math.max(1, 20 - property.length()); + OUT.printf(" %" + length + "s ", propertyBuilder.toString()); + } + } + OUT.println(); } private static void printProfiling() { @@ -248,7 +510,6 @@ int totalCallCount = 0; int totalInlinedCallSiteCount = 0; - int totalNotInlinedCallSiteCount = 0; int totalNodeCount = 0; int totalInvalidationCount = 0; @@ -259,21 +520,34 @@ continue; } - int notInlinedCallSiteCount = TruffleInliningImpl.getInlinableCallSites(callTarget).size(); - int nodeCount = NodeUtil.countNodes(callTarget.rootNode); - int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.rootNode, InlinedCallSite.class); + int nodeCount = NodeUtil.countNodes(callTarget.getRootNode(), null, true); + int inlinedCallSiteCount = countInlinedNodes(callTarget.getRootNode()); String comment = callTarget.installedCode == null ? " int" : ""; comment += callTarget.compilationEnabled ? "" : " fail"; - OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, + OUT.printf("%-50s | %10d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, nodeCount, callTarget.getCompilationProfile().getInvalidationCount(), comment); totalCallCount += callTarget.callCount; totalInlinedCallSiteCount += inlinedCallSiteCount; - totalNotInlinedCallSiteCount += notInlinedCallSiteCount; totalNodeCount += nodeCount; totalInvalidationCount += callTarget.getCompilationProfile().getInvalidationCount(); } - OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount, totalInvalidationCount); + OUT.printf("%-50s | %10d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNodeCount, totalInvalidationCount); + } + + private static int countInlinedNodes(Node rootNode) { + List callers = NodeUtil.findAllNodeInstances(rootNode, CallNode.class); + int count = 0; + for (CallNode callNode : callers) { + if (callNode.isInlined()) { + count++; + RootNode root = callNode.getCurrentRootNode(); + if (root != null) { + count += countInlinedNodes(root); + } + } + } + return count; } private static void registerCallTarget(OptimizedCallTarget callTarget) { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Mar 05 19:40:15 2014 -0800 @@ -68,16 +68,16 @@ private final Providers providers; private final ResolvedJavaMethod executeHelperMethod; private final CanonicalizerPhase canonicalizer; - private final ResolvedJavaType[] skippedExceptionTypes; + private final GraphBuilderConfiguration config; private Set constantReceivers; private final GraphCache cache; private final TruffleCache truffleCache; - public PartialEvaluator(RuntimeProvider runtime, Providers providers, TruffleCache truffleCache) { + public PartialEvaluator(RuntimeProvider runtime, Providers providers, TruffleCache truffleCache, GraphBuilderConfiguration config) { this.providers = providers; CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(providers.getMetaAccess(), providers.getConstantReflection()); this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue(), customCanonicalizer); - this.skippedExceptionTypes = TruffleCompilerImpl.getSkippedExceptionTypes(providers.getMetaAccess()); + this.config = config; this.cache = runtime.getGraphCache(); this.truffleCache = truffleCache; try { @@ -94,13 +94,10 @@ throw Debug.handle(e); } - if (TraceTruffleCompilationDetails.getValue()) { + if (TraceTruffleCompilationHistogram.getValue()) { constantReceivers = new HashSet<>(); } - final GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(); - config.setSkippedExceptionTypes(skippedExceptionTypes); - final StructuredGraph graph = new StructuredGraph(executeHelperMethod); try (Scope s = Debug.scope("createGraph", graph)) { @@ -133,7 +130,7 @@ new VerifyFrameDoesNotEscapePhase().apply(graph, false); - if (TraceTruffleCompilationDetails.getValue() && constantReceivers != null) { + if (TraceTruffleCompilationHistogram.getValue() && constantReceivers != null) { DebugHistogram histogram = Debug.createHistogram("Expanded Truffle Nodes"); for (Constant c : constantReceivers) { histogram.add(c.asObject().getClass().getSimpleName()); @@ -187,7 +184,7 @@ for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class)) { InvokeKind kind = methodCallTargetNode.invokeKind(); if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || methodCallTargetNode.receiver() instanceof NewFrameNode))) { - if (TraceTruffleCompilationDetails.getValue() && kind == InvokeKind.Special) { + if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) { ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); constantReceivers.add(constantNode.asConstant()); } @@ -211,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); @@ -219,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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Wed Mar 05 19:40:15 2014 -0800 @@ -26,6 +26,7 @@ import java.lang.reflect.*; import java.util.*; +import java.util.Map.Entry; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -60,8 +61,10 @@ private final OptimisticOptimizations optimisticOptimizations; private final HashMap, StructuredGraph> cache = new HashMap<>(); + private final HashMap, Long> lastUsed = new HashMap<>(); private final StructuredGraph markerGraph = new StructuredGraph(); private final ResolvedJavaType stringBuilderClass; + private long counter; public TruffleCache(Providers providers, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations) { this.providers = providers; @@ -82,6 +85,7 @@ } StructuredGraph resultGraph = cache.get(key); if (resultGraph != null) { + lastUsed.put(key, counter++); return resultGraph; } @@ -90,6 +94,28 @@ return null; } + if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) { + List lastUsedList = new ArrayList<>(); + for (long l : lastUsed.values()) { + lastUsedList.add(l); + } + Collections.sort(lastUsedList); + long mid = lastUsedList.get(lastUsedList.size() / 2); + + List> toRemoveList = new ArrayList<>(); + for (Entry, Long> entry : lastUsed.entrySet()) { + if (entry.getValue() < mid) { + toRemoveList.add(entry.getKey()); + } + } + + for (List entry : toRemoveList) { + cache.remove(entry); + lastUsed.remove(entry); + } + } + + lastUsed.put(key, counter++); cache.put(key, markerGraph); try (Scope s = Debug.scope("TruffleCache", new Object[]{providers.getMetaAccess(), method})) { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Mar 05 19:40:15 2014 -0800 @@ -36,7 +36,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.CompilerThreadFactory.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -65,12 +64,12 @@ private final Suites suites; private final PartialEvaluator partialEvaluator; private final Backend backend; - private final ResolvedJavaType[] skippedExceptionTypes; + private final GraphBuilderConfiguration config; private final RuntimeProvider runtime; private final TruffleCache truffleCache; private final ThreadPoolExecutor compileQueue; - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class}; + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class}; public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); @@ -81,10 +80,9 @@ Replacements truffleReplacements = ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements(); this.providers = backend.getProviders().copyWith(truffleReplacements); this.suites = backend.getSuites().getDefaultSuites(); - this.skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); // Create compilation queue. - CompilerThreadFactory factory = new CompilerThreadFactory("TruffleCompilerThread", new DebugConfigAccess() { + CompilerThreadFactory factory = new CompilerThreadFactory("TruffleCompilerThread", new CompilerThreadFactory.DebugConfigAccess() { public GraalDebugConfig getDebugConfig() { if (Debug.isEnabled()) { GraalDebugConfig debugConfig = DebugEnvironment.initialize(TTY.out().out()); @@ -97,18 +95,21 @@ }); compileQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); - final GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault(); - config.setSkippedExceptionTypes(skippedExceptionTypes); - this.truffleCache = new TruffleCache(providers, config, TruffleCompilerImpl.Optimizations); + ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); + GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault(); + eagerConfig.setSkippedExceptionTypes(skippedExceptionTypes); + this.truffleCache = new TruffleCache(providers, eagerConfig, TruffleCompilerImpl.Optimizations); - this.partialEvaluator = new PartialEvaluator(runtime, providers, truffleCache); + this.config = GraphBuilderConfiguration.getDefault(); + this.config.setSkippedExceptionTypes(skippedExceptionTypes); + this.partialEvaluator = new PartialEvaluator(runtime, providers, truffleCache, config); if (Debug.isEnabled()) { DebugEnvironment.initialize(System.out); } } - static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { + private static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); @@ -135,15 +136,17 @@ private InstalledCode compileMethodImpl(final OptimizedCallTarget compilable) { final StructuredGraph graph; - final GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(); - config.setSkippedExceptionTypes(skippedExceptionTypes); GraphCache graphCache = runtime.getGraphCache(); if (graphCache != null) { graphCache.removeStaleGraphs(); } + if (TraceTruffleCompilation.getValue()) { + OptimizedCallTarget.logOptimizingStart(compilable); + } + if (TraceTruffleInliningTree.getValue()) { - printInlineTree(compilable.getRootNode()); + NodeUtil.printInliningTree(OUT, compilable.getRootNode()); } long timeCompilationStarted = System.nanoTime(); @@ -156,7 +159,7 @@ } long timePartialEvaluationFinished = System.nanoTime(); int nodeCountPartialEval = graph.getNodeCount(); - InstalledCode compiledMethod = compileMethodHelper(graph, config, assumptions, compilable.toString()); + InstalledCode compiledMethod = compileMethodHelper(graph, assumptions, compilable.toString(), compilable.getSpeculationLog()); long timeCompilationFinished = System.nanoTime(); int nodeCountLowered = graph.getNodeCount(); @@ -168,47 +171,27 @@ } if (TraceTruffleCompilation.getValue()) { - int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode()); 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, - (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, - (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, code != null ? code.length : 0); + Map properties = new LinkedHashMap<>(); + OptimizedCallTarget.addASTSizeProperty(compilable.getRootNode(), properties); + properties.put("Time", String.format("%5.0f(%4.0f+%-4.0f)ms", // + (timeCompilationFinished - timeCompilationStarted) / 1e6, // + (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, // + (timeCompilationFinished - timePartialEvaluationFinished) / 1e6)); + properties.put("Nodes", String.format("%5d/%5d", nodeCountPartialEval, nodeCountLowered)); + properties.put("CodeSize", code != null ? code.length : 0); + properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection())); + + OptimizedCallTarget.logOptimizingDone(compilable, properties); } return compiledMethod; } - private void printInlineTree(RootNode rootNode) { - OUT.println(); - OUT.println("Inlining tree for: " + rootNode); - rootNode.accept(new InlineTreeVisitor()); + private static String formatSourceSection(SourceSection sourceSection) { + return sourceSection != null ? sourceSection.toString() : "n/a"; } - private class InlineTreeVisitor implements NodeVisitor { - - public boolean visit(Node node) { - if (node instanceof InlinedCallSite) { - InlinedCallSite inlinedCallSite = (InlinedCallSite) node; - int indent = this.indent(node); - for (int i = 0; i < indent; ++i) { - OUT.print(" "); - } - OUT.println(inlinedCallSite.getCallTarget()); - } - return true; - } - - private int indent(Node n) { - if (n instanceof RootNode) { - return 0; - } else if (n instanceof InlinedCallSite) { - return indent(n.getParent()) + 1; - } else { - return indent(n.getParent()); - } - } - } - - public InstalledCode compileMethodHelper(StructuredGraph graph, GraphBuilderConfiguration config, Assumptions assumptions, String name) { + public InstalledCode compileMethodHelper(StructuredGraph graph, Assumptions assumptions, String name, SpeculationLog speculationLog) { try (Scope s = Debug.scope("TruffleFinal")) { Debug.dump(graph, "After TruffleTier"); } catch (Throwable e) { @@ -220,8 +203,8 @@ CodeCacheProvider codeCache = providers.getCodeCache(); CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); CompilationResult compilationResult = new CompilationResult(name); - result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(config), OptimisticOptimizations.ALL, getProfilingInfo(graph), - new SpeculationLog(), suites, false, compilationResult, CompilationResultBuilderFactory.Default); + result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), Optimizations, getProfilingInfo(graph), speculationLog, + suites, false, compilationResult, CompilationResultBuilderFactory.Default); } catch (Throwable e) { throw Debug.handle(e); } @@ -244,7 +227,7 @@ InstalledCode installedCode = null; try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); TimerCloseable a = CodeInstallationTime.start()) { - installedCode = providers.getCodeCache().addMethod(graph.method(), result, null); + installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog); } catch (Throwable e) { throw Debug.handle(e); } @@ -259,7 +242,7 @@ return installedCode; } - private PhaseSuite createGraphBuilderSuite(GraphBuilderConfiguration config) { + private PhaseSuite createGraphBuilderSuite() { PhaseSuite suite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); ListIterator> iterator = suite.findPhase(GraphBuilderPhase.class); iterator.remove(); @@ -277,4 +260,8 @@ } } } + + public PartialEvaluator getPartialEvaluator() { + return partialEvaluator; + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Wed Mar 05 19:40:15 2014 -0800 @@ -41,40 +41,42 @@ * Element = Include | '~' Exclude ; * */ - @Option(help = "") + @Option(help = "Restrict compilation to comma-separated list of includes (or excludes prefixed with tilde)") public static final OptionValue TruffleCompileOnly = new OptionValue<>(null); - @Option(help = "") + @Option(help = "Compile call target when call count exceeds this threshold") public static final OptionValue TruffleCompilationThreshold = new OptionValue<>(1000); - @Option(help = "") + @Option(help = "Minimum number of calls before a call target is compiled") public static final OptionValue TruffleMinInvokeThreshold = new OptionValue<>(3); - @Option(help = "") + @Option(help = "Delay compilation after an invalidation to allow for reprofiling") public static final OptionValue TruffleInvalidationReprofileCount = new OptionValue<>(3); - @Option(help = "") + @Option(help = "Delay compilation after a node replacement") public static final OptionValue TruffleReplaceReprofileCount = new OptionValue<>(10); - @Option(help = "") - public static final OptionValue TruffleInliningReprofileCount = new OptionValue<>(100); - @Option(help = "") + @Option(help = "Enable automatic inlining of call targets") public static final OptionValue TruffleFunctionInlining = new OptionValue<>(true); - @Option(help = "") - public static final OptionValue TruffleGraphMaxNodes = new OptionValue<>(25000); - @Option(help = "") - public static final OptionValue TruffleInliningMaxRecursiveDepth = new OptionValue<>(2); - @Option(help = "") + @Option(help = "Maximum number of Graal IR nodes during partial evaluation") + public static final OptionValue TruffleGraphMaxNodes = new OptionValue<>(30000); + @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit") public static final OptionValue TruffleInliningMaxCallerSize = new OptionValue<>(2250); - @Option(help = "") + @Option(help = "Skip inlining candidate if its tree size exceeds this limit") public static final OptionValue TruffleInliningMaxCalleeSize = new OptionValue<>(250); - @Option(help = "") + @Option(help = "Call frequency relative to call target") + public static final OptionValue TruffleInliningMinFrequency = new OptionValue<>(0.3); + @Option(help = "Allow inlining of less hot candidates if tree size is small") public static final OptionValue TruffleInliningTrivialSize = new OptionValue<>(10); - @Option(help = "") - public static final OptionValue TruffleInliningMinFrequency = new OptionValue<>(0.3); + @Option(help = "Enable call target splitting") + public static final OptionValue TruffleSplittingEnabled = new OptionValue<>(true); + @Option(help = "Disable call target splitting if tree size exceeds this limit") + public static final OptionValue TruffleSplittingMaxCalleeSize = new OptionValue<>(100); + @Option(help = "Number of most recently used methods in truffle cache") + public static final OptionValue TruffleMaxCompilationCacheSize = new OptionValue<>(512); + @Option(help = "Enable asynchronous truffle compilation in background thread") + public static final OptionValue TruffleBackgroundCompilation = new OptionValue<>(true); @Option(help = "") public static final OptionValue TruffleUseTimeForCompilationDecision = new OptionValue<>(false); @Option(help = "") public static final OptionValue TruffleCompilationDecisionTime = new OptionValue<>(100); @Option(help = "") public static final OptionValue TruffleCompilationDecisionTimePrintFail = new OptionValue<>(false); - @Option(help = "") - public static final OptionValue TruffleBackgroundCompilation = new OptionValue<>(true); // tracing @Option(help = "") @@ -82,6 +84,10 @@ @Option(help = "") public static final OptionValue TraceTruffleCompilationDetails = new OptionValue<>(false); @Option(help = "") + public static final OptionValue TraceTruffleCompilationHistogram = new OptionValue<>(false); + @Option(help = "Prints out all polymorphic and generic nodes after compilation.") + public static final OptionValue TraceTruffleCompilationPolymorphism = new OptionValue<>(false); + @Option(help = "") public static final OptionValue TraceTruffleExpansion = new OptionValue<>(false); @Option(help = "") public static final OptionValue TraceTruffleExpansionSource = new OptionValue<>(false); @@ -92,12 +98,14 @@ @Option(help = "") public static final OptionValue TruffleCompilationExceptionsAreFatal = new OptionValue<>(true); @Option(help = "") - public static final OptionValue TraceTruffleInlining = new OptionValue<>(true); + public static final OptionValue TraceTruffleInlining = new OptionValue<>(false); @Option(help = "") public static final OptionValue TraceTruffleInliningTree = new OptionValue<>(false); @Option(help = "") public static final OptionValue TraceTruffleInliningDetails = new OptionValue<>(false); @Option(help = "") + public static final OptionValue TraceTruffleSplitting = new OptionValue<>(false); + @Option(help = "") public static final OptionValue TruffleCallTargetProfiling = new StableOptionValue<>(false); // @formatter:on } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java Wed Mar 05 19:40:15 2014 -0800 @@ -26,14 +26,14 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; -import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.*; /** * Enables a Truffle compilable to masquerade as a {@link JavaMethod} for use as a context value in * {@linkplain Debug#scope(String, Object...) debug scopes}. */ public class TruffleDebugJavaMethod implements JavaMethod { - private final DefaultCallTarget compilable; + private final RootCallTarget compilable; private static final JavaType declaringClass = new JavaType() { @@ -95,7 +95,7 @@ } }; - public TruffleDebugJavaMethod(DefaultCallTarget compilable) { + public TruffleDebugJavaMethod(RootCallTarget compilable) { this.compilable = compilable; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +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; - -public interface TruffleInlining { - - /** Returns true if reprofiling is required else false. */ - boolean performInlining(OptimizedCallTarget callTarget); - - /** - * Returns the minimum number of invocations required until the next inlining can occur. Only - * used if {@link #performInlining(OptimizedCallTarget)} returned true. - */ - int getInvocationReprofileCount(); - - /** - * Returns the number of invocations or loop invocations required until the next inlining can - * occur. Only used if {@link #performInlining(OptimizedCallTarget)} returned true. - */ - int getReprofileCount(); -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +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 static com.oracle.graal.truffle.TruffleCompilerOptions.*; - -import java.io.*; -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.api.nodes.*; - -class TruffleInliningImpl implements TruffleInlining { - - private static final int MIN_INVOKES_AFTER_INLINING = 2; - - private static final PrintStream OUT = TTY.out().out(); - - public int getReprofileCount() { - return TruffleCompilerOptions.TruffleInliningReprofileCount.getValue(); - } - - public int getInvocationReprofileCount() { - return MIN_INVOKES_AFTER_INLINING; - } - - @Override - public boolean performInlining(OptimizedCallTarget target) { - final InliningPolicy policy = new InliningPolicy(target); - if (!policy.continueInlining()) { - if (TraceTruffleInliningDetails.getValue()) { - List inlinableCallSites = getInlinableCallSites(target); - if (!inlinableCallSites.isEmpty()) { - OUT.printf("[truffle] inlining hit caller size limit (%3d >= %3d).%3d remaining call sites in %s:\n", policy.callerNodeCount, TruffleInliningMaxCallerSize.getValue(), - inlinableCallSites.size(), target.getRootNode()); - policy.sortByRelevance(inlinableCallSites); - printCallSiteInfo(policy, inlinableCallSites, ""); - } - } - return false; - } - - List inlinableCallSites = getInlinableCallSites(target); - if (inlinableCallSites.isEmpty()) { - return false; - } - - policy.sortByRelevance(inlinableCallSites); - - boolean inlined = false; - for (InlinableCallSiteInfo inlinableCallSite : inlinableCallSites) { - if (!policy.isWorthInlining(inlinableCallSite)) { - break; - } - if (inlinableCallSite.getCallSite().inline(target)) { - if (TraceTruffleInlining.getValue()) { - printCallSiteInfo(policy, inlinableCallSite, "inlined"); - } - inlined = true; - break; - } - } - - if (inlined) { - for (InlinableCallSiteInfo callSite : inlinableCallSites) { - callSite.getCallSite().resetCallCount(); - } - } else { - if (TraceTruffleInliningDetails.getValue()) { - OUT.printf("[truffle] inlining stopped.%3d remaining call sites in %s:\n", inlinableCallSites.size(), target.getRootNode()); - printCallSiteInfo(policy, inlinableCallSites, ""); - } - } - - return inlined; - } - - private static void printCallSiteInfo(InliningPolicy policy, List inlinableCallSites, String msg) { - for (InlinableCallSiteInfo candidate : inlinableCallSites) { - printCallSiteInfo(policy, candidate, msg); - } - } - - 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.getCallSite(), nodes, calls, policy.metric(callSite), callSite.getCallSite().getCallTarget()); - } - - private static final class InliningPolicy { - - private final int callerNodeCount; - private final int callerInvocationCount; - - public InliningPolicy(OptimizedCallTarget caller) { - this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode()); - this.callerInvocationCount = caller.getCompilationProfile().getOriginalInvokeCounter(); - } - - public boolean continueInlining() { - return callerNodeCount < TruffleInliningMaxCallerSize.getValue(); - } - - public boolean isWorthInlining(InlinableCallSiteInfo callSite) { - return callSite.getInlineNodeCount() <= TruffleInliningMaxCalleeSize.getValue() && callSite.getInlineNodeCount() + callerNodeCount <= TruffleInliningMaxCallerSize.getValue() && - callSite.getCallCount() > 0 && callSite.getRecursiveDepth() < TruffleInliningMaxRecursiveDepth.getValue() && - (frequency(callSite) >= TruffleInliningMinFrequency.getValue() || callSite.getInlineNodeCount() <= TruffleInliningTrivialSize.getValue()); - } - - public double metric(InlinableCallSiteInfo callSite) { - double cost = callSite.getInlineNodeCount(); - double metric = frequency(callSite) / cost; - return metric; - } - - private double frequency(InlinableCallSiteInfo callSite) { - return (double) callSite.getCallCount() / (double) callerInvocationCount; - } - - public void sortByRelevance(List inlinableCallSites) { - Collections.sort(inlinableCallSites, new Comparator() { - - @Override - public int compare(InlinableCallSiteInfo cs1, InlinableCallSiteInfo cs2) { - int result = (isWorthInlining(cs2) ? 1 : 0) - (isWorthInlining(cs1) ? 1 : 0); - if (result == 0) { - return Double.compare(metric(cs2), metric(cs1)); - } - return result; - } - }); - } - } - - private static final class InlinableCallSiteInfo { - - private final InlinableCallSite callSite; - private final int callCount; - private final int nodeCount; - private final int recursiveDepth; - - public InlinableCallSiteInfo(InlinableCallSite callSite) { - this.callSite = callSite; - this.callCount = callSite.getCallCount(); - this.nodeCount = NodeUtil.countNodes(callSite.getInlineTree()); - this.recursiveDepth = calculateRecursiveDepth(); - } - - public int getRecursiveDepth() { - return recursiveDepth; - } - - private int calculateRecursiveDepth() { - int depth = 0; - Node parent = ((Node) callSite).getParent(); - while (!(parent instanceof RootNode)) { - assert parent != null; - if (parent instanceof InlinedCallSite && ((InlinedCallSite) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; - } - parent = parent.getParent(); - } - if (((RootNode) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; - } - return depth; - } - - public InlinableCallSite getCallSite() { - return callSite; - } - - public int getCallCount() { - return callCount; - } - - public int getInlineNodeCount() { - return nodeCount; - } - } - - static List getInlinableCallSites(final DefaultCallTarget target) { - final ArrayList inlinableCallSites = new ArrayList<>(); - target.getRootNode().accept(new NodeVisitor() { - - @Override - public boolean visit(Node node) { - if (node instanceof InlinableCallSite) { - inlinableCallSites.add(new InlinableCallSiteInfo((InlinableCallSite) node)); - } - return true; - } - }); - return inlinableCallSites; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,37 @@ +/* + * 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 java.util.*; + +public interface TruffleInliningProfile extends Comparable { + + OptimizedCallNode getCallNode(); + + boolean isInliningAllowed(); + + int compareTo(TruffleInliningProfile o); + + Map getDebugProperties(); + +} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Wed Mar 05 19:40:15 2014 -0800 @@ -58,7 +58,6 @@ truffleReplacements.registerSubstitutions(FrameWithoutBoxingSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedAssumptionSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedCallTargetSubstitutions.class); - truffleReplacements.registerSubstitutions(DefaultCallTargetSubstitutions.class); return truffleReplacements; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java Wed Mar 05 19:40:15 2014 -0800 @@ -23,17 +23,17 @@ package com.oracle.graal.truffle; import com.oracle.graal.debug.*; -import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.*; public class TruffleTreeDumpHandler implements DebugDumpHandler { @Override public void dump(Object object, final String message) { - if (object instanceof DefaultCallTarget) { - DefaultCallTarget callTarget = (DefaultCallTarget) object; + if (object instanceof RootCallTarget) { + RootCallTarget callTarget = (RootCallTarget) object; if (callTarget.getRootNode() != null) { - new GraphPrintVisitor().beginGroup(callTarget.toString()).beginGraph(message).visit(callTarget.getRootNode()).printToNetwork(); + new GraphPrintVisitor().beginGroup(callTarget.toString()).beginGraph(message).visit(callTarget.getRootNode()).printToNetwork(false); } } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -38,8 +38,8 @@ public class IntegerAddExactNode extends IntegerAddNode implements Canonicalizable, IntegerExactArithmeticNode { public IntegerAddExactNode(ValueNode x, ValueNode y) { - super(x.kind(), x, y); - assert x.kind() == y.kind() && (x.kind() == Kind.Int || x.kind() == Kind.Long); + super(x.stamp().unrestricted(), x, y); + assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp; } @Override @@ -54,12 +54,15 @@ return graph().unique(new IntegerAddExactNode(y(), x())); } if (x().isConstant()) { + Constant xConst = x().asConstant(); + Constant yConst = y().asConstant(); + assert xConst.getKind() == yConst.getKind(); try { - if (kind() == Kind.Int) { - return ConstantNode.forInt(ExactMath.addExact(x().asConstant().asInt(), y().asConstant().asInt()), graph()); + if (xConst.getKind() == Kind.Int) { + return ConstantNode.forInt(ExactMath.addExact(xConst.asInt(), yConst.asInt()), graph()); } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(ExactMath.addExact(x().asConstant().asLong(), y().asConstant().asLong()), graph()); + assert xConst.getKind() == Kind.Long; + return ConstantNode.forLong(ExactMath.addExact(xConst.asLong(), yConst.asLong()), graph()); } } catch (ArithmeticException ex) { // The operation will result in an overflow exception, so do not canonicalize. @@ -84,8 +87,12 @@ } @NodeIntrinsic - public static native int addExact(int a, int b); + public static int addExact(int a, int b) { + return ExactMath.addExact(a, b); + } @NodeIntrinsic - public static native long addExact(long a, long b); + public static long addExact(long a, long b) { + return ExactMath.addExact(a, b); + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; import com.oracle.truffle.api.*; /** @@ -37,8 +38,8 @@ public class IntegerMulExactNode extends IntegerMulNode implements Canonicalizable, IntegerExactArithmeticNode { public IntegerMulExactNode(ValueNode x, ValueNode y) { - super(x.kind(), x, y); - assert x.kind() == y.kind() && (x.kind() == Kind.Int || x.kind() == Kind.Long); + super(x.stamp().unrestricted(), x, y); + assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp; } @Override @@ -47,12 +48,15 @@ return graph().unique(new IntegerMulExactNode(y(), x())); } if (x().isConstant()) { + Constant xConst = x().asConstant(); + Constant yConst = y().asConstant(); + assert xConst.getKind() == yConst.getKind(); try { - if (kind() == Kind.Int) { - return ConstantNode.forInt(ExactMath.multiplyExact(x().asConstant().asInt(), y().asConstant().asInt()), graph()); + if (xConst.getKind() == Kind.Int) { + return ConstantNode.forInt(ExactMath.multiplyExact(xConst.asInt(), yConst.asInt()), graph()); } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(ExactMath.multiplyExact(x().asConstant().asLong(), y().asConstant().asLong()), graph()); + assert xConst.getKind() == Kind.Long; + return ConstantNode.forLong(ExactMath.multiplyExact(xConst.asLong(), yConst.asLong()), graph()); } } catch (ArithmeticException ex) { // The operation will result in an overflow exception, so do not canonicalize. @@ -63,7 +67,7 @@ return x(); } if (c == 0) { - return ConstantNode.defaultForKind(kind(), graph()); + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } } return this; @@ -80,8 +84,12 @@ } @NodeIntrinsic - public static native int multiplyExact(int a, int b); + public static int multiplyExact(int a, int b) { + return ExactMath.multiplyExact(a, b); + } @NodeIntrinsic - public static native long multiplyExact(long a, long b); + public static long multiplyExact(long a, long b) { + return ExactMath.multiplyExact(a, b); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -38,8 +38,8 @@ public class IntegerSubExactNode extends IntegerSubNode implements Canonicalizable, IntegerExactArithmeticNode { public IntegerSubExactNode(ValueNode x, ValueNode y) { - super(x.kind(), x, y); - assert x.kind() == y.kind() && (x.kind() == Kind.Int || x.kind() == Kind.Long); + super(StampTool.sub(x.stamp(), y.stamp()), x, y); + assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp; } @Override @@ -51,15 +51,18 @@ @Override public Node canonical(CanonicalizerTool tool) { if (x() == y()) { - return ConstantNode.forIntegerKind(kind(), 0, graph()); + return ConstantNode.forIntegerStamp(stamp(), 0, graph()); } if (x().isConstant() && y().isConstant()) { + Constant xConst = x().asConstant(); + Constant yConst = y().asConstant(); + assert xConst.getKind() == yConst.getKind(); try { - if (kind() == Kind.Int) { - return ConstantNode.forInt(ExactMath.subtractExact(x().asConstant().asInt(), y().asConstant().asInt()), graph()); + if (xConst.getKind() == Kind.Int) { + return ConstantNode.forInt(ExactMath.subtractExact(xConst.asInt(), yConst.asInt()), graph()); } else { - assert kind() == Kind.Long; - return ConstantNode.forLong(ExactMath.subtractExact(x().asConstant().asLong(), y().asConstant().asLong()), graph()); + assert xConst.getKind() == Kind.Long; + return ConstantNode.forLong(ExactMath.subtractExact(xConst.asLong(), yConst.asLong()), graph()); } } catch (ArithmeticException ex) { // The operation will result in an overflow exception, so do not canonicalize. @@ -84,8 +87,12 @@ } @NodeIntrinsic - public static native int subtractExact(int a, int b); + public static int subtractExact(int a, int b) { + return ExactMath.subtractExact(a, b); + } @NodeIntrinsic - public static native long subtractExact(long a, long b); + public static long subtractExact(long a, long b) { + return ExactMath.subtractExact(a, b); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -25,7 +25,6 @@ import java.util.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; @@ -34,7 +33,6 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.runtime.*; import com.oracle.graal.truffle.*; import com.oracle.graal.truffle.nodes.*; import com.oracle.truffle.api.*; @@ -46,8 +44,6 @@ */ public class NewFrameNode extends FixedWithNextNode implements IterableNodeType, VirtualizableAllocation, Canonicalizable { - static final ResolvedJavaType FRAME_TYPE = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getMetaAccess().lookupJavaType(FrameWithoutBoxing.class); - @Input private ValueNode descriptor; @Input private ValueNode caller; @Input private ValueNode arguments; @@ -59,8 +55,8 @@ this.arguments = arguments; } - public NewFrameNode(ValueNode descriptor, ValueNode caller, ValueNode arguments) { - this(StampFactory.exactNonNull(FRAME_TYPE), descriptor, caller, arguments); + public NewFrameNode(ResolvedJavaType frameType, ValueNode descriptor, ValueNode caller, ValueNode arguments) { + this(StampFactory.exactNonNull(frameType), descriptor, caller, arguments); } public ValueNode getDescriptor() { @@ -233,5 +229,5 @@ } @NodeIntrinsic - public static native FrameWithoutBoxing allocate(FrameDescriptor descriptor, PackedFrame caller, Arguments args); + public static native FrameWithoutBoxing allocate(@ConstantNodeParameter Class frameType, FrameDescriptor descriptor, PackedFrame caller, Arguments args); } diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java Wed Mar 05 19:40:15 2014 -0800 @@ -44,12 +44,6 @@ @MethodSubstitution 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); + return NewFrameNode.allocate(FrameWithoutBoxing.class, descriptor, caller, args); } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -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. */ @@ -263,7 +202,7 @@ case NOT: assert arguments.size() == 1; - replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph)))); + replace(invoke, graph.unique(new XorNode(StampFactory.forKind(wordKind), arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph)))); break; case READ: { @@ -362,14 +301,14 @@ if (toKind == Kind.Int) { assert value.kind() == Kind.Long; - return graph.unique(new ConvertNode(Kind.Long, Kind.Int, value)); + return graph.unique(new NarrowNode(value, 32)); } else { assert toKind == Kind.Long; assert value.kind().getStackKind() == Kind.Int; if (unsigned) { - return graph.unique(new ReinterpretNode(Kind.Long, value)); + return graph.unique(new ZeroExtendNode(value, 64)); } else { - return graph.unique(new ConvertNode(Kind.Int, Kind.Long, value)); + return graph.unique(new SignExtendNode(value, 64)); } } } @@ -381,8 +320,8 @@ */ private static ValueNode createBinaryNodeInstance(Class nodeClass, Kind kind, ValueNode left, ValueNode right) { try { - Constructor constructor = nodeClass.getConstructor(Kind.class, ValueNode.class, ValueNode.class); - return constructor.newInstance(kind, left, right); + Constructor constructor = nodeClass.getConstructor(Stamp.class, ValueNode.class, ValueNode.class); + return constructor.newInstance(StampFactory.forKind(kind), left, right); } catch (Throwable ex) { throw new GraalInternalError(ex).addContext(nodeClass.getName()); } @@ -431,7 +370,7 @@ } protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, Kind readKind, BarrierType barrierType, boolean compressible) { - ReadNode read = graph.add(new ReadNode(base, location, StampFactory.forKind(readKind), barrierType, compressible)); + ReadNode read = graph.add(new ReadNode(base, location, StampFactory.forKind(readKind.getStackKind()), barrierType, compressible)); graph.addBeforeFixed(invoke.asNode(), read); /* * The read must not float outside its block otherwise it may float above an explicit zero diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,7 @@ import static org.junit.Assert.*; +import java.lang.reflect.*; import java.util.*; import com.oracle.truffle.api.*; @@ -61,7 +62,17 @@ } static E createGenericNode(NodeFactory factory, Object... constants) { - return factory.createNodeGeneric(createNode(factory, constants)); + Method createGenericMethod; + try { + createGenericMethod = factory.getClass().getMethod("createGeneric", factory.getNodeClass()); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + try { + return factory.getNodeClass().cast(createGenericMethod.invoke(null, createNode(factory, constants))); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } } static TestRootNode createRoot(NodeFactory factory, Object... constants) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/UnsupportedSpecializationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/UnsupportedSpecializationTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012, 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.truffle.api.dsl.test; + +import java.util.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.dsl.test.UnsupportedSpecializationTestFactory.Unsupported1Factory; +import com.oracle.truffle.api.dsl.test.UnsupportedSpecializationTestFactory.Unsupported2Factory; +import com.oracle.truffle.api.nodes.*; + +public class UnsupportedSpecializationTest { + + @Test + public void testUnsupported1() { + TestRootNode root = TestHelper.createRoot(Unsupported1Factory.getInstance()); + try { + TestHelper.executeWith(root, ""); + Assert.fail(); + } catch (UnsupportedSpecializationException e) { + Assert.assertNotNull(e.getSuppliedValues()); + Assert.assertEquals(1, e.getSuppliedValues().length); + Assert.assertEquals("", e.getSuppliedValues()[0]); + Assert.assertSame(root.getNode().getChildren().iterator().next(), e.getSuppliedNodes()[0]); + Assert.assertEquals(root.getNode(), e.getNode()); + } + } + + @NodeChild("a") + abstract static class Unsupported1 extends ValueNode { + + @Specialization + public int doInteger(@SuppressWarnings("unused") int a) { + throw new AssertionError(); + } + } + + @Test + public void testUnsupported2() { + TestRootNode root = TestHelper.createRoot(Unsupported2Factory.getInstance()); + try { + TestHelper.executeWith(root, "", 1); + Assert.fail(); + } catch (UnsupportedSpecializationException e) { + Assert.assertNotNull(e.getSuppliedValues()); + Assert.assertNotNull(e.getSuppliedNodes()); + Assert.assertEquals(3, e.getSuppliedValues().length); + Assert.assertEquals(3, e.getSuppliedNodes().length); + Assert.assertEquals("", e.getSuppliedValues()[0]); + Assert.assertEquals(false, e.getSuppliedValues()[1]); + Assert.assertEquals(null, e.getSuppliedValues()[2]); + List children = NodeUtil.findNodeChildren(root.getNode()); + Assert.assertSame(children.get(0), e.getSuppliedNodes()[0]); + Assert.assertNull(e.getSuppliedNodes()[1]); + Assert.assertSame(children.get(1), e.getSuppliedNodes()[2]); + Assert.assertEquals(root.getNode(), e.getNode()); + } + } + + @SuppressWarnings("unused") + @NodeChildren({@NodeChild("a"), @NodeChild("b")}) + abstract static class Unsupported2 extends ValueNode { + + @ShortCircuit("b") + public boolean needsB(Object a) { + return false; + } + + @Specialization + public int doInteger(int a, boolean hasB, int b) { + throw new AssertionError(); + } + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeFactory.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeFactory.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeFactory.java Wed Mar 05 19:40:15 2014 -0800 @@ -46,15 +46,6 @@ T createNode(Object... arguments); /** - * Instantiates a new generic variant of the node. This is an optional method and throws an - * {@link UnsupportedOperationException} if not supported. - * - * @param thisNode the current node - * @return the specialized node - */ - T createNodeGeneric(T thisNode); - - /** * Returns the node class that will get created by {@link #createNode(Object...)}. The node * class does not match exactly to the instantiated object but they are guaranteed to be * assignable. diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012, 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.dsl; + +import java.util.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * Thrown by the generated code of Truffle-DSL if no compatible Specialization could be found for + * the provided values. + */ +public final class UnsupportedSpecializationException extends RuntimeException { + + private static final long serialVersionUID = -2122892028296836269L; + + private final Node node; + private final Node[] suppliedNodes; + private final Object[] suppliedValues; + + public UnsupportedSpecializationException(Node node, Node[] suppliedNodes, Object... suppliedValues) { + super("Unexpected values provided for " + node + ": " + Arrays.toString(suppliedValues)); + Objects.requireNonNull(suppliedNodes, "The suppliedNodes parameter must not be null."); + if (suppliedNodes.length != suppliedValues.length) { + throw new IllegalArgumentException("The length of suppliedNodes must match the length of suppliedValues."); + } + this.node = node; + this.suppliedNodes = suppliedNodes; + this.suppliedValues = suppliedValues; + } + + /** + * Returns the {@link Node} that caused the this {@link UnsupportedSpecializationException}. + */ + public Node getNode() { + return node; + } + + /** + * Returns the children of the {@link Node} returned by {@link #getNode()} which produced the + * values returned by {@link #getSuppliedValues()}. The array returned by + * {@link #getSuppliedNodes()} has the same length as the array returned by + * {@link #getSuppliedValues()}. Never returns null. + */ + public Node[] getSuppliedNodes() { + return suppliedNodes; + } + + /** + * Returns the dynamic values that were supplied to the node.The array returned by + * {@link #getSuppliedNodes()} has the same length as the array returned by + * {@link #getSuppliedValues()}. Never returns null. + */ + public Object[] getSuppliedValues() { + return suppliedValues; + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Wed Mar 05 19:40:15 2014 -0800 @@ -37,7 +37,8 @@ * {@link FrameDescriptor} represents the current structure of the frame. The method * {@link FrameDescriptor#addFrameSlot(Object, FrameSlotKind)} can be used to create predefined * frame slots. The setter and getter methods in the {@link Frame} class can be used to access the - * current value of a particular frame slot. + * current value of a particular frame slot. Values can be removed from a frame via the + * {@link FrameDescriptor#removeFrameSlot(Object)} method. *

* *

@@ -64,11 +65,20 @@ public void test() { TruffleRuntime runtime = Truffle.getRuntime(); FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlot slot = frameDescriptor.addFrameSlot("localVar", FrameSlotKind.Int); + String varName = "localVar"; + FrameSlot slot = frameDescriptor.addFrameSlot(varName, FrameSlotKind.Int); TestRootNode rootNode = new TestRootNode(frameDescriptor, new AssignLocal(slot), new ReadLocal(slot)); CallTarget target = runtime.createCallTarget(rootNode); Object result = target.call(); Assert.assertEquals(42, result); + frameDescriptor.removeFrameSlot(varName); + boolean slotMissing = false; + try { + result = target.call(); + } catch (IllegalArgumentException iae) { + slotMissing = true; + } + Assert.assertTrue(slotMissing); } class TestRootNode extends RootNode { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,8 +27,7 @@ import com.oracle.truffle.api.frame.*; /** - * Represents the target of a call. Instances of this interface can be created using the - * {@link TruffleRuntime#createCallTarget(com.oracle.truffle.api.nodes.RootNode)} method. + * Represents the target of a call. */ public abstract class CallTarget { diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/LoopCountReceiver.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/LoopCountReceiver.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/LoopCountReceiver.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,10 @@ */ package com.oracle.truffle.api; +/** + * Accepts the execution count of a loop that is a child of this node. The optimization heuristics + * can use the loop count to guide compilation and inlining. + */ public interface LoopCountReceiver { void reportLoopCount(int count); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ReplaceObserver.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ReplaceObserver.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ReplaceObserver.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,7 +24,12 @@ */ package com.oracle.truffle.api; +import com.oracle.truffle.api.nodes.*; + +/** + * An observer that is notified whenever a child node is replaced. + */ public interface ReplaceObserver { - void nodeReplaced(); + void nodeReplaced(Node oldNode, Node newNode, String reason); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,50 @@ +/* + * 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; + +import com.oracle.truffle.api.nodes.*; + +/** + * Represents the target of a call to a {@link RootNode}, i.e., to another tree of nodes. Instances + * of this class can be created using {@link TruffleRuntime#createCallTarget(RootNode)}. + */ +public abstract class RootCallTarget extends CallTarget { + + private final RootNode rootNode; + + public RootCallTarget(RootNode function) { + this.rootNode = function; + this.rootNode.setCallTarget(this); + } + + @Override + public String toString() { + return rootNode.toString(); + } + + public RootNode getRootNode() { + return rootNode; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java Wed Mar 05 19:40:15 2014 -0800 @@ -33,7 +33,7 @@ public class TruffleOptions { /** - * Enables/disables the rewriting of traces in the truffle runtime to stdout. + * Enables/disables the rewriting of traces in the Truffle runtime to stdout. *

* Can be set with {@code -Dtruffle.TraceRewrites=true}. */ diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Wed Mar 05 19:40:15 2014 -0800 @@ -48,7 +48,9 @@ * represents the entry point * @return the new call target object */ - CallTarget createCallTarget(RootNode rootNode); + RootCallTarget createCallTarget(RootNode rootNode); + + CallNode createCallNode(CallTarget target); /** * Creates a new assumption object that can be checked and invalidated. diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Wed Mar 05 19:40:15 2014 -0800 @@ -86,6 +86,14 @@ return addFrameSlot(identifier, kind); } + public void removeFrameSlot(Object identifier) { + assert identifierToSlotMap.containsKey(identifier); + slots.remove(identifierToSlotMap.get(identifier)); + identifierToSlotMap.remove(identifier); + updateVersion(); + getNotInFrameAssumption(identifier); + } + public int getSize() { return slots.size(); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultAssumption.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultAssumption.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultAssumption.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,11 +24,16 @@ */ package com.oracle.truffle.api.impl; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.*; -public final class DefaultAssumption extends AbstractAssumption { +/** + * This is an implementation-specific class. Do not use or instantiate it. Instead, use + * {@link TruffleRuntime#createAssumption()} to create an {@link Assumption}. + */ +final class DefaultAssumption extends AbstractAssumption { - public DefaultAssumption(String name) { + DefaultAssumption(String name) { super(name); } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,70 @@ +/* + * 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.impl; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +public class DefaultCallNode extends CallNode { + + public DefaultCallNode(CallTarget target) { + super(target); + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + return getCallTarget().call(caller, arguments); + } + + @Override + public void inline() { + } + + @Override + public CallTarget getSplitCallTarget() { + return null; + } + + @Override + public boolean split() { + return false; + } + + @Override + public boolean isSplittable() { + return false; + } + + @Override + public boolean isInlined() { + return false; + } + + @Override + public String toString() { + return getParent() != null ? getParent().toString() : super.toString(); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java Wed Mar 05 19:40:15 2014 -0800 @@ -28,27 +28,19 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; -public class DefaultCallTarget extends CallTarget { - - protected final RootNode rootNode; +/** + * This is an implementation-specific class. Do not use or instantiate it. Instead, use + * {@link TruffleRuntime#createCallTarget(RootNode)} to create a {@link RootCallTarget}. + */ +public class DefaultCallTarget extends RootCallTarget { - public DefaultCallTarget(RootNode function) { - this.rootNode = function; - this.rootNode.setCallTarget(this); - } - - @Override - public String toString() { - return rootNode.toString(); + protected DefaultCallTarget(RootNode function) { + super(function); } @Override public Object call(PackedFrame caller, Arguments args) { - VirtualFrame frame = new DefaultVirtualFrame(rootNode.getFrameDescriptor(), caller, args); - return rootNode.execute(frame); - } - - public RootNode getRootNode() { - return rootNode; + VirtualFrame frame = new DefaultVirtualFrame(getRootNode().getFrameDescriptor(), caller, args); + return getRootNode().execute(frame); } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Wed Mar 05 19:40:15 2014 -0800 @@ -27,11 +27,16 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; +/** + * This is an implementation-specific class. Do not use or instantiate it. Instead, use + * {@link TruffleRuntime#createMaterializedFrame(Arguments)} or {@link Frame#materialize()} to + * create a {@link MaterializedFrame}. + */ final class DefaultMaterializedFrame implements MaterializedFrame, PackedFrame { private final DefaultVirtualFrame wrapped; - protected DefaultMaterializedFrame(DefaultVirtualFrame wrapped) { + DefaultMaterializedFrame(DefaultVirtualFrame wrapped) { this.wrapped = wrapped; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultPackedFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultPackedFrame.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultPackedFrame.java Wed Mar 05 19:40:15 2014 -0800 @@ -26,11 +26,15 @@ import com.oracle.truffle.api.frame.*; +/** + * This is an implementation-specific class. Do not use or instantiate it. Instead, use + * {@link Frame#pack()} to create a {@link PackedFrame}. + */ final class DefaultPackedFrame implements PackedFrame { private final DefaultVirtualFrame wrapped; - protected DefaultPackedFrame(DefaultVirtualFrame wrapped) { + DefaultPackedFrame(DefaultVirtualFrame wrapped) { this.wrapped = wrapped; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Wed Mar 05 19:40:15 2014 -0800 @@ -31,19 +31,32 @@ /** * Default implementation of the Truffle runtime if the virtual machine does not provide a better * performing alternative. + *

+ * This is an implementation-specific class. Do not use or instantiate it. Instead, use + * {@link Truffle#getRuntime()} to retrieve the current {@link TruffleRuntime}. */ public final class DefaultTruffleRuntime implements TruffleRuntime { + public DefaultTruffleRuntime() { + if (Truffle.getRuntime() != null) { + throw new IllegalArgumentException("Cannot instantiate DefaultTruffleRuntime. Use Truffle.getRuntime() instead."); + } + } + @Override public String getName() { return "Default Truffle Runtime"; } @Override - public CallTarget createCallTarget(RootNode rootNode) { + public RootCallTarget createCallTarget(RootNode rootNode) { return new DefaultCallTarget(rootNode); } + public CallNode createCallNode(CallTarget target) { + return new DefaultCallNode(target); + } + @Override public VirtualFrame createVirtualFrame(PackedFrame caller, Arguments arguments, FrameDescriptor frameDescriptor) { return new DefaultVirtualFrame(frameDescriptor, caller, arguments); diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Wed Mar 05 19:40:15 2014 -0800 @@ -29,7 +29,12 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; -public final class DefaultVirtualFrame implements VirtualFrame { +/** + * This is an implementation-specific class. Do not use or instantiate it. Instead, use + * {@link TruffleRuntime#createVirtualFrame(PackedFrame, Arguments, FrameDescriptor)} to create a + * {@link VirtualFrame}. + */ +final class DefaultVirtualFrame implements VirtualFrame { private final FrameDescriptor descriptor; private final PackedFrame caller; @@ -37,7 +42,7 @@ private Object[] locals; private byte[] tags; - public DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) { + DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) { this.descriptor = descriptor; this.caller = caller; this.arguments = arguments; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2012, 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. 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.*; + +/** + * This node represents a call to a static {@link CallTarget}. This node should be used whenever a + * {@link CallTarget} is considered constant at a certain location in the tree. This enables the + * Truffle runtime to perform inlining or other optimizations for this call-site. This class is + * intended to be implemented by truffle runtime implementors and not by guest language + * implementors. + * + * @see #create(CallTarget) to create a CallNode instance. + */ +public abstract class CallNode extends Node { + + protected final CallTarget callTarget; + + protected CallNode(CallTarget callTarget) { + this.callTarget = callTarget; + } + + /** + * Calls this constant target passing a caller frame and arguments. + * + * @param caller the caller frame + * @param arguments the arguments that should be passed to the callee + * @return the return result of the call + */ + public abstract Object call(PackedFrame caller, Arguments arguments); + + /** + * Returns the originally supplied {@link CallTarget} when this call node was created. Please + * note that the returned {@link CallTarget} is not necessarily the {@link CallTarget} that is + * called. For that use {@link #getCurrentCallTarget()} instead. + * + * @return the {@link CallTarget} provided. + */ + public CallTarget getCallTarget() { + return callTarget; + } + + /** + * @return true if this {@link CallNode} was already inlined. + */ + public abstract boolean isInlined(); + + public abstract void inline(); + + public abstract boolean isSplittable(); + + public abstract boolean split(); + + public final boolean isSplit() { + return getSplitCallTarget() != null; + } + + public abstract CallTarget getSplitCallTarget(); + + /** + * Returns the used call target when {@link #call(PackedFrame, Arguments)} is invoked. If the + * {@link CallNode} was split this method returns the {@link CallTarget} returned by + * {@link #getSplitCallTarget()}. If not split this method returns the original supplied + * {@link CallTarget}. + * + * @return the used {@link CallTarget} when node is called + */ + public CallTarget getCurrentCallTarget() { + CallTarget split = getSplitCallTarget(); + if (split != null) { + return split; + } else { + return getCallTarget(); + } + } + + @Override + protected void onReplace(Node newNode, String reason) { + super.onReplace(newNode, reason); + + /* + * Old call nodes are removed in the old target root node. + */ + CallNode oldCall = this; + RootNode oldRoot = getCurrentRootNode(); + if (oldRoot != null) { + oldRoot.removeCachedCallNode(oldCall); + } + + registerCallTarget((CallNode) newNode); + } + + protected static final void registerCallTarget(CallNode newNode) { + RootNode newRoot = newNode.getCurrentRootNode(); + if (newRoot != null) { + newRoot.addCachedCallNode(newNode); + } + } + + protected void notifyCallNodeAdded() { + + } + + /** + * Returns the {@link RootNode} associated with {@link CallTarget} returned by + * {@link #getCurrentCallTarget()}. + * + * @see #getCurrentCallTarget() + * @return the root node of the used call target + */ + public final RootNode getCurrentRootNode() { + CallTarget target = getCurrentCallTarget(); + if (target instanceof RootCallTarget) { + return ((RootCallTarget) target).getRootNode(); + } + return null; + } + + /** + * @deprecated always returns true now. + */ + @Deprecated + public boolean isInlinable() { + return true; + } + + /** + * @deprecated instead use {@link #getCurrentRootNode()} and check for {@link #isInlined()} for + * true. + */ + @Deprecated + public RootNode getInlinedRoot() { + if (!isInlined()) { + return null; + } + return getCurrentRootNode(); + } + + /** + * @deprecated use {@link TruffleRuntime#createCallNode(CallTarget)} instead + */ + @Deprecated + public static CallNode create(CallTarget target) { + return Truffle.getRuntime().createCallNode(target); + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ControlFlowException.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ControlFlowException.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ControlFlowException.java Wed Mar 05 19:40:15 2014 -0800 @@ -36,6 +36,12 @@ * Creates an exception thrown to model control flow. */ public ControlFlowException() { + /* + * We use the super constructor that initializes the cause to null. Without that, the cause + * would be this exception itself. This helps escape analysis: it avoids the circle of an + * object pointing to itself. + */ + super((Throwable) null); } /** diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Wed Mar 05 19:40:15 2014 -0800 @@ -169,7 +169,7 @@ } } - public void printToNetwork() { + public void printToNetwork(boolean ignoreErrors) { try { Transformer tr = TransformerFactory.newInstance().newTransformer(); tr.setOutputProperty(OutputKeys.METHOD, "xml"); @@ -178,7 +178,9 @@ BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000); tr.transform(new DOMSource(dom), new StreamResult(stream)); } catch (TransformerException | IOException e) { - e.printStackTrace(); + if (!ignoreErrors) { + e.printStackTrace(); + } } } @@ -341,6 +343,13 @@ LinkedHashMap nodes = new LinkedHashMap<>(); NodeClass nodeClass = NodeClass.get(node.getClass()); + if (node instanceof CallNode) { + CallNode callNode = ((CallNode) node); + RootNode inlinedRoot = callNode.getCurrentRootNode(); + if (inlinedRoot != null && callNode.isInlined()) { + nodes.put("inlinedRoot", inlinedRoot); + } + } for (NodeField field : nodeClass.getFields()) { NodeFieldKind kind = field.getKind(); if (kind == NodeFieldKind.CHILD || kind == NodeFieldKind.CHILDREN) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinableCallSite.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinableCallSite.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +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.*; - -/** - * Denotes a call node that can inline the tree of its associated call target. - * - * @see InlinedCallSite - */ -public interface InlinableCallSite { - - /** - * Returns the number of calls since the last reset of the call count. - * - * @return the current call count. - */ - int getCallCount(); - - /** - * Resets the call count to 0. - */ - void resetCallCount(); - - /** - * Returns the tree that would be inlined by a call to {@link #inline(FrameFactory)}. - * - * @return the node tree to be inlined. - */ - Node getInlineTree(); - - /** - * Returns the call target associated with this call site. - * - * @return the inlinable {@link CallTarget}. - */ - CallTarget getCallTarget(); - - /** - * Instructs the call node to inline the associated call target. - * - * @param factory Frame factory for creating new virtual frames for inlined calls. - * @return {@code true} if call target was inlined; {@code false} otherwise. - */ - boolean inline(FrameFactory factory); -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinedCallSite.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinedCallSite.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +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.*; - -/** - * Denotes a call node with an inlined call target. Allows for recursive call detection. - * - * @see InlinableCallSite - */ -public interface InlinedCallSite { - - /** - * Returns the call target that has been inlined at this call site. - * - * @return the inlined call target. - */ - CallTarget getCallTarget(); -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Mar 05 19:40:15 2014 -0800 @@ -82,6 +82,14 @@ this.sourceSection = section; } + public Kind getKind() { + NodeInfo info = getClass().getAnnotation(NodeInfo.class); + if (info != null) { + return info.kind(); + } + return Kind.SPECIALIZED; + } + /** * Clears any previously assigned guest language source code from this node. */ @@ -172,7 +180,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."); } @@ -185,7 +193,7 @@ if (!NodeUtil.replaceChild(this.parent, this, newNode)) { fixupTree(); } - reportReplace(); + reportReplace(this, newNode, reason); return newNode; } @@ -245,11 +253,12 @@ return false; } - private void reportReplace() { + private void reportReplace(Node oldNode, Node newNode, String reason) { RootNode rootNode = getRootNode(); if (rootNode != null) { - if (rootNode.getCallTarget() instanceof ReplaceObserver) { - ((ReplaceObserver) rootNode.getCallTarget()).nodeReplaced(); + CallTarget target = rootNode.getCallTarget(); + if (target instanceof ReplaceObserver) { + ((ReplaceObserver) target).nodeReplaced(oldNode, newNode, reason); } } } @@ -395,7 +404,7 @@ * * @return the {@link RootNode} or {@code null} if there is none. */ - protected final RootNode getRootNode() { + public final RootNode getRootNode() { Node rootNode = this; while (rootNode.getParent() != null) { assert !(rootNode instanceof RootNode) : "root node must not have a parent"; diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Mar 05 19:40:15 2014 -0800 @@ -34,6 +34,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.Node.Children; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * Utility class that manages the special access methods for node instances. @@ -451,6 +452,48 @@ return null; } + /** + * @deprecated will be removed, exposed Truffle runtime specific functionality. + */ + @Deprecated + public static List findOutermostCallTargets(Node node) { + RootNode root = node.getRootNode(); + if (root == null) { + return Collections.emptyList(); + } + List roots = new ArrayList<>(); + roots.add(root.getCallTarget()); + for (CallNode callNode : root.getCachedCallNodes()) { + if (callNode.isInlined()) { + roots.addAll(findOutermostCallTargets(callNode)); + } + } + return roots; + } + + /** + * @deprecated will be removed, exposed Truffle runtime specific functionality. + */ + @Deprecated + public static RootNode findOutermostRootNode(Node node) { + Node parent = node; + while (parent != null) { + if (parent instanceof RootNode) { + RootNode root = (RootNode) parent; + @SuppressWarnings("deprecation") + Node next = root.getParentInlinedCall(); + if (next != null) { + parent = next; + } else { + return root; + } + } else { + parent = parent.getParent(); + } + } + return null; + } + public static T findParent(Node start, Class clazz) { Node parent = start.getParent(); if (parent == null) { @@ -571,36 +614,87 @@ } public static int countNodes(Node root) { - return countNodes(root, null); + return countNodes(root, null, null, false); } - public static int countNodes(Node root, Class clazz) { - NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz); + public static int countNodes(Node root, Class clazz, Kind nodeKind, boolean countInlinedCallNodes) { + NodeCountVisitor nodeCount = new NodeCountVisitor(clazz, nodeKind, countInlinedCallNodes); root.accept(nodeCount); return nodeCount.nodeCount; } + public static int countNodes(Node root, Class clazz, boolean countInlinedCallNodes) { + return countNodes(root, clazz, null, countInlinedCallNodes); + } + private static final class NodeCountVisitor implements NodeVisitor { + private final boolean inspectInlinedCalls; int nodeCount; - private final Node root; + private final Kind kind; private final Class clazz; - private NodeCountVisitor(Node root, Class clazz) { - this.root = root; + private NodeCountVisitor(Class clazz, Kind kind, boolean inspectInlinedCalls) { this.clazz = clazz; + this.kind = kind; + this.inspectInlinedCalls = inspectInlinedCalls; } @Override public boolean visit(Node node) { - if (node instanceof RootNode && node != root) { - return false; - } - if (clazz == null || clazz.isInstance(node)) { + if ((clazz == null || clazz.isInstance(node)) && (kind == null || isKind(node))) { nodeCount++; } + + if (inspectInlinedCalls && node instanceof CallNode) { + CallNode call = (CallNode) node; + if (call.isInlined()) { + Node target = ((RootCallTarget) call.getCurrentCallTarget()).getRootNode(); + if (target != null) { + target.accept(this); + } + } + } + return true; } + + private boolean isKind(Node n) { + return kind == n.getKind(); + } + } + + public static void printInliningTree(final PrintStream stream, RootNode root) { + printRootNode(stream, 0, root); + root.accept(new NodeVisitor() { + int depth = 1; + + public boolean visit(Node node) { + if (node instanceof CallNode) { + CallNode callNode = ((CallNode) node); + RootNode inlinedRoot = callNode.getCurrentRootNode(); + if (inlinedRoot != null && callNode.isInlined()) { + depth++; + printRootNode(stream, depth * 2, inlinedRoot); + inlinedRoot.accept(this); + depth--; + } + } + return true; + } + }); + } + + private static void printRootNode(PrintStream stream, int indent, RootNode root) { + for (int i = 0; i < indent; i++) { + stream.print(" "); + } + stream.print(root.toString()); + stream.print(" ("); + stream.print(countNodes(root)); + stream.print("/"); + stream.print(countNodes(root, null, true)); + stream.println(")"); } public static String printCompactTreeToString(Node node) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,8 @@ */ package com.oracle.truffle.api.nodes; +import java.util.*; + import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; @@ -37,6 +39,11 @@ private CallTarget callTarget; private final FrameDescriptor frameDescriptor; + /* + * Internal set to keep back-references to the call-sites. + */ + private final Set cachedCallNodes = Collections.newSetFromMap(new WeakHashMap()); + protected RootNode() { this(null, null); } @@ -55,6 +62,51 @@ } /** + * @deprecated Not required anymore. Do not use. + */ + @Deprecated + public RootNode inline() { + if (!isInlinable()) { + throw new UnsupportedOperationException("Inlining is not enabled."); + } + return split(); + } + + /** + * @deprecated Not required anymore. Do not use. + */ + @Deprecated + public int getInlineNodeCount() { + return 0; + } + + /** + * @deprecated Not required anymore. Do not use. + */ + @Deprecated + public boolean isInlinable() { + return true; + } + + public RootNode split() { + return NodeUtil.cloneNode(this); + } + + public boolean isSplittable() { + return false; + } + + /** + * Reports the execution count of a loop that is a child of this node. The optimization + * heuristics can use the loop count to guide compilation and inlining. + */ + public void reportLoopCount(int count) { + if (getCallTarget() instanceof LoopCountReceiver) { + ((LoopCountReceiver) getCallTarget()).reportLoopCount(count); + } + } + + /** * Executes this function using the specified frame and returns the result value. * * @param frame the frame of the currently executing guest language method @@ -66,11 +118,47 @@ return callTarget; } - public FrameDescriptor getFrameDescriptor() { + public final FrameDescriptor getFrameDescriptor() { return frameDescriptor; } - public void setCallTarget(CallTarget callTarget) { + public final void setCallTarget(CallTarget callTarget) { this.callTarget = callTarget; } + + /* Internal API. Do not use. */ + void addCachedCallNode(CallNode callSite) { + if (cachedCallNodes.add(callSite)) { + for (CallNode callNode : cachedCallNodes) { + if (callSite != callNode) { + callNode.notifyCallNodeAdded(); + } + } + } + } + + /* Internal API. Do not use. */ + void removeCachedCallNode(CallNode callSite) { + this.cachedCallNodes.remove(callSite); + } + + /** + * Returns a {@link Set} of {@link CallNode} nodes which are created to invoke this RootNode. + * This method does not make any guarantees to contain all the {@link CallNode} nodes that are + * invoking this method. Due to its weak nature the elements returned by this method may change + * with each consecutive call. + * + * @return a set of {@link CallNode} nodes + */ + public final Set getCachedCallNodes() { + return Collections.unmodifiableSet(cachedCallNodes); + } + + /** + * @deprecated use {@link #getCachedCallNodes()} instead. + */ + @Deprecated + public final CallNode getParentInlinedCall() { + return cachedCallNodes.isEmpty() ? null : cachedCallNodes.iterator().next(); + } } diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Wed Mar 05 19:40:15 2014 -0800 @@ -43,8 +43,8 @@ public static final String OPTION_DETAILED_REWRITE_REASONS = "DetailedRewriteReasons"; - private final TypeMirror node; - private final TypeMirror nodeArray; + private final DeclaredType node; + private final ArrayType nodeArray; private final TypeMirror unexpectedValueException; private final TypeMirror frame; private final TypeMirror assumption; @@ -131,11 +131,11 @@ return compilerDirectives; } - public TypeMirror getNode() { + public DeclaredType getNode() { return node; } - public TypeMirror getNodeArray() { + public ArrayType getNodeArray() { return nodeArray; } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/api/ExtensionProcessor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/api/ExtensionProcessor.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.dsl.processor.api; - -import javax.lang.model.element.*; - -public interface ExtensionProcessor { - - void process(ExtensionContext context, AnnotationMirror mirror, Element element); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeVariable.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeVariable.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.dsl.processor.ast; - -public class CodeTreeVariable extends CodeTree { - - private final String name; - - private CodeTree value; - - public CodeTreeVariable() { - super(CodeTreeKind.GROUP, null, null); - this.name = ""; - } - - public CodeTreeVariable(String name) { - super(CodeTreeKind.GROUP, null, null); - this.name = name; - } - - public String getName() { - return name; - } - - public void set(CodeTree tree) { - if (value == tree) { - return; - } - if (this.value != null) { - remove(this.value); - } - this.value = tree; - add(tree); - } - - public CodeTree get() { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Mar 05 19:40:15 2014 -0800 @@ -99,6 +99,22 @@ return param.getLocalName(); } + private static CodeTree createAccessChild(NodeExecutionData targetExecution) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + Element accessElement = targetExecution.getChild().getAccessElement(); + if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { + builder.string("this.").string(targetExecution.getChild().getName()); + } else if (accessElement.getKind() == ElementKind.FIELD) { + builder.string("this.").string(accessElement.getSimpleName().toString()); + } else { + throw new AssertionError(); + } + if (targetExecution.isIndexed()) { + builder.string("[" + targetExecution.getIndex() + "]"); + } + return builder.getRoot(); + } + private static String castValueName(ActualParameter parameter) { return valueName(parameter) + "Cast"; } @@ -155,18 +171,14 @@ } private String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) { - if (sourceParameter != null) { - if (!sourceParameter.getSpecification().isSignature()) { - return valueName(targetParameter); - } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) { - if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), targetParameter.getTypeSystemType())) { - return castValueName(targetParameter); - } + if (!sourceParameter.getSpecification().isSignature()) { + return valueName(targetParameter); + } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) { + if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), targetParameter.getTypeSystemType())) { + return castValueName(targetParameter); } - return valueName(targetParameter); - } else { - return valueName(targetParameter); } + return valueName(targetParameter); } private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName, @@ -331,11 +343,36 @@ } protected void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) { - builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); - builder.startCall("createInfo0"); - builder.doubleQuote("Unsupported values"); - addInternalValueParameterNames(builder, current, current, null, false, null); - builder.end().end().end(); + CodeTreeBuilder nodes = builder.create(); + CodeTreeBuilder arguments = builder.create(); + nodes.startCommaGroup(); + arguments.startCommaGroup(); + boolean empty = true; + for (ActualParameter parameter : current.getParameters()) { + NodeExecutionData executionData = parameter.getSpecification().getExecution(); + if (executionData != null) { + if (executionData.isShortCircuit()) { + nodes.nullLiteral(); + arguments.string(valueName(parameter.getPreviousParameter())); + } + nodes.tree(createAccessChild(executionData)); + arguments.string(valueName(parameter)); + empty = false; + } + } + nodes.end(); + arguments.end(); + + builder.startThrow().startNew(getContext().getType(UnsupportedSpecializationException.class)); + builder.string("this"); + builder.startNewArray(getContext().getTruffleTypes().getNodeArray(), null); + + builder.tree(nodes.getRoot()); + builder.end(); + if (!empty) { + builder.tree(arguments.getRoot()); + } + builder.end().end(); } private static List findUserConstructors(TypeMirror nodeType) { @@ -502,7 +539,6 @@ TypeMirror nodeFactory = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType()); clazz.getImplements().add(nodeFactory); clazz.add(createCreateNodeMethod(node)); - clazz.add(createCreateNodeGenericMethod(node)); clazz.add(createGetNodeClassMethod(node)); clazz.add(createGetNodeSignaturesMethod()); clazz.add(createGetChildrenSignatureMethod(node)); @@ -672,22 +708,6 @@ return method; } - private CodeExecutableElement createCreateNodeGenericMethod(NodeData node) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeGeneric"); - CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME); - method.addParameter(nodeParam); - - CodeTreeBuilder builder = method.createBuilder(); - if (!node.needsRewrites(getContext())) { - builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).doubleQuote("No specialized version.").end().end(); - } else { - builder.startReturn().startCall("createGeneric"); - builder.string(THIS_NODE_LOCAL_VAR_NAME); - builder.end().end(); - } - return method; - } - private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class)); TypeMirror returnType = Utils.getDeclaredType(nodeFactoryType, node.getNodeType()); @@ -933,12 +953,32 @@ if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) { clazz.add(createGenericExecute(node, rootGroup)); } + + clazz.add(createGetKind(node, null, Kind.SPECIALIZED)); } protected boolean needsInvokeCopyConstructorMethod() { return getModel().getNode().isPolymorphic(); } + protected CodeExecutableElement createGetKind(NodeData node, SpecializationData specialization, Kind kind) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getNodeInfoKind(), "getKind"); + + TypeMirror nodeInfoKind = context.getTruffleTypes().getNodeInfoKind(); + + CodeTreeBuilder builder = method.createBuilder(); + if (node.isPolymorphic() && specialization == null) { + // assume next0 exists + builder.startIf().string("next0 != null && next0.getKind() == ").staticReference(nodeInfoKind, "SPECIALIZED").end(); + builder.startBlock(); + builder.startReturn().staticReference(nodeInfoKind, "POLYMORPHIC").end(); + builder.end(); + } + + builder.startReturn().staticReference(nodeInfoKind, kind.name()).end(); + return method; + } + protected CodeExecutableElement createInvokeCopyConstructor(TypeMirror baseType, SpecializationData specialization) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), baseType, "invokeCopyConstructor"); if (specialization == null) { @@ -966,16 +1006,12 @@ for (ActualParameter param : getModel().getSignatureParameters()) { NodeExecutionData execution = param.getSpecification().getExecution(); - CodeTreeBuilder access = builder.create(); - access.string("this.").string(execution.getChild().getName()); - if (execution.isIndexed()) { - access.string("[").string(String.valueOf(execution.getIndex())).string("]"); - } + CodeTree access = createAccessChild(execution); String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName()); oldBuilder.declaration(execution.getChild().getNodeData().getNodeType(), oldName, access); - nullBuilder.startStatement().tree(access.getRoot()).string(" = null").end(); - resetBuilder.startStatement().tree(access.getRoot()).string(" = ").string(oldName).end(); + nullBuilder.startStatement().tree(access).string(" = null").end(); + resetBuilder.startStatement().tree(access).string(" = ").string(oldName).end(); } builder.tree(oldBuilder.getRoot()); @@ -2275,7 +2311,7 @@ private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, ActualParameter unexpectedParameter) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); if (targetExecution != null) { - builder.tree(createAccessChild(builder, targetExecution)); + builder.tree(createAccessChild(targetExecution)); builder.string("."); } @@ -2329,22 +2365,6 @@ return builder.getRoot(); } - private CodeTree createAccessChild(CodeTreeBuilder parent, NodeExecutionData targetExecution) throws AssertionError { - CodeTreeBuilder builder = parent.create(); - Element accessElement = targetExecution.getChild().getAccessElement(); - if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { - builder.string("this.").string(targetExecution.getChild().getName()); - } else if (accessElement.getKind() == ElementKind.FIELD) { - builder.string("this.").string(accessElement.getSimpleName().toString()); - } else { - throw new AssertionError(); - } - if (targetExecution.isIndexed()) { - builder.string("[" + targetExecution.getIndex() + "]"); - } - return builder.getRoot(); - } - private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { NodeExecutionData execution = parameter.getSpecification().getExecution(); if (execution == null || !execution.isShortCircuit()) { @@ -2503,7 +2523,7 @@ } createCachedExecuteMethods(specialization); - + clazz.add(createGetKind(specialization.getNode(), specialization, Kind.SPECIALIZED)); } private ExecutableElement createUpdateType(ActualParameter parameter) { @@ -2587,6 +2607,12 @@ if (needsInvokeCopyConstructorMethod()) { clazz.add(createInvokeCopyConstructor(nodeGen.asType(), specialization)); } + + if (specialization.isGeneric()) { + clazz.add(createGetKind(specialization.getNode(), specialization, Kind.GENERIC)); + } else if (specialization.isUninitialized()) { + clazz.add(createGetKind(specialization.getNode(), specialization, Kind.UNINITIALIZED)); + } } protected void createConstructors(CodeTypeElement clazz) { diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationListenerData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationListenerData.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.dsl.processor.node; - -import com.oracle.truffle.dsl.processor.template.*; - -public class SpecializationListenerData extends TemplateMethod { - - public SpecializationListenerData(TemplateMethod method) { - super(method); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/JavaName.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/JavaName.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.dsl.processor.template; - -import java.util.*; -import java.util.regex.*; - -public final class JavaName { - - private static final String[] RESERVED_NAMES = new String[]{"abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do", "if", - "private", "this", "break", "double", "implements", "protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", - "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", - "while"}; - - private static final Set RESERVED_NAMES_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(RESERVED_NAMES))); - - private static final Pattern VALID_JAVA_NAME_PATTERN = Pattern.compile("[_a-zA-z][_a-zA-Z0-9]*"); - - private JavaName() { - super(); - } - - public static boolean isReserved(String name) { - return RESERVED_NAMES_SET.contains(name); - } - - public static boolean isValid(String typeName) { - return VALID_JAVA_NAME_PATTERN.matcher(typeName).matches(); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSource.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSource.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import java.io.*; - -import com.oracle.truffle.api.*; - -/** - * Singleton source used for core method nodes. - */ -public final class CoreSource implements Source { - - private final String name; - - public CoreSource(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public String getCode() { - return name; - } - - @Override - public String toString() { - return name; - } - - public String getPath() { - return null; - } - - public Reader getReader() { - return null; - } - - public InputStream getInputStream() { - return null; - } - - public String getCode(int lineNumber) { - return null; - } - - public int getLineCount() { - return 0; - } - - public int getLineNumber(int offset) { - return 0; - } - - public int getLineStartOffset(int lineNumber) { - return 0; - } - - public int getLineLength(int lineNumber) { - return 0; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSourceSection.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSourceSection.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +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.nodes; - -import com.oracle.truffle.api.*; - -/** - * Source sections used for core method nodes. - */ -public final class CoreSourceSection implements NullSourceSection { - - private final String name; - - public CoreSourceSection(String name) { - this.name = name; - } - - public Source getSource() { - return new CoreSource(name); - } - - public int getStartLine() { - return 0; - } - - public int getStartColumn() { - return 0; - } - - public int getCharIndex() { - return 0; - } - - @Override - public int getCharLength() { - return 0; - } - - public int getCharEndIndex() { - return 0; - } - - public String getIdentifier() { - return null; - } - - public String getCode() { - return name; - } - - @Override - public String toString() { - return name; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/DefinedNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/DefinedNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Switches execution to the parallel {@link RubyNode#isDefined} semantic path. Represents the - * {@code defined?} keyword in Ruby. - */ -@NodeInfo(shortName = "defined") -public class DefinedNode extends RubyNode { - - @Child protected RubyNode child; - - public DefinedNode(RubyContext context, SourceSection sourceSection, RubyNode child) { - super(context, sourceSection); - this.child = adoptChild(child); - } - - @Override - public Object execute(VirtualFrame frame) { - return child.isDefined(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/InlinableMethodImplementation.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/InlinableMethodImplementation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * A method implementation that also carries the pristine root node and frame descriptor, from which - * we can inline. - * - * @see InlinedUnboxedDispatchNode - * @see InlinedBoxedDispatchNode - * @see InlineHeuristic - */ -public class InlinableMethodImplementation extends CallTargetMethodImplementation { - - private final FrameDescriptor frameDescriptor; - private final RubyRootNode pristineRootNode; - - public final boolean alwaysInline; - public final boolean shouldAppendCallNode; - - public InlinableMethodImplementation(CallTarget callTarget, MaterializedFrame declarationFrame, FrameDescriptor frameDescriptor, RubyRootNode pristineRootNode, boolean alwaysInline, - boolean shouldAppendCallNode) { - super(callTarget, declarationFrame); - - assert frameDescriptor != null; - assert pristineRootNode != null; - - this.frameDescriptor = frameDescriptor; - this.pristineRootNode = pristineRootNode; - this.alwaysInline = alwaysInline; - this.shouldAppendCallNode = shouldAppendCallNode; - } - - public FrameDescriptor getFrameDescriptor() { - return frameDescriptor; - } - - public RubyRootNode getPristineRootNode() { - return pristineRootNode; - } - - public RubyRootNode getCloneOfPristineRootNode() { - return NodeUtil.cloneNode(pristineRootNode); - } - - public boolean alwaysInline() { - return alwaysInline; - } - - public boolean getShouldAppendCallNode() { - return shouldAppendCallNode; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/ReadNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/ReadNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013 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; - -/** - * Interface for all nodes which read something, providing a method to transform them to write the - * same thing. - */ -public interface ReadNode { - - /** - * Return a new node that performs the equivalent write operation to this node's read, using the - * supplied node for the right-hand-side. - */ - RubyNode makeWriteNode(RubyNode rhs); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +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.nodes; - -import java.math.*; - -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.ruby.nodes.call.*; -import com.oracle.truffle.ruby.nodes.instrument.*; -import com.oracle.truffle.ruby.nodes.yield.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.core.range.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Base class for most nodes in Ruby. - * - * @see DispatchNode - * @see YieldDispatchNode - */ -@TypeSystemReference(RubyTypes.class) -public abstract class RubyNode extends Node { - - private final RubyContext context; - - public RubyNode(RubyContext context, SourceSection sourceSection) { - super(sourceSection); - - assert context != null; - assert sourceSection != null; - - this.context = context; - } - - public RubyNode(RubyNode prev) { - this(prev.context, prev.getSourceSection()); - } - - public abstract Object execute(VirtualFrame frame); - - /** - * Ruby's parallel semantic path. - * - * @see DefinedNode - */ - public Object isDefined(@SuppressWarnings("unused") VirtualFrame frame) { - throw new UnsupportedOperationException("no definition for " + getClass().getName()); - } - - public RubyArray executeArray(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyArray(execute(frame)); - } - - public BigInteger executeBignum(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectBigInteger(execute(frame)); - } - - public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectBoolean(execute(frame)); - } - - public RubyBignum executeBoxedBignum(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyBignum(execute(frame)); - } - - public RubyFixnum executeBoxedFixnum(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyFixnum(execute(frame)); - } - - public RubyFloat executeBoxedFloat(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyFloat(execute(frame)); - } - - public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectInteger(execute(frame)); - } - - public FixnumRange executeFixnumRange(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectFixnumRange(execute(frame)); - } - - public double executeFloat(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectDouble(execute(frame)); - } - - public NilPlaceholder executeNilPlaceholder(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectNilPlaceholder(execute(frame)); - } - - public Node executeNode(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectNode(execute(frame)); - } - - public Object[] executeObjectArray(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectObjectArray(execute(frame)); - } - - public ObjectRange executeObjectRange(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectObjectRange(execute(frame)); - } - - public RubyBasicObject executeRubyBasicObject(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyBasicObject(execute(frame)); - } - - public RubyBinding executeRubyBinding(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyBinding(execute(frame)); - } - - public RubyClass executeRubyClass(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyClass(execute(frame)); - } - - public RubyContinuation executeRubyContinuation(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyContinuation(execute(frame)); - } - - public RubyException executeRubyException(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyException(execute(frame)); - } - - public RubyFiber executeRubyFiber(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyFiber(execute(frame)); - } - - public RubyFile executeRubyFile(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyFile(execute(frame)); - } - - public RubyHash executeRubyHash(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyHash(execute(frame)); - } - - public RubyMatchData executeRubyMatchData(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyMatchData(execute(frame)); - } - - public RubyMethod executeRubyMethod(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyMethod(execute(frame)); - } - - public RubyModule executeRubyModule(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyModule(execute(frame)); - } - - public RubyNilClass executeRubyNilClass(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyNilClass(execute(frame)); - } - - public RubyObject executeRubyObject(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyObject(execute(frame)); - } - - public RubyProc executeRubyProc(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyProc(execute(frame)); - } - - public RubyRange executeRubyRange(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyRange(execute(frame)); - } - - public RubyRegexp executeRubyRegexp(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyRegexp(execute(frame)); - } - - public RubySymbol executeRubySymbol(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubySymbol(execute(frame)); - } - - public RubyThread executeRubyThread(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyThread(execute(frame)); - } - - public RubyTime executeRubyTime(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyTime(execute(frame)); - } - - public RubyString executeString(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectRubyString(execute(frame)); - } - - public UndefinedPlaceholder executeUndefinedPlaceholder(VirtualFrame frame) throws UnexpectedResultException { - return RubyTypesGen.RUBYTYPES.expectUndefinedPlaceholder(execute(frame)); - } - - public void executeVoid(VirtualFrame frame) { - execute(frame); - } - - /** - * If you aren't sure whether you have a normal {@link RubyNode} or a {@link RubyProxyNode}, - * this method will return the real node, whether that is this node, or whether this node is a - * proxy and you actually need the child. - */ - public RubyNode getNonProxyNode() { - return this; - } - - public RubyContext getContext() { - return context; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyRootNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyRootNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * The root node in an AST for a method. Unlike {@link RubyNode}, this has a single entry point, - * {@link #execute}, which Truffle knows about and can create a {@link CallTarget} from. - */ -public class RubyRootNode extends RootNode { - - protected final String indicativeName; - @Child protected RubyNode body; - - public RubyRootNode(SourceSection sourceSection, FrameDescriptor descriptor, String indicativeName, RubyNode body) { - super(sourceSection, descriptor); - - assert indicativeName != null; - assert body != null; - - this.body = adoptChild(body); - this.indicativeName = indicativeName; - } - - @Override - public Object execute(VirtualFrame frame) { - return body.execute(frame); - } - - @Override - public String toString() { - final SourceSection sourceSection = getSourceSection(); - final String source = sourceSection == null ? "" : sourceSection.toString(); - return "Method " + indicativeName + ":" + source + "@" + Integer.toHexString(hashCode()); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyTypes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyTypes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import java.math.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.core.range.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * The list of types and type conversions that the AST interpreter knows about and can specialise - * using. Used by the DSL. - */ -@TypeSystem({UndefinedPlaceholder.class, // - NilPlaceholder.class, // - boolean.class, // - int.class, // - double.class, // - BigInteger.class, // - FixnumRange.class, // - ObjectRange.class, // - RubyArray.class, // - RubyBignum.class, // - RubyBinding.class, // - RubyClass.class, // - RubyContinuation.class, // - RubyException.class, // - RubyFiber.class, // - RubyFile.class, // - RubyFixnum.class, // - RubyFloat.class, // - RubyHash.class, // - RubyMatchData.class, // - RubyMethod.class, // - RubyModule.class, // - RubyNilClass.class, // - RubyProc.class, // - RubyRange.class, // - RubyRegexp.class, // - RubyString.class, // - RubySymbol.class, // - RubyThread.class, // - RubyTime.class, // - RubyObject.class, // - RubyBasicObject.class, // - Node.class, // - Object[].class}) -public class RubyTypes { - - /* - * The implicit casts allow the DSL to convert from an object of one type to another to satisfy - * specializations. - */ - - @ImplicitCast - public NilPlaceholder unboxNil(@SuppressWarnings("unused") RubyNilClass value) { - return NilPlaceholder.INSTANCE; - } - - @ImplicitCast - public int unboxFixnum(RubyFixnum value) { - return value.getValue(); - } - - @ImplicitCast - public BigInteger unboxBignum(RubyBignum value) { - return value.getValue(); - } - - @ImplicitCast - public double unboxFloat(RubyFloat value) { - return value.getValue(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/WriteNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/WriteNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2013 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; - -/** - * Interface for all nodes which write something, providing a method to transform them to read the - * same thing. - */ -public interface WriteNode { - - /** - * Return a new node that performs the equivalent read operation to this node's write. - */ - RubyNode makeReadNode(); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BooleanDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BooleanDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -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.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * An unboxed node in the dispatch chain that dispatches if the node is a boolean. In normal unboxed - * dispatch we look at the Java class of the receiver. However, in Ruby true and false are two - * separate classes, so in this situation we have to dispatch on the value, as well as the Java - * class when we are dealing with booleans. - *

- * TODO(CS): it would be nice if we could {@link RubyNode#executeBoolean} the receiver, but by the - * time we get to this dispatch node the receiver is already executed. - */ -public class BooleanDispatchNode extends UnboxedDispatchNode { - - private final Assumption falseUnmodifiedAssumption; - private final RubyMethod falseMethod; - - private final Assumption trueUnmodifiedAssumption; - private final RubyMethod trueMethod; - - @Child protected UnboxedDispatchNode next; - - public BooleanDispatchNode(RubyContext context, SourceSection sourceSection, Assumption falseUnmodifiedAssumption, RubyMethod falseMethod, Assumption trueUnmodifiedAssumption, - RubyMethod trueMethod, UnboxedDispatchNode next) { - super(context, sourceSection); - - assert falseUnmodifiedAssumption != null; - assert falseMethod != null; - assert trueUnmodifiedAssumption != null; - assert trueMethod != null; - - this.falseUnmodifiedAssumption = falseUnmodifiedAssumption; - this.falseMethod = falseMethod; - - this.trueUnmodifiedAssumption = trueUnmodifiedAssumption; - this.trueMethod = trueMethod; - - this.next = adoptChild(next); - } - - @Override - public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - // Check it's a boolean - - if (!(receiverObject instanceof Boolean)) { - return next.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - - // Check the value - - Assumption unmodifiedAssumption; - RubyMethod method; - - if ((boolean) receiverObject) { - unmodifiedAssumption = trueUnmodifiedAssumption; - method = trueMethod; - } else { - unmodifiedAssumption = falseUnmodifiedAssumption; - method = falseMethod; - } - - // Check the class has not been modified - - try { - unmodifiedAssumption.check(); - } catch (InvalidAssumptionException e) { - return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects); - } - - // Call the method - - return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects); - } - - @Override - public void setNext(UnboxedDispatchNode next) { - this.next = adoptChild(next); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * A node in the dispatch chain that expects the receiver to be an object boxed into a full - * {@link RubyBasicObject}. - */ -public abstract class BoxedDispatchNode extends DispatchNode { - - public BoxedDispatchNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public abstract Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxingDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxingDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * A node in the dispatch chain that boxes the receiver into a full Ruby {@link RubyBasicObject}. - * This node is initially created as an {@link UninitializedBoxingDispatchNode} and only becomes - * this node when we know that we do need to box on the fast path. Within this node we specialized - * for the case that the receiver is always already boxed. - */ -public class BoxingDispatchNode extends UnboxedDispatchNode { - - @Child protected BoxedDispatchNode next; - - private final BranchProfile boxBranch = new BranchProfile(); - - public BoxingDispatchNode(RubyContext context, SourceSection sourceSection, BoxedDispatchNode next) { - super(context, sourceSection); - - this.next = adoptChild(next); - } - - @Override - public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - RubyBasicObject boxedReceiverObject; - - if (receiverObject instanceof RubyBasicObject) { - boxedReceiverObject = (RubyBasicObject) receiverObject; - } else { - boxBranch.enter(); - boxedReceiverObject = getContext().getCoreLibrary().box(receiverObject); - } - - return next.dispatch(frame, boxedReceiverObject, blockObject, argumentsObjects); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedBoxedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedBoxedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -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.core.*; -import com.oracle.truffle.ruby.runtime.lookup.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * A node in the dispatch chain that comes after the boxing point and caches a method on a full - * boxed Ruby BasicObject, matching it by looking at the lookup node and assuming it has not been - * modified. - */ -public class CachedBoxedDispatchNode extends BoxedDispatchNode { - - private final LookupNode expectedLookupNode; - private final Assumption unmodifiedAssumption; - private final RubyMethod method; - - @Child protected BoxedDispatchNode next; - - public CachedBoxedDispatchNode(RubyContext context, SourceSection sourceSection, LookupNode expectedLookupNode, RubyMethod method, BoxedDispatchNode next) { - super(context, sourceSection); - - assert expectedLookupNode != null; - assert method != null; - - this.expectedLookupNode = expectedLookupNode; - unmodifiedAssumption = expectedLookupNode.getUnmodifiedAssumption(); - this.method = method; - this.next = adoptChild(next); - } - - @Override - public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - // Check the lookup node is what we expect - - if (receiverObject.getLookupNode() != expectedLookupNode) { - return next.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - - // Check the class has not been modified - - try { - unmodifiedAssumption.check(); - } catch (InvalidAssumptionException e) { - return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects); - } - - // Call the method - - return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedUnboxedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedUnboxedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -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.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * A node in the dispatch chain that comes before the boxing point and caches a method on a Java - * object, matching it by looking at the class and assuming it has not been modified. - */ -public class CachedUnboxedDispatchNode extends UnboxedDispatchNode { - - private final Class expectedClass; - private final Assumption unmodifiedAssumption; - private final RubyMethod method; - - @Child protected UnboxedDispatchNode next; - - public CachedUnboxedDispatchNode(RubyContext context, SourceSection sourceSection, Class expectedClass, Assumption unmodifiedAssumption, RubyMethod method, UnboxedDispatchNode next) { - super(context, sourceSection); - - assert expectedClass != null; - assert unmodifiedAssumption != null; - assert method != null; - - this.expectedClass = expectedClass; - this.unmodifiedAssumption = unmodifiedAssumption; - this.method = method; - this.next = adoptChild(next); - } - - @Override - public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - // Check the class is what we expect - - if (receiverObject.getClass() != expectedClass) { - return next.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - - // Check the class has not been modified - - try { - unmodifiedAssumption.check(); - } catch (InvalidAssumptionException e) { - return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects); - } - - // Call the method - - return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects); - } - - @Override - public void setNext(UnboxedDispatchNode next) { - this.next = adoptChild(next); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +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.nodes.call; - -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.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * A call node that has a chain of dispatch nodes. - *

- * The dispatch chain starts as {@link CallNode} -> {@link DispatchHeadNode} -> - * {@link UninitializedBoxingDispatchNode} -> {@link UninitializedDispatchNode}. - *

- * When the {@link UninitializedDispatchNode} is reached a new node is inserted into the chain. If - * the node dispatches based on some unboxed value (unboxed as in it's not a Ruby object, just a - * Java object) such as {@link Integer}, then that node is inserted before the - * {@link UninitializedBoxingDispatchNode}, otherwise if it dispatches based on some Ruby - * BasicObject, it is inserted afterwards. - *

- * The {@link UninitializedBoxingDispatchNode} becomes a {@link BoxingDispatchNode} when we find - * that the boxing has to be done on the fast path - when there is some boxed dispatch node. - *

- * So the general format is {@link CallNode} -> {@link DispatchHeadNode} -> zero or more - * unboxed dispatches -> {@link UninitializedBoxingDispatchNode} | {@link BoxingDispatchNode} - * -> zero or more boxed dispatches -> {@link UninitializedDispatchNode}. - *

- * There are several special cases of unboxed and boxed dispatch nodes based on the types and - * methods involved. - *

- * If we have too many dispatch nodes we replace the whole chain with {@link DispatchHeadNode} -> - * {@link BoxingDispatchNode} -> {@link GeneralBoxedDispatchNode}. - *

- * This system allows us to dispatch based purely on Java class, before we have to turn the object - * into a full {@link RubyBasicObject} and consider the full Ruby lookup process, and something such - * as a math call which may work on Fixnum or Float to work as just a couple of applications of - * {@code instanceof} and assumption checks. - */ -public class CallNode extends RubyNode { - - @Child protected RubyNode receiver; - @Child protected ProcOrNullNode block; - @Children protected final RubyNode[] arguments; - - private final String name; - private final boolean isSplatted; - - @Child protected DispatchHeadNode dispatchHead; - - public CallNode(RubyContext context, SourceSection section, String name, RubyNode receiver, RubyNode block, boolean isSplatted, RubyNode[] arguments) { - super(context, section); - - assert receiver != null; - assert arguments != null; - assert name != null; - - this.receiver = adoptChild(receiver); - - if (block == null) { - this.block = null; - } else { - this.block = adoptChild(ProcOrNullNodeFactory.create(context, section, block)); - } - - this.arguments = adoptChildren(arguments); - this.name = name; - this.isSplatted = isSplatted; - - dispatchHead = adoptChild(new DispatchHeadNode(context, section, name, isSplatted)); - } - - @Override - public Object execute(VirtualFrame frame) { - final Object receiverObject = receiver.execute(frame); - final Object[] argumentsObjects = executeArguments(frame); - final RubyProc blockObject = executeBlock(frame); - - return dispatchHead.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - - private RubyProc executeBlock(VirtualFrame frame) { - if (block != null) { - return block.executeRubyProc(frame); - } else { - return null; - } - } - - @ExplodeLoop - private Object[] executeArguments(VirtualFrame frame) { - final Object[] argumentsObjects = new Object[arguments.length]; - - for (int i = 0; i < arguments.length; i++) { - argumentsObjects[i] = arguments[i].execute(frame); - assert RubyContext.shouldObjectBeVisible(argumentsObjects[i]) : argumentsObjects[i].getClass(); - } - - if (isSplatted) { - assert argumentsObjects[0] instanceof RubyArray; - return ((RubyArray) argumentsObjects[0]).toObjectArray(); - } else { - return argumentsObjects; - } - } - - @Override - public Object isDefined(VirtualFrame frame) { - final RubyContext context = getContext(); - - Object receiverObject; - - try { - /* - * TODO(CS): Getting a node via an accessor like this doesn't work with Truffle at the - * moment and will cause frame escape errors, so we don't use it in compilation mode. - */ - - CompilerAsserts.neverPartOfCompilation(); - - receiverObject = receiver.execute(frame); - } catch (Exception e) { - return NilPlaceholder.INSTANCE; - } - - final RubyBasicObject receiverBasicObject = context.getCoreLibrary().box(receiverObject); - - final RubyMethod method = receiverBasicObject.getLookupNode().lookupMethod(name); - - final RubyBasicObject self = context.getCoreLibrary().box(frame.getArguments(RubyArguments.class).getSelf()); - - if (method == null || method.isUndefined()) { - return NilPlaceholder.INSTANCE; - } - - if (!method.isVisibleTo(self)) { - return NilPlaceholder.INSTANCE; - } - - return context.makeString("method"); - } - - public String getName() { - return name; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchHeadNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchHeadNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * The head of a chain of dispatch nodes. Can be used with {@link CallNode} or on its own. - */ -public class DispatchHeadNode extends DispatchNode { - - private final RubyContext context; - private final String name; - private final boolean isSplatted; - - @Child protected UnboxedDispatchNode dispatch; - - public DispatchHeadNode(RubyContext context, SourceSection sourceSection, String name, boolean isSplatted) { - super(context, sourceSection); - - assert context != null; - assert name != null; - - this.context = context; - this.name = name; - this.isSplatted = isSplatted; - - final UninitializedDispatchNode uninitializedDispatch = new UninitializedDispatchNode(context, sourceSection, name); - dispatch = adoptChild(new UninitializedBoxingDispatchNode(context, sourceSection, uninitializedDispatch)); - } - - public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object... argumentsObjects) { - return dispatch.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - - /** - * Replace the entire dispatch chain with a fresh chain. Used when the situation has changed in - * such a significant way that it's best to start again rather than add new specializations to - * the chain. Used for example when methods appear to have been monkey-patched. - */ - public Object respecialize(VirtualFrame frame, String reason, Object receiverObject, RubyProc blockObject, Object... argumentObjects) { - CompilerAsserts.neverPartOfCompilation(); - - replace(new DispatchHeadNode(context, getSourceSection(), name, isSplatted), reason); - - final RubyBasicObject receiverBasicObject = context.getCoreLibrary().box(receiverObject); - - final RubyMethod method = lookup(frame, receiverBasicObject, name); - return method.call(frame.pack(), receiverBasicObject, blockObject, argumentObjects); - } - - public UnboxedDispatchNode getDispatch() { - return dispatch; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -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.control.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Any node in the dispatch chain. - */ -public class DispatchNode extends Node { - - private final RubyContext context; - - public DispatchNode(RubyContext context, SourceSection sourceSection) { - super(sourceSection); - - assert context != null; - assert sourceSection != null; - - this.context = context; - } - - /** - * Get the depth of this node in the dispatch chain. The first node below - * {@link DispatchHeadNode} is at depth 1. - */ - public int getDepth() { - int depth = 1; - Node parent = this.getParent(); - - while (!(parent instanceof DispatchHeadNode)) { - parent = parent.getParent(); - depth++; - } - - return depth; - } - - public Object respecialize(String reason, VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object... argumentsObjects) { - CompilerAsserts.neverPartOfCompilation(); - - final int depth = getDepth(); - final DispatchHeadNode head = (DispatchHeadNode) NodeUtil.getNthParent(this, depth); - - return head.respecialize(frame, reason, receiverObject, blockObject, argumentsObjects); - } - - /** - * The central point for method lookup. - */ - protected RubyMethod lookup(VirtualFrame frame, RubyBasicObject receiverBasicObject, String name) { - final RubyMethod method = receiverBasicObject.getLookupNode().lookupMethod(name); - - final RubyBasicObject self = context.getCoreLibrary().box(frame.getArguments(RubyArguments.class).getSelf()); - - if (method == null || method.isUndefined()) { - CompilerDirectives.transferToInterpreter(); - throw new RaiseException(context.getCoreLibrary().nameErrorNoMethod(name, receiverBasicObject.toString())); - } - - if (!method.isVisibleTo(self)) { - CompilerDirectives.transferToInterpreter(); - throw new RaiseException(context.getCoreLibrary().noMethodError(name, receiverBasicObject.toString())); - } - - return method; - } - - public RubyContext getContext() { - return context; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralBoxedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralBoxedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * A node in the dispatch chain that does no caching and looks up methods from scratch each time it - * is called. - */ -public class GeneralBoxedDispatchNode extends BoxedDispatchNode { - - private final String name; - - public GeneralBoxedDispatchNode(RubyContext context, SourceSection sourceSection, String name) { - super(context, sourceSection); - - assert name != null; - - this.name = name; - } - - @Override - public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - /* - * TODO(CS): we should probably have some kind of cache here - even if it's just a hash map. - * MRI and JRuby do and might avoid some pathological cases. - */ - - final RubyMethod method = lookup(frame, receiverObject, name); - return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralSuperCallNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralSuperCallNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -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.control.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents a super call - that is a call with self as the receiver, but the superclass of self - * used for lookup. Currently implemented without any caching, and needs to be replaced with the - * same caching mechanism as for normal calls without complicating the existing calls too much. - */ -@NodeInfo(shortName = "general-super-call") -public class GeneralSuperCallNode extends RubyNode { - - private final String name; - private final boolean isSplatted; - @Child protected RubyNode block; - @Children protected final RubyNode[] arguments; - - public GeneralSuperCallNode(RubyContext context, SourceSection sourceSection, String name, RubyNode block, RubyNode[] arguments, boolean isSplatted) { - super(context, sourceSection); - - assert name != null; - assert arguments != null; - assert !isSplatted || arguments.length == 1; - - this.name = name; - this.block = adoptChild(block); - this.arguments = adoptChildren(arguments); - this.isSplatted = isSplatted; - } - - @ExplodeLoop - @Override - public final Object execute(VirtualFrame frame) { - // This method is only a simple implementation - it needs proper caching - - CompilerAsserts.neverPartOfCompilation(); - - final RubyBasicObject self = (RubyBasicObject) frame.getArguments(RubyArguments.class).getSelf(); - - // Execute the arguments - - final Object[] argumentsObjects = new Object[arguments.length]; - - CompilerAsserts.compilationConstant(arguments.length); - for (int i = 0; i < arguments.length; i++) { - argumentsObjects[i] = arguments[i].execute(frame); - } - - // Execute the block - - RubyProc blockObject; - - if (block != null) { - final Object blockTempObject = block.execute(frame); - - if (blockTempObject instanceof NilPlaceholder) { - blockObject = null; - } else { - blockObject = (RubyProc) blockTempObject; - } - } else { - blockObject = null; - } - - // Lookup method - - final RubyClass selfClass = self.getRubyClass(); - final RubyMethod method = selfClass.getSuperclass().lookupMethod(name); - - if (method == null || method.isUndefined()) { - CompilerDirectives.transferToInterpreter(); - throw new RaiseException(getContext().getCoreLibrary().nameErrorNoMethod(name, self.toString())); - } - - if (!method.isVisibleTo(self)) { - CompilerDirectives.transferToInterpreter(); - throw new RaiseException(getContext().getCoreLibrary().noMethodError("(unknown)")); - } - - // Call the method - - if (isSplatted) { - final RubyArray argumentsArray = (RubyArray) argumentsObjects[0]; - return method.call(frame.pack(), self, blockObject, argumentsArray.asList().toArray()); - } else { - return method.call(frame.pack(), self, blockObject, argumentsObjects); - } - } - - @Override - public Object isDefined(VirtualFrame frame) { - final RubyContext context = getContext(); - - try { - final RubyBasicObject self = context.getCoreLibrary().box(frame.getArguments(RubyArguments.class).getSelf()); - final RubyBasicObject receiverRubyObject = context.getCoreLibrary().box(self); - - final RubyMethod method = receiverRubyObject.getRubyClass().getSuperclass().lookupMethod(name); - - if (method == null || method.isUndefined() || !method.isVisibleTo(self)) { - return NilPlaceholder.INSTANCE; - } else { - return context.makeString("super"); - } - } catch (Exception e) { - return NilPlaceholder.INSTANCE; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlineHeuristic.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlineHeuristic.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -import com.oracle.truffle.ruby.nodes.*; - -public class InlineHeuristic { - - public static boolean shouldInline(InlinableMethodImplementation method) { - if (method.alwaysInline()) { - return true; - } - - return false; - } - - public static boolean shouldInlineYield(@SuppressWarnings("unused") InlinableMethodImplementation method) { - return true; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedBoxedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedBoxedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -import java.util.*; - -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.*; -import com.oracle.truffle.ruby.runtime.lookup.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * A node in the dispatch chain that comes after the boxing point and caches a method on a full - * boxed {@link RubyBasicObject}, matching it by looking at the lookup node and assuming it has not - * been modified. - */ -public class InlinedBoxedDispatchNode extends BoxedDispatchNode { - - private final LookupNode expectedLookupNode; - private final Assumption unmodifiedAssumption; - - private final InlinableMethodImplementation method; - private final RubyRootNode rootNode; - - @Child protected BoxedDispatchNode next; - - public InlinedBoxedDispatchNode(RubyContext context, SourceSection sourceSection, LookupNode expectedLookupNode, InlinableMethodImplementation method, BoxedDispatchNode next) { - super(context, sourceSection); - - assert expectedLookupNode != null; - assert method != null; - - this.expectedLookupNode = expectedLookupNode; - unmodifiedAssumption = expectedLookupNode.getUnmodifiedAssumption(); - this.method = method; - this.rootNode = method.getCloneOfPristineRootNode(); - this.next = adoptChild(next); - } - - @Override - public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - // Check the lookup node is what we expect - - if (receiverObject.getLookupNode() != expectedLookupNode) { - return next.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - - // Check the class has not been modified - - try { - unmodifiedAssumption.check(); - } catch (InvalidAssumptionException e) { - return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects); - } - - // Call the method - - Object[] modifiedArgumentsObjects; - - CompilerAsserts.compilationConstant(method.getShouldAppendCallNode()); - - if (method.getShouldAppendCallNode()) { - modifiedArgumentsObjects = Arrays.copyOf(argumentsObjects, argumentsObjects.length + 1); - modifiedArgumentsObjects[modifiedArgumentsObjects.length - 1] = this; - } else { - modifiedArgumentsObjects = argumentsObjects; - } - - final RubyArguments arguments = new RubyArguments(method.getDeclarationFrame(), receiverObject, blockObject, modifiedArgumentsObjects); - final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, method.getFrameDescriptor()); - return rootNode.execute(inlinedFrame); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedUnboxedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedUnboxedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -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 class InlinedUnboxedDispatchNode extends UnboxedDispatchNode { - - private final Class expectedClass; - private final Assumption unmodifiedAssumption; - - private final InlinableMethodImplementation method; - private final RubyRootNode rootNode; - - @Child protected UnboxedDispatchNode next; - - public InlinedUnboxedDispatchNode(RubyContext context, SourceSection sourceSection, Class expectedClass, Assumption unmodifiedAssumption, InlinableMethodImplementation method, - UnboxedDispatchNode next) { - super(context, sourceSection); - - assert expectedClass != null; - assert method != null; - - this.expectedClass = expectedClass; - this.unmodifiedAssumption = unmodifiedAssumption; - this.method = method; - this.rootNode = method.getCloneOfPristineRootNode(); - this.next = adoptChild(next); - } - - @Override - public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - // Check the class is what we expect - - if (receiverObject.getClass() != expectedClass) { - return next.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - - // Check the class has not been modified - - try { - unmodifiedAssumption.check(); - } catch (InvalidAssumptionException e) { - return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects); - } - - // Call the method - - final RubyArguments arguments = new RubyArguments(method.getDeclarationFrame(), receiverObject, blockObject, argumentsObjects); - final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, method.getFrameDescriptor()); - return rootNode.execute(inlinedFrame); - } - - @Override - public void setNext(UnboxedDispatchNode next) { - this.next = adoptChild(next); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/ProcOrNullNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/ProcOrNullNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.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.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Wraps some node that will produce either a {@link RubyProc} or a {@link NilPlaceholder} and - * returns {@code null} in case of the latter. Used in parts of the dispatch chain. - */ -@NodeInfo(shortName = "proc-or-null") -@NodeChild(value = "child", type = RubyNode.class) -public abstract class ProcOrNullNode extends RubyNode { - - public ProcOrNullNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ProcOrNullNode(ProcOrNullNode prev) { - super(prev); - } - - @Specialization - public Object doNil(@SuppressWarnings("unused") NilPlaceholder nil) { - return null; - } - - @Specialization - public Object doProc(RubyProc proc) { - return proc; - } - - @Override - public RubyProc executeRubyProc(VirtualFrame frame) { - final Object proc = execute(frame); - - // The standard asRubyProc test doesn't allow for null - assert proc == null || RubyTypesGen.RUBYTYPES.isRubyProc(proc); - - return (RubyProc) proc; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UnboxedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UnboxedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * A node in the dispatch chain that expects the receiver to be a simple Java object such as a boxed - * primitive, rather than a full {@link RubyBasicObject}. This allows calls to be made with a - * receiver such as {@link Integer} without having to turn it into a {@link RubyFixnum}. Followed at - * some point by an {@link UninitializedBoxingDispatchNode} or {@link BoxingDispatchNode} before we - * try to dispatch on a Ruby BasicObject or the {@link UninitializedDispatchNode}. - */ -public abstract class UnboxedDispatchNode extends DispatchNode { - - public UnboxedDispatchNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public abstract Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects); - - public void setNext(@SuppressWarnings("unused") UnboxedDispatchNode next) { - throw new UnsupportedOperationException(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedBoxingDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedBoxingDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * A node in the dispatch chain that transfers to interpreter and then boxes the receiver. - */ -public class UninitializedBoxingDispatchNode extends UnboxedDispatchNode { - - @Child protected BoxedDispatchNode next; - - public UninitializedBoxingDispatchNode(RubyContext context, SourceSection sourceSection, BoxedDispatchNode next) { - super(context, sourceSection); - - this.next = adoptChild(next); - } - - @Override - public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - CompilerDirectives.transferToInterpreter(); - - /* - * If the next dispatch node is something other than the uninitialized dispatch node then we - * need to replace this node because it's now on the fast path. If the receiver was already - * boxed. - * - * Note that with this scheme it will take a couple of calls for the chain to become fully - * specialized. - */ - - if (next instanceof UninitializedDispatchNode) { - this.replace(new BoxingDispatchNode(getContext(), getSourceSection(), next)); - } - - return next.dispatch(frame, getContext().getCoreLibrary().box(receiverObject), blockObject, argumentsObjects); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2013 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.call; - -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.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * The uninitialized dispatch node. Only reached when the method is not expected by any node in the - * dispatch chain, and only creates new nodes or modifies the existing chain. - */ -public class UninitializedDispatchNode extends BoxedDispatchNode { - - /* - * Node at depth 5 is 4 actual dispatches, the boxing dispatch and the final uninitalized - * dispatch. - */ - - private static final int MAX_DEPTH = 5; - - private final String name; - - public UninitializedDispatchNode(RubyContext context, SourceSection sourceSection, String name) { - super(context, sourceSection); - - assert name != null; - - this.name = name; - } - - @Override - public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) { - CompilerDirectives.transferToInterpreter(); - - final RubyContext context = getContext(); - - final RubyMethod method = lookup(frame, receiverObject, name); - - final int depth = getDepth(); - - final DispatchHeadNode dispatchHead = (DispatchHeadNode) NodeUtil.getNthParent(this, depth); - - if (depth == MAX_DEPTH) { - /* - * Replace the chain with DispatchHeadNode -> ExpectBoxedDispatchNode -> - * GeneralDispatchNode. - */ - - context.implementationMessage("resorting to a general call node at %s", getSourceSection()); - NodeUtil.printTree(System.err, dispatchHead); - - final GeneralBoxedDispatchNode newGeneralDispatch = new GeneralBoxedDispatchNode(getContext(), getSourceSection(), name); - final BoxingDispatchNode newBoxing = new BoxingDispatchNode(getContext(), getSourceSection(), newGeneralDispatch); - - dispatchHead.getDispatch().replace(newBoxing); - return newBoxing.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } else if (receiverObject instanceof Unboxable) { - /* - * Unboxed dispatch nodes are prepended to the chain of dispatch nodes, so they're - * before the point where receivers will definitely be boxed. - */ - - final Object receiverUnboxed = ((Unboxable) receiverObject).unbox(); - - final UnboxedDispatchNode firstDispatch = dispatchHead.getDispatch(); - - if (receiverObject instanceof RubyTrueClass || receiverObject instanceof RubyFalseClass) { - final Assumption falseUnmodifiedAssumption = context.getCoreLibrary().getFalseClass().getUnmodifiedAssumption(); - final RubyMethod falseMethod = lookup(frame, context.getCoreLibrary().box(false), name); - final Assumption trueUnmodifiedAssumption = context.getCoreLibrary().getTrueClass().getUnmodifiedAssumption(); - final RubyMethod trueMethod = lookup(frame, context.getCoreLibrary().box(true), name); - - final BooleanDispatchNode newDispatch = new BooleanDispatchNode(getContext(), getSourceSection(), falseUnmodifiedAssumption, falseMethod, trueUnmodifiedAssumption, trueMethod, null); - firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain"); - newDispatch.setNext(firstDispatch); - return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects); - } else { - UnboxedDispatchNode newDispatch; - - if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) { - newDispatch = new InlinedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(), - (InlinableMethodImplementation) method.getImplementation(), null); - } else { - newDispatch = new CachedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(), method, null); - } - - firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain"); - newDispatch.setNext(firstDispatch); - - return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects); - } - } else { - /* - * Boxed dispatch nodes are appended to the chain of dispatch nodes, so they're after - * the point where receivers are guaranteed to be boxed. - */ - - final UninitializedDispatchNode newUninitializedDispatch = new UninitializedDispatchNode(getContext(), getSourceSection(), name); - - BoxedDispatchNode newDispatch; - - if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) { - newDispatch = new InlinedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), (InlinableMethodImplementation) method.getImplementation(), - newUninitializedDispatch); - } else { - newDispatch = new CachedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), method, newUninitializedDispatch); - } - - replace(newDispatch, "appending new boxed dispatch node to chain"); - - return newDispatch.dispatch(frame, receiverObject, blockObject, argumentsObjects); - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/BooleanCastNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/BooleanCastNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2013 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.cast; - -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.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Casts a value into a boolean. Works at the language level, so doesn't call any Ruby methods to - * cast non-core or monkey-patched objects. - */ -@NodeInfo(shortName = "cast-boolean") -@NodeChild(value = "child", type = RubyNode.class) -public abstract class BooleanCastNode extends RubyNode { - - public BooleanCastNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BooleanCastNode(BooleanCastNode copy) { - super(copy.getContext(), copy.getSourceSection()); - } - - @Specialization - public boolean doBoolean(boolean value) { - return value; - } - - @Specialization - public boolean doNil(@SuppressWarnings("unused") NilPlaceholder nil) { - return false; - } - - @Generic - public boolean doGeneric(Object object) { - if (object instanceof Boolean) { - return (boolean) object; - } else if (object instanceof NilPlaceholder || object instanceof RubyNilClass) { - return false; - } else { - return true; - } - } - - @Override - public abstract boolean executeBoolean(VirtualFrame frame); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/LambdaNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/LambdaNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 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.cast; - -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.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -@NodeInfo(shortName = "lambda") -public class LambdaNode extends RubyNode { - - @Child private RubyNode definition; - - public LambdaNode(RubyContext context, SourceSection sourceSection, RubyNode definition) { - super(context, sourceSection); - this.definition = adoptChild(definition); - } - - @Override - public Object execute(VirtualFrame frame) { - return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA, frame.getArguments(RubyArguments.class).getSelf(), null, (RubyMethod) definition.execute(frame)); - } - - @Override - public void executeVoid(VirtualFrame frame) { - definition.executeVoid(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/ProcCastNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/ProcCastNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.cast; - -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.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Casts an object to a Ruby Proc object. - */ -@NodeInfo(shortName = "cast-proc") -@NodeChild("child") -public abstract class ProcCastNode extends RubyNode { - - @Child protected DispatchHeadNode toProc; - - public ProcCastNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - toProc = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_proc", false)); - } - - public ProcCastNode(ProcCastNode prev) { - super(prev); - toProc = adoptChild(prev.toProc); - } - - @Specialization - public NilPlaceholder doNil(NilPlaceholder nil) { - return nil; - } - - @Specialization - public RubyProc doRubyProc(RubyProc proc) { - return proc; - } - - @Specialization - public RubyProc doObject(VirtualFrame frame, RubyBasicObject object) { - return (RubyProc) toProc.dispatch(frame, object, null); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/SplatCastNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/SplatCastNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.cast; - -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.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -/** - * Splat as used to cast a value to an array if it isn't already, as in {@code *value}. - */ -@NodeInfo(shortName = "cast-splat") -@NodeChild("child") -public abstract class SplatCastNode extends RubyNode { - - public SplatCastNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SplatCastNode(SplatCastNode prev) { - super(prev); - } - - protected abstract RubyNode getChild(); - - @Specialization - public RubyArray doArray(RubyArray array) { - return array; - } - - @Specialization - public RubyArray doObject(Object object) { - if (object instanceof RubyArray) { - return (RubyArray) object; - } else { - return RubyArray.specializedFromObject(getContext().getCoreLibrary().getArrayClass(), object); - } - } - - @Override - public void executeVoid(VirtualFrame frame) { - getChild().executeVoid(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToRegexpNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToRegexpNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.cast; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -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.*; - -/** - * Creates a regex from a string. - */ -@NodeInfo(shortName = "cast-string-to-regexp") -@NodeChild("string") -public abstract class StringToRegexpNode extends RubyNode { - - public StringToRegexpNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public StringToRegexpNode(StringToRegexpNode prev) { - super(prev); - } - - @Specialization - public RubyRegexp doString(RubyString string) { - return new RubyRegexp(getContext().getCoreLibrary().getRegexpClass(), string.toString()); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToSymbolNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToSymbolNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.cast; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -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.*; - -/** - * Creates a symbol from a string. - */ -@NodeInfo(shortName = "cast-string-to-symbol") -@NodeChild("string") -public abstract class StringToSymbolNode extends RubyNode { - - public StringToSymbolNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public StringToSymbolNode(StringToSymbolNode prev) { - super(prev); - } - - @Specialization - public RubySymbol doString(RubyString string) { - return new RubySymbol(getContext().getCoreLibrary().getSymbolClass(), string.toString()); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/CachedReadConstantNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/CachedReadConstantNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2013 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.constants; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents a constant read from some object and cached, with the assumption that the object it - * was read from is unmodified. If that assumption does not hold the read is uninitialized. If the - * class of the receiver changes we also uninitialize. - */ -@NodeInfo(shortName = "cached-read-constant") -public class CachedReadConstantNode extends ReadConstantNode { - - private final RubyClass expectedClass; - private final Assumption unmodifiedAssumption; - - private final Object value; - - private final boolean hasBoolean; - private final boolean booleanValue; - - private final boolean hasInt; - private final int intValue; - - private final boolean hasDouble; - private final double doubleValue; - - private final BranchProfile boxBranchProfile = new BranchProfile(); - - public CachedReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyClass expectedClass, Object value) { - super(context, sourceSection, name, receiver); - - this.expectedClass = expectedClass; - unmodifiedAssumption = expectedClass.getUnmodifiedAssumption(); - - this.value = value; - - /* - * We could do this lazily as needed, but I'm sure the compiler will appreciate the fact - * that these fields are all final. - */ - - if (value instanceof Boolean) { - hasBoolean = true; - booleanValue = (boolean) value; - - hasInt = false; - intValue = -1; - - hasDouble = false; - doubleValue = -1; - } else if (value instanceof Integer) { - hasBoolean = false; - booleanValue = false; - - hasInt = true; - intValue = (int) value; - - hasDouble = true; - doubleValue = (int) value; - } else if (value instanceof Double) { - hasBoolean = false; - booleanValue = false; - - hasInt = false; - intValue = -1; - - hasDouble = true; - doubleValue = (double) value; - } else { - hasBoolean = false; - booleanValue = false; - - hasInt = false; - intValue = -1; - - hasDouble = false; - doubleValue = -1; - } - } - - @Override - public Object execute(VirtualFrame frame) { - try { - guard(frame); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - - return value; - } - - @Override - public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { - guard(frame); - - if (hasBoolean) { - return booleanValue; - } else { - throw new UnexpectedResultException(value); - } - } - - @Override - public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException { - guard(frame); - - if (hasInt) { - return intValue; - } else { - throw new UnexpectedResultException(value); - } - } - - @Override - public double executeFloat(VirtualFrame frame) throws UnexpectedResultException { - guard(frame); - - if (hasDouble) { - return doubleValue; - } else { - throw new UnexpectedResultException(value); - } - } - - @Override - public void executeVoid(VirtualFrame frame) { - } - - public void guard(VirtualFrame frame) throws UnexpectedResultException { - final RubyContext context = getContext(); - - final Object receiverObject = receiver.execute(frame); - - RubyBasicObject receiverRubyObject; - - // TODO(CS): put the boxing into a separate node that can specialize for each type it sees - - if (receiverObject instanceof RubyBasicObject) { - receiverRubyObject = (RubyBasicObject) receiverObject; - } else { - boxBranchProfile.enter(); - receiverRubyObject = context.getCoreLibrary().box(receiverObject); - } - - if (receiverRubyObject.getRubyClass() != expectedClass) { - CompilerDirectives.transferToInterpreter(); - throw new UnexpectedResultException(uninitialize(receiverRubyObject)); - } - - try { - unmodifiedAssumption.check(); - } catch (InvalidAssumptionException e) { - throw new UnexpectedResultException(uninitialize(receiverRubyObject)); - } - } - - private Object uninitialize(RubyBasicObject receiverObject) { - return replace(new UninitializedReadConstantNode(getContext(), getSourceSection(), name, receiver)).execute(receiverObject); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/ReadConstantNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/ReadConstantNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013 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.constants; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -public abstract class ReadConstantNode extends RubyNode { - - protected final String name; - @Child protected RubyNode receiver; - - public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) { - super(context, sourceSection); - this.name = name; - this.receiver = adoptChild(receiver); - } - - @Override - public Object isDefined(VirtualFrame frame) { - final RubyContext context = getContext(); - - if (name.equals("Encoding")) { - /* - * Work-around so I don't have to load the iconv library - runners/formatters/junit.rb. - */ - return context.makeString("constant"); - } - - Object value; - - try { - value = context.getCoreLibrary().box(receiver.execute(frame)).getLookupNode().lookupConstant(name); - } catch (RaiseException e) { - /* - * If we are looking up a constant in a constant that is itself undefined, we return Nil - * rather than raising the error. Eg.. defined?(Defined::Undefined1::Undefined2) - */ - - if (e.getRubyException().getRubyClass() == context.getCoreLibrary().getNameErrorClass()) { - return NilPlaceholder.INSTANCE; - } - - throw e; - } - - if (value == null) { - return NilPlaceholder.INSTANCE; - } else { - return context.makeString("constant"); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/UninitializedReadConstantNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/UninitializedReadConstantNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2013 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.constants; - -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.control.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents an uninitialized constant read from some object. After the first read it will be - * specialized to some other node. This is the starting point for all constant reads. - */ -@NodeInfo(shortName = "uninitialized-read-constant") -public class UninitializedReadConstantNode extends ReadConstantNode { - - public UninitializedReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) { - super(context, sourceSection, name, receiver); - } - - /** - * This execute method allows us to pass in the already executed receiver object, so that during - * uninitialization it is not executed once by the specialized node and again by this node. - */ - public Object execute(RubyBasicObject receiverObject) { - CompilerAsserts.neverPartOfCompilation(); - - final RubyContext context = receiverObject.getRubyClass().getContext(); - - Object value; - - value = receiverObject.getLookupNode().lookupConstant(name); - - if (value == null && receiverObject instanceof RubyModule) { - /* - * FIXME(CS): I'm obviously doing something wrong with constant lookup in nested modules - * here, but explicitly looking in the Module itself, not its lookup node, seems to fix - * it for now. - */ - - value = ((RubyModule) receiverObject).lookupConstant(name); - } - - if (value == null) { - throw new RaiseException(context.getCoreLibrary().nameErrorUninitializedConstant(name)); - } - - replace(new CachedReadConstantNode(context, getSourceSection(), name, receiver, receiverObject.getRubyClass(), value)); - - assert RubyContext.shouldObjectBeVisible(value); - - return value; - } - - @Override - public Object execute(VirtualFrame frame) { - CompilerDirectives.transferToInterpreter(); - - final RubyContext context = getContext(); - - final Object receiverObject = receiver.execute(frame); - final RubyBasicObject receiverRubyObject = context.getCoreLibrary().box(receiverObject); - - return execute(receiverRubyObject); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/WriteConstantNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/WriteConstantNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 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.constants; - -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.*; - -/** - * Represents writing a constant into some module. - */ -@NodeInfo(shortName = "write-constant") -public class WriteConstantNode extends RubyNode { - - private final String name; - @Child protected RubyNode module; - @Child protected RubyNode rhs; - - public WriteConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode module, RubyNode rhs) { - super(context, sourceSection); - this.name = name; - this.module = adoptChild(module); - this.rhs = adoptChild(rhs); - } - - @Override - public Object execute(VirtualFrame frame) { - // TODO(cs): can module ever not evaluate to a RubyModule? - - final RubyModule moduleObject = (RubyModule) module.execute(frame); - - final Object rhsValue = rhs.execute(frame); - - assert rhsValue != null; - assert !(rhsValue instanceof String); - - moduleObject.setModuleConstant(name, rhsValue); - - return rhsValue; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/AndNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/AndNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -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.*; - -/** - * Represents a Ruby {@code and} or {@code &&} expression. - */ -@NodeInfo(shortName = "and") -@NodeChildren({@NodeChild("left"), @NodeChild("right")}) -public abstract class AndNode extends RubyNode { - - public AndNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AndNode(AndNode copy) { - super(copy.getContext(), copy.getSourceSection()); - } - - @ShortCircuit("right") - public boolean needsRightNode(Object a) { - return GeneralConversions.toBoolean(a); - } - - @ShortCircuit("right") - public boolean needsRightNode(boolean a) { - return a; - } - - @Specialization - public boolean doBoolean(boolean a, boolean hasB, boolean b) { - return hasB ? b : a; - } - - @Specialization - public Object doObject(boolean a, boolean hasB, Object b) { - return hasB ? b : a; - } - - @Generic - public Object doGeneric(Object a, boolean hasB, Object b) { - return hasB ? b : a; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.nodes.literal.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -@NodeInfo(shortName = "break") -public class BreakNode extends RubyNode { - - @Child private RubyNode child; - - public BreakNode(RubyContext context, SourceSection sourceSection, RubyNode child) { - super(context, sourceSection); - this.child = adoptChild(child); - } - - @Override - public Object execute(VirtualFrame frame) { - if (child instanceof NilNode) { - throw BreakException.NIL; - } else { - throw new BreakException(child.execute(frame)); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ElidableResultNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ElidableResultNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.*; - -/** - * This node has a pair of children - one required and one elidable result. The required node is - * always executed, but its result is discarded. Therefore it should perform some useful side - * effects. The elidable node is executed, and its result value returned, if an execute method with - * a non-void type is used. It is not executed at all if a void typed execute method is used. - * Therefore it should not perform any observable side effects. - */ -@NodeInfo(shortName = "elidable-result") -public class ElidableResultNode extends RubyNode { - - @Child protected RubyNode required; - @Child protected RubyNode elidableResult; - - public ElidableResultNode(RubyContext context, SourceSection sourceSection, RubyNode required, RubyNode elidableResult) { - super(context, sourceSection); - this.required = adoptChild(required); - this.elidableResult = adoptChild(elidableResult); - } - - @Override - public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException { - required.executeVoid(frame); - return elidableResult.executeFixnum(frame); - } - - @Override - public double executeFloat(VirtualFrame frame) throws UnexpectedResultException { - required.executeVoid(frame); - return elidableResult.executeFloat(frame); - } - - @Override - public Object execute(VirtualFrame frame) { - required.executeVoid(frame); - return elidableResult.execute(frame); - } - - @Override - public void executeVoid(VirtualFrame frame) { - required.execute(frame); - } - - @Override - public Object isDefined(VirtualFrame frame) { - return elidableResult.isDefined(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/EnsureNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/EnsureNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.*; - -/** - * Represents an ensure clause in exception handling. Represented separately to the try part. - */ -@NodeInfo(shortName = "ensure") -public class EnsureNode extends RubyNode { - - @Child protected RubyNode tryPart; - @Child protected RubyNode ensurePart; - - public EnsureNode(RubyContext context, SourceSection sourceSection, RubyNode tryPart, RubyNode ensurePart) { - super(context, sourceSection); - this.tryPart = adoptChild(tryPart); - this.ensurePart = adoptChild(ensurePart); - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return tryPart.execute(frame); - } finally { - ensurePart.executeVoid(frame); - } - } - - @Override - public void executeVoid(VirtualFrame frame) { - try { - tryPart.executeVoid(frame); - } finally { - ensurePart.executeVoid(frame); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/FlipFlopNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/FlipFlopNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.nodes.cast.*; -import com.oracle.truffle.ruby.nodes.methods.locals.*; -import com.oracle.truffle.ruby.runtime.*; - -@NodeInfo(shortName = "flip-flop") -public class FlipFlopNode extends RubyNode { - - @Child protected BooleanCastNode begin; - @Child protected BooleanCastNode end; - @Child protected FlipFlopStateNode stateNode; - - private final boolean exclusive; - - public FlipFlopNode(RubyContext context, SourceSection sourceSection, BooleanCastNode begin, BooleanCastNode end, FlipFlopStateNode stateNode, boolean exclusive) { - super(context, sourceSection); - this.begin = adoptChild(begin); - this.end = adoptChild(end); - this.stateNode = adoptChild(stateNode); - this.exclusive = exclusive; - } - - @Override - public boolean executeBoolean(VirtualFrame frame) { - if (exclusive) { - if (stateNode.getState(frame)) { - if (end.executeBoolean(frame)) { - stateNode.setState(frame, false); - } - - return true; - } else { - final boolean newState = begin.executeBoolean(frame); - stateNode.setState(frame, newState); - return newState; - } - } else { - if (stateNode.getState(frame)) { - if (end.executeBoolean(frame)) { - stateNode.setState(frame, false); - } - - return true; - } else { - if (begin.executeBoolean(frame)) { - stateNode.setState(frame, !end.executeBoolean(frame)); - return true; - } - - return false; - } - } - } - - @Override - public Object execute(VirtualFrame frame) { - return executeBoolean(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/IfNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/IfNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.cast.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Represents a Ruby {@code if} expression. Note that in this representation we always have an - * {@code else} part. - */ -@NodeInfo(shortName = "if") -public class IfNode extends RubyNode { - - @Child protected BooleanCastNode condition; - @Child protected RubyNode thenBody; - @Child protected RubyNode elseBody; - - private final BranchProfile thenProfile = new BranchProfile(); - private final BranchProfile elseProfile = new BranchProfile(); - - public IfNode(RubyContext context, SourceSection sourceSection, BooleanCastNode condition, RubyNode thenBody, RubyNode elseBody) { - super(context, sourceSection); - this.condition = adoptChild(condition); - this.thenBody = adoptChild(thenBody); - this.elseBody = adoptChild(elseBody); - } - - @Override - public Object execute(VirtualFrame frame) { - if (condition.executeBoolean(frame)) { - thenProfile.enter(); - return thenBody.execute(frame); - } else { - elseProfile.enter(); - return elseBody.execute(frame); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.nodes.literal.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -@NodeInfo(shortName = "next") -public class NextNode extends RubyNode { - - @Child private RubyNode child; - - public NextNode(RubyContext context, SourceSection sourceSection, RubyNode child) { - super(context, sourceSection); - - this.child = adoptChild(child); - } - - @Override - public Object execute(VirtualFrame frame) { - if (child instanceof NilNode) { - throw NextException.NIL; - } else { - throw new NextException(child.execute(frame)); - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NotNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NotNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.nodes.cast.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Represents a Ruby {@code not} or {@code !} expression. - */ -@NodeInfo(shortName = "not") -public class NotNode extends RubyNode { - - @Child protected BooleanCastNode child; - - public NotNode(RubyContext context, SourceSection sourceSection, BooleanCastNode child) { - super(context, sourceSection); - this.child = adoptChild(child); - } - - @Override - public boolean executeBoolean(VirtualFrame frame) { - return !child.executeBoolean(frame); - } - - @Override - public Object execute(VirtualFrame frame) { - return executeBoolean(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/OrNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/OrNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -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.*; - -/** - * Represents a Ruby {@code or} or {@code ||} expression. - */ -@NodeInfo(shortName = "or") -@NodeChildren({@NodeChild("left"), @NodeChild("right")}) -public abstract class OrNode extends RubyNode { - - public OrNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public OrNode(OrNode copy) { - super(copy.getContext(), copy.getSourceSection()); - } - - @ShortCircuit("right") - public boolean needsRightNode(Object a) { - return !GeneralConversions.toBoolean(a); - } - - @ShortCircuit("right") - public boolean needsRightNode(boolean a) { - return !a; - } - - @Specialization - public Object doBoolean(boolean a, boolean hasB, Object b) { - return hasB ? b : a; - } - - @Generic - public Object doGeneric(Object a, boolean hasB, Object b) { - return hasB ? b : a; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RedoNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RedoNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.control.*; - -@NodeInfo(shortName = "redo") -public class RedoNode extends RubyNode { - - public RedoNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public Object execute(VirtualFrame frame) { - throw new RedoException(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueAnyNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueAnyNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.objects.*; - -/** - * Rescues any exception. - */ -@NodeInfo(shortName = "rescue-any") -public class RescueAnyNode extends RescueNode { - - public RescueAnyNode(RubyContext context, SourceSection sourceSection, RubyNode body) { - super(context, sourceSection, body); - } - - @Override - public boolean canHandle(VirtualFrame frame, RubyBasicObject exception) { - return true; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueClassesNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueClassesNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Rescues any of a set of classes. - */ -@NodeInfo(shortName = "rescue-classes") -public class RescueClassesNode extends RescueNode { - - @Children final RubyNode[] handlingClassNodes; - - public RescueClassesNode(RubyContext context, SourceSection sourceSection, RubyNode[] handlingClassNodes, RubyNode body) { - super(context, sourceSection, body); - this.handlingClassNodes = adoptChildren(handlingClassNodes); - } - - @ExplodeLoop - @Override - public boolean canHandle(VirtualFrame frame, RubyBasicObject exception) { - final RubyClass exceptionRubyClass = exception.getRubyClass(); - - for (RubyNode handlingClassNode : handlingClassNodes) { - // TODO(CS): what if we don't get a class? - - final RubyClass handlingClass = (RubyClass) handlingClassNode.execute(frame); - - if (exceptionRubyClass.assignableTo(handlingClass)) { - return true; - } - } - - return false; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Base node for all nodes which may be able to rescue an exception. They have a test method - * {@link #canHandle} and a body to execute if that test passes. - */ -public abstract class RescueNode extends RubyNode { - - @Child protected RubyNode body; - - public RescueNode(RubyContext context, SourceSection sourceSection, RubyNode body) { - super(context, sourceSection); - this.body = adoptChild(body); - } - - public abstract boolean canHandle(VirtualFrame frame, RubyBasicObject exception); - - @Override - public Object execute(VirtualFrame frame) { - return body.execute(frame); - } - - @Override - public void executeVoid(VirtualFrame frame) { - body.executeVoid(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueSplatNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueSplatNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Rescue any of several classes, that we get from an expression that evaluates to an array of - * classes. - * - */ -@NodeInfo(shortName = "rescue-splat") -public class RescueSplatNode extends RescueNode { - - @Child RubyNode handlingClassesArray; - - public RescueSplatNode(RubyContext context, SourceSection sourceSection, RubyNode handlingClassesArray, RubyNode body) { - super(context, sourceSection, body); - this.handlingClassesArray = adoptChild(handlingClassesArray); - } - - @ExplodeLoop - @Override - public boolean canHandle(VirtualFrame frame, RubyBasicObject exception) { - final RubyArray handlingClasses = (RubyArray) handlingClassesArray.execute(frame); - - final RubyClass exceptionRubyClass = exception.getRubyClass(); - - for (Object handlingClass : handlingClasses.asList()) { - if (exceptionRubyClass.assignableTo((RubyClass) handlingClass)) { - return true; - } - } - - return false; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RetryNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RetryNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.control.*; - -@NodeInfo(shortName = "retry") -public class RetryNode extends RubyNode { - - public RetryNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public Object execute(VirtualFrame frame) { - throw new RetryException(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ReturnNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ReturnNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.control.*; - -/** - * Represents an explicit return. The return ID indicates where we should be returning to - this can - * be non-trivial if you have blocks. - */ -@NodeInfo(shortName = "return") -public class ReturnNode extends RubyNode { - - private final long returnID; - @Child protected RubyNode value; - - public ReturnNode(RubyContext context, SourceSection sourceSection, long returnID, RubyNode value) { - super(context, sourceSection); - this.returnID = returnID; - this.value = adoptChild(value); - } - - @Override - public Object execute(VirtualFrame frame) { - throw new ReturnException(returnID, value.execute(frame)); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/SequenceNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/SequenceNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -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.*; - -/** - * A sequence of statements to be executed in serial. - */ -@NodeInfo(shortName = "sequence") -public final class SequenceNode extends RubyNode { - - @Children protected final RubyNode[] body; - - public SequenceNode(RubyContext context, SourceSection sourceSection, RubyNode... body) { - super(context, sourceSection); - this.body = adoptChildren(body); - } - - @ExplodeLoop - @Override - public Object execute(VirtualFrame frame) { - for (int n = 0; n < body.length - 1; n++) { - body[n].executeVoid(frame); - } - - return body[body.length - 1].execute(frame); - } - - @ExplodeLoop - @Override - public void executeVoid(VirtualFrame frame) { - for (int n = 0; n < body.length; n++) { - body[n].executeVoid(frame); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/TryNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/TryNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents a block of code run with exception handlers. There's no {@code try} keyword in Ruby - - * it's implicit - but it's similar to a try statement in any other language. - */ -@NodeInfo(shortName = "try") -public class TryNode extends RubyNode { - - @Child protected RubyNode tryPart; - @Children final RescueNode[] rescueParts; - @Child protected RubyNode elsePart; - - private final BranchProfile controlFlowProfile = new BranchProfile(); - - public TryNode(RubyContext context, SourceSection sourceSection, RubyNode tryPart, RescueNode[] rescueParts, RubyNode elsePart) { - super(context, sourceSection); - this.tryPart = adoptChild(tryPart); - this.rescueParts = adoptChildren(rescueParts); - this.elsePart = adoptChild(elsePart); - } - - @Override - public Object execute(VirtualFrame frame) { - while (true) { - try { - final Object result = tryPart.execute(frame); - elsePart.executeVoid(frame); - return result; - } catch (ControlFlowException exception) { - controlFlowProfile.enter(); - - throw exception; - } catch (RuntimeException exception) { - CompilerDirectives.transferToInterpreter(); - - try { - return handleException(frame, exception); - } catch (RetryException e) { - continue; - } - } - } - } - - private Object handleException(VirtualFrame frame, RuntimeException exception) { - CompilerAsserts.neverPartOfCompilation(); - - final RubyContext context = getContext(); - - final RubyBasicObject rubyException = ExceptionTranslator.translateException(context, exception); - - context.getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", rubyException); - - for (RescueNode rescue : rescueParts) { - if (rescue.canHandle(frame, rubyException)) { - return rescue.execute(frame); - } - } - - throw exception; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/WhileNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/WhileNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.cast.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -/** - * Represents a Ruby {@code while} statement. - */ -@NodeInfo(shortName = "while") -public class WhileNode extends RubyNode { - - @Child protected BooleanCastNode condition; - @Child protected RubyNode body; - - private final BranchProfile breakProfile = new BranchProfile(); - private final BranchProfile nextProfile = new BranchProfile(); - private final BranchProfile redoProfile = new BranchProfile(); - - public WhileNode(RubyContext context, SourceSection sourceSection, BooleanCastNode condition, RubyNode body) { - super(context, sourceSection); - this.condition = adoptChild(condition); - this.body = adoptChild(body); - } - - @Override - public Object execute(VirtualFrame frame) { - outer: while (condition.executeBoolean(frame)) { - while (true) { - try { - body.execute(frame); - continue outer; - } catch (BreakException e) { - breakProfile.enter(); - return e.getResult(); - } catch (NextException e) { - nextProfile.enter(); - continue outer; - } catch (RedoException e) { - redoProfile.enter(); - } - } - } - - return NilPlaceholder.INSTANCE; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayConcatNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayConcatNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -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.array.*; - -/** - * Concatenate arrays. - */ -@NodeInfo(shortName = "array-concat") -public final class ArrayConcatNode extends RubyNode { - - @Children protected final RubyNode[] children; - - public ArrayConcatNode(RubyContext context, SourceSection sourceSection, RubyNode[] children) { - super(context, sourceSection); - assert children.length > 1; - this.children = adoptChildren(children); - } - - @ExplodeLoop - @Override - public Object execute(VirtualFrame frame) { - final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass()); - - for (int n = 0; n < children.length; n++) { - final Object childObject = children[n].execute(frame); - - if (childObject instanceof RubyArray) { - // setRangeArray has special cases for setting a zero-length range at the end - final int end = array.size(); - array.setRangeArrayExclusive(end, end, (RubyArray) childObject); - } else { - array.push(childObject); - } - } - - return array; - } - - @ExplodeLoop - @Override - public void executeVoid(VirtualFrame frame) { - for (int n = 0; n < children.length; n++) { - children[n].executeVoid(frame); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayCoreMethodNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayCoreMethodNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -public abstract class ArrayCoreMethodNode extends CoreMethodNode { - - public ArrayCoreMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ArrayCoreMethodNode(ArrayCoreMethodNode prev) { - super(prev); - } - - protected boolean isEmptyStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof EmptyArrayStore; - } - - protected boolean isFixnumStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof FixnumArrayStore; - } - - protected boolean isFixnumImmutablePairStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof FixnumImmutablePairArrayStore; - } - - protected boolean isObjectStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof ObjectArrayStore; - } - - protected boolean isObjectImmutablePairStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof ObjectImmutablePairArrayStore; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayIndexNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayIndexNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -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.array.*; - -/** - * Index an array, without using any method lookup. This isn't a call - it's an operation on a core - * class. - */ -@NodeInfo(shortName = "array-index") -@NodeChildren({@NodeChild(value = "array", type = RubyNode.class)}) -public abstract class ArrayIndexNode extends RubyNode { - - final int index; - - public ArrayIndexNode(RubyContext context, SourceSection sourceSection, int index) { - super(context, sourceSection); - this.index = index; - } - - public ArrayIndexNode(ArrayIndexNode prev) { - super(prev); - index = prev.index; - } - - @Specialization(guards = "isEmptyStore", order = 1) - public NilPlaceholder indexEmpty(@SuppressWarnings("unused") RubyArray array) { - return NilPlaceholder.INSTANCE; - } - - @Specialization(guards = "isFixnumStore", rewriteOn = UnexpectedResultException.class, order = 2) - public int indexFixnum(RubyArray array) throws UnexpectedResultException { - final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore(); - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - @Specialization(guards = "isFixnumStore", order = 3) - public Object indexMaybeFixnum(RubyArray array) { - final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore(); - - try { - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - @Specialization(guards = "isFixnumImmutablePairStore", rewriteOn = UnexpectedResultException.class, order = 4) - public int indexFixnumImmutablePair(RubyArray array) throws UnexpectedResultException { - final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore(); - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - @Specialization(guards = "isFixnumImmutablePairStore", order = 5) - public Object indexMaybeFixnumImmutablePair(RubyArray array) { - final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore(); - - try { - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - @Specialization(guards = "isObjectStore", order = 6) - public Object indexObject(RubyArray array) { - final ObjectArrayStore store = (ObjectArrayStore) array.getArrayStore(); - return store.get(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - @Specialization(guards = "isObjectImmutablePairStore", order = 7) - public Object indexObjectImmutablePair(RubyArray array) { - final ObjectImmutablePairArrayStore store = (ObjectImmutablePairArrayStore) array.getArrayStore(); - return store.get(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - protected boolean isEmptyStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof EmptyArrayStore; - } - - protected boolean isFixnumStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof FixnumArrayStore; - } - - protected boolean isFixnumImmutablePairStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof FixnumImmutablePairArrayStore; - } - - protected boolean isObjectStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof ObjectArrayStore; - } - - protected boolean isObjectImmutablePairStore(RubyArray receiver) { - return receiver.getArrayStore() instanceof ObjectImmutablePairArrayStore; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1080 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; - -import com.oracle.truffle.api.CompilerDirectives.SlowPath; -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.utilities.*; -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.core.array.*; -import com.oracle.truffle.ruby.runtime.core.range.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -@CoreClass(name = "Array") -public abstract class ArrayNodes { - - @CoreMethod(names = "+", minArgs = 1, maxArgs = 1) - public abstract static class AddNode extends CoreMethodNode { - - public AddNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AddNode(AddNode prev) { - super(prev); - } - - @Specialization - public RubyArray equal(RubyArray a, RubyArray b) { - final RubyArray result = new RubyArray(getContext().getCoreLibrary().getArrayClass()); - result.setRangeArrayExclusive(0, 0, a); - result.setRangeArrayExclusive(a.size(), a.size(), b); - return result; - } - - } - - @CoreMethod(names = "-", minArgs = 1, maxArgs = 1) - public abstract static class SubNode extends CoreMethodNode { - - public SubNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SubNode(SubNode prev) { - super(prev); - } - - @Specialization - public RubyArray equal(RubyArray a, RubyArray b) { - return a.relativeComplement(b); - } - - } - - @CoreMethod(names = "*", minArgs = 1, maxArgs = 1) - public abstract static class MulNode extends CoreMethodNode { - - public MulNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MulNode(MulNode prev) { - super(prev); - } - - @Specialization - public RubyArray mul(RubyArray array, int count) { - // TODO(CS): use the same storage type - - final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass()); - - for (int n = 0; n < count; n++) { - for (int i = 0; i < array.size(); i++) { - result.push(array.get(i)); - } - } - - return result; - } - - } - - @CoreMethod(names = "==", minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(RubyArray a, RubyArray b) { - // TODO(CS) - return a.equals(b); - } - - } - - @CoreMethod(names = "[]", minArgs = 1, maxArgs = 2) - public abstract static class IndexNode extends ArrayCoreMethodNode { - - public IndexNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public IndexNode(IndexNode prev) { - super(prev); - } - - @Specialization(guards = "isEmptyStore", order = 1) - public NilPlaceholder indexEmpty(@SuppressWarnings("unused") RubyArray array, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - return NilPlaceholder.INSTANCE; - } - - @Specialization(guards = "isFixnumStore", rewriteOn = UnexpectedResultException.class, order = 2) - public int indexFixnum(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) throws UnexpectedResultException { - final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore(); - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - @Specialization(guards = "isFixnumStore", order = 3) - public Object indexMaybeFixnum(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore(); - - try { - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - @Specialization(guards = "isFixnumImmutablePairStore", rewriteOn = UnexpectedResultException.class, order = 4) - public int indexFixnumImmutablePair(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) throws UnexpectedResultException { - final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore(); - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - @Specialization(guards = "isFixnumImmutablePairStore", order = 5) - public Object indexMaybeFixnumImmutablePair(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore(); - - try { - return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index)); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - @Specialization(guards = "isObjectStore", order = 6) - public Object indexObject(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - final ObjectArrayStore store = (ObjectArrayStore) array.getArrayStore(); - return store.get(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - @Specialization(guards = "isObjectImmutablePairStore", order = 7) - public Object indexObjectImmutablePair(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - final ObjectImmutablePairArrayStore store = (ObjectImmutablePairArrayStore) array.getArrayStore(); - return store.get(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - @Specialization(order = 8) - public Object indexRange(RubyArray array, int begin, int rangeLength) { - final int length = array.size(); - final int normalisedBegin = ArrayUtilities.normaliseIndex(length, begin); - return array.getRangeExclusive(normalisedBegin, normalisedBegin + rangeLength); - } - - @Specialization(order = 9) - public Object indexRange(RubyArray array, FixnumRange range, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - if (range.doesExcludeEnd()) { - return array.getRangeExclusive(range.getBegin(), range.getExclusiveEnd()); - } else { - return array.getRangeInclusive(range.getBegin(), range.getInclusiveEnd()); - } - } - - } - - @CoreMethod(names = "[]=", minArgs = 2, maxArgs = 3) - public abstract static class IndexSetNode extends ArrayCoreMethodNode { - - public IndexSetNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public IndexSetNode(IndexSetNode prev) { - super(prev); - } - - @Specialization(guards = "isEmptyStore", order = 1) - public Object indexSetEmpty(RubyArray array, int index, Object value, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - array.set(index, value); - return value; - } - - @Specialization(guards = "isFixnumStore", rewriteOn = GeneraliseArrayStoreException.class, order = 2) - public int indexSetFixnum(RubyArray array, int index, int value, @SuppressWarnings("unused") UndefinedPlaceholder unused) throws GeneraliseArrayStoreException { - final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore(); - final int normalisedIndex = ArrayUtilities.normaliseIndex(store.size(), index); - store.setFixnum(normalisedIndex, value); - return value; - } - - @Specialization(guards = "isFixnumStore", order = 3) - public int indexSetFixnumMayGeneralise(RubyArray array, int index, int value, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore(); - final int normalisedIndex = ArrayUtilities.normaliseIndex(store.size(), index); - - try { - store.setFixnum(normalisedIndex, value); - } catch (GeneraliseArrayStoreException e) { - array.set(normalisedIndex, value); - } - - return value; - } - - @Specialization(guards = "isObjectStore", order = 4) - public Object indexSetObject(RubyArray array, int index, Object value, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - final ObjectArrayStore store = (ObjectArrayStore) array.getArrayStore(); - final int normalisedIndex = ArrayUtilities.normaliseIndex(store.size(), index); - - try { - store.set(normalisedIndex, value); - } catch (GeneraliseArrayStoreException e) { - array.set(normalisedIndex, value); - } - - return value; - } - - @Specialization(order = 5) - public RubyArray indexSetRange(RubyArray array, FixnumRange range, RubyArray value, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - if (range.doesExcludeEnd()) { - array.setRangeArrayExclusive(range.getBegin(), range.getExclusiveEnd(), value); - } else { - array.setRangeArrayInclusive(range.getBegin(), range.getInclusiveEnd(), value); - } - - return value; - } - - @Specialization(order = 6) - public Object indexSetRange(RubyArray array, FixnumRange range, Object value, @SuppressWarnings("unused") UndefinedPlaceholder unused) { - if (range.doesExcludeEnd()) { - array.setRangeSingleExclusive(range.getBegin(), range.getExclusiveEnd(), value); - } else { - array.setRangeSingleInclusive(range.getBegin(), range.getInclusiveEnd(), value); - } - - return value; - } - - @Specialization(order = 7) - public RubyArray indexSetRange(RubyArray array, int begin, int rangeLength, RubyArray value) { - array.setRangeArrayExclusive(begin, begin + rangeLength, value); - return value; - } - - @Specialization(order = 8) - public Object indexSetRange(RubyArray array, int begin, int rangeLength, Object value) { - if (value instanceof UndefinedPlaceholder) { - if (array.getArrayStore() instanceof EmptyArrayStore) { - return indexSetEmpty(array, begin, rangeLength, UndefinedPlaceholder.INSTANCE); - } else if (array.getArrayStore() instanceof FixnumArrayStore) { - return indexSetFixnumMayGeneralise(array, begin, rangeLength, UndefinedPlaceholder.INSTANCE); - } else { - return indexSetObject(array, begin, rangeLength, UndefinedPlaceholder.INSTANCE); - } - } - - array.setRangeSingleExclusive(begin, begin + rangeLength, value); - return value; - } - - } - - @CoreMethod(names = "all?", needsBlock = true, maxArgs = 0) - public abstract static class AllNode extends YieldingCoreMethodNode { - - public AllNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AllNode(AllNode prev) { - super(prev); - } - - @Specialization - public boolean all(VirtualFrame frame, RubyArray array, RubyProc block) { - for (Object value : array.asList()) { - if (!yieldBoolean(frame, block, value)) { - return false; - } - } - - return true; - } - - } - - @CoreMethod(names = "any?", needsBlock = true, maxArgs = 0) - public abstract static class AnyNode extends YieldingCoreMethodNode { - - public AnyNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AnyNode(AnyNode prev) { - super(prev); - } - - @Specialization - public boolean any(VirtualFrame frame, RubyArray array, RubyProc block) { - for (Object value : array.asList()) { - if (yieldBoolean(frame, block, value)) { - return true; - } - } - - return false; - } - - } - - @CoreMethod(names = "compact", maxArgs = 0) - public abstract static class CompactNode extends ArrayCoreMethodNode { - - public CompactNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CompactNode(CompactNode prev) { - super(prev); - } - - @Specialization - public RubyArray compat(RubyArray array) { - final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass()); - - for (Object value : array.asList()) { - if (!(value instanceof NilPlaceholder || value instanceof RubyNilClass)) { - result.push(value); - } - } - - return result; - } - - } - - @CoreMethod(names = "concat", minArgs = 1, maxArgs = 1) - public abstract static class ConcatNode extends CoreMethodNode { - - public ConcatNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ConcatNode(ConcatNode prev) { - super(prev); - } - - @Specialization - public RubyArray concat(RubyArray array, RubyArray other) { - array.setRangeArrayExclusive(array.size(), array.size(), other); - return array; - } - - } - - @CoreMethod(names = "delete", minArgs = 1, maxArgs = 1) - public abstract static class DeleteNode extends CoreMethodNode { - - public DeleteNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DeleteNode(DeleteNode prev) { - super(prev); - } - - @Specialization - public Object delete(RubyArray array, Object value) { - boolean deleted = false; - int n = 0; - - while (n < array.size()) { - if (array.get(n) == value) { - array.deleteAt(n); - deleted = true; - } else { - n++; - } - } - - if (deleted) { - return value; - } else { - return NilPlaceholder.INSTANCE; - } - } - - } - - @CoreMethod(names = "delete_at", minArgs = 1, maxArgs = 1) - public abstract static class DeleteAtNode extends CoreMethodNode { - - public DeleteAtNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DeleteAtNode(DeleteAtNode prev) { - super(prev); - } - - @Specialization - public Object deleteAt(RubyArray array, int index) { - return array.deleteAt(index); - } - - } - - @CoreMethod(names = "dup", maxArgs = 0) - public abstract static class DupNode extends ArrayCoreMethodNode { - - public DupNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DupNode(DupNode prev) { - super(prev); - } - - @Specialization - public Object dup(RubyArray array) { - return array.dup(); - } - - } - - @CoreMethod(names = "each", needsBlock = true, maxArgs = 0) - public abstract static class EachNode extends YieldingCoreMethodNode { - - private final BranchProfile breakProfile = new BranchProfile(); - private final BranchProfile nextProfile = new BranchProfile(); - private final BranchProfile redoProfile = new BranchProfile(); - - public EachNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EachNode(EachNode prev) { - super(prev); - } - - @Specialization - public Object each(VirtualFrame frame, RubyArray array, RubyProc block) { - outer: for (int n = 0; n < array.size(); n++) { - while (true) { - try { - yield(frame, block, array.get(n)); - continue outer; - } catch (BreakException e) { - breakProfile.enter(); - return e.getResult(); - } catch (NextException e) { - nextProfile.enter(); - continue outer; - } catch (RedoException e) { - redoProfile.enter(); - } - } - } - - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "each_with_index", needsBlock = true, maxArgs = 0) - public abstract static class EachWithIndexNode extends YieldingCoreMethodNode { - - public EachWithIndexNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EachWithIndexNode(EachWithIndexNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder eachWithIndex(VirtualFrame frame, RubyArray array, RubyProc block) { - for (int n = 0; n < array.size(); n++) { - try { - yield(frame, block, array.get(n), n); - } catch (BreakException e) { - break; - } - } - - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "empty?", maxArgs = 0) - public abstract static class EmptyNode extends ArrayCoreMethodNode { - - public EmptyNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EmptyNode(EmptyNode prev) { - super(prev); - } - - @Specialization - public boolean isEmpty(RubyArray array) { - return array.isEmpty(); - } - - } - - @CoreMethod(names = "find", needsBlock = true, maxArgs = 0) - public abstract static class FindNode extends YieldingCoreMethodNode { - - public FindNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FindNode(FindNode prev) { - super(prev); - } - - @Specialization - public Object find(VirtualFrame frame, RubyArray array, RubyProc block) { - for (int n = 0; n < array.size(); n++) { - try { - final Object value = array.get(n); - - if (yieldBoolean(frame, block, value)) { - return value; - } - } catch (BreakException e) { - break; - } - } - - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "first", maxArgs = 0) - public abstract static class FirstNode extends ArrayCoreMethodNode { - - public FirstNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FirstNode(FirstNode prev) { - super(prev); - } - - @Specialization - public Object first(RubyArray array) { - if (array.size() == 0) { - return NilPlaceholder.INSTANCE; - } else { - return array.get(0); - } - } - - } - - @CoreMethod(names = "flatten", maxArgs = 0) - public abstract static class FlattenNode extends ArrayCoreMethodNode { - - public FlattenNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FlattenNode(FlattenNode prev) { - super(prev); - } - - @Specialization - public RubyArray flatten(RubyArray array) { - final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass()); - array.flattenTo(result); - return result; - } - - } - - @CoreMethod(names = "include?", minArgs = 1, maxArgs = 1) - public abstract static class IncludeNode extends ArrayCoreMethodNode { - - public IncludeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public IncludeNode(IncludeNode prev) { - super(prev); - } - - @Specialization - public boolean include(RubyArray array, Object value) { - return array.contains(value); - } - - } - - @CoreMethod(names = {"inject", "reduce"}, needsBlock = true, minArgs = 0, maxArgs = 1) - public abstract static class InjectNode extends YieldingCoreMethodNode { - - public InjectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InjectNode(InjectNode prev) { - super(prev); - } - - @Specialization - public Object inject(VirtualFrame frame, RubyArray array, @SuppressWarnings("unused") UndefinedPlaceholder initial, RubyProc block) { - Object accumulator = array.get(0); - - for (int n = 1; n < array.size(); n++) { - accumulator = yield(frame, block, accumulator, array.get(n)); - } - - return accumulator; - } - - @Specialization - public Object inject(VirtualFrame frame, RubyArray array, Object initial, RubyProc block) { - if (initial instanceof UndefinedPlaceholder) { - return inject(frame, array, UndefinedPlaceholder.INSTANCE, block); - } - - Object accumulator = initial; - - for (int n = 0; n < array.size(); n++) { - accumulator = yield(frame, block, accumulator, array.get(n)); - } - - return accumulator; - } - - } - - @CoreMethod(names = "insert", minArgs = 2, maxArgs = 2) - public abstract static class InsertNode extends ArrayCoreMethodNode { - - public InsertNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InsertNode(InsertNode prev) { - super(prev); - } - - @Specialization(guards = "isFixnumStore", rewriteOn = GeneraliseArrayStoreException.class) - public int insert(RubyArray array, int index, int value) throws GeneraliseArrayStoreException { - final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore(); - store.insertFixnum(ArrayUtilities.normaliseIndex(store.size(), index), value); - return value; - } - - @Specialization - public Object insert(RubyArray array, int index, Object value) { - array.insert(ArrayUtilities.normaliseIndex(array.size(), index), value); - return value; - } - - } - - @CoreMethod(names = {"inspect", "to_s"}, maxArgs = 0) - public abstract static class InspectNode extends CoreMethodNode { - - public InspectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InspectNode(InspectNode prev) { - super(prev); - } - - @Specialization - public RubyString inspect(RubyArray array) { - final RubyContext context = getContext(); - return getContext().makeString(inspect(context, array)); - } - - @SlowPath - private static String inspect(RubyContext context, RubyArray array) { - final StringBuilder builder = new StringBuilder(); - - builder.append("["); - - for (int n = 0; n < array.size(); n++) { - if (n > 0) { - builder.append(", "); - } - - // TODO(CS): slow path send - builder.append(context.getCoreLibrary().box(array.get(n)).send("inspect", null)); - } - - builder.append("]"); - - return builder.toString(); - } - - } - - @CoreMethod(names = "join", minArgs = 1, maxArgs = 1) - public abstract static class JoinNode extends ArrayCoreMethodNode { - - public JoinNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public JoinNode(JoinNode prev) { - super(prev); - } - - @Specialization - public RubyString join(RubyArray array, RubyString separator) { - return array.getRubyClass().getContext().makeString(array.join(separator.toString())); - } - - } - - @CoreMethod(names = "last", maxArgs = 0) - public abstract static class LastNode extends ArrayCoreMethodNode { - - public LastNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LastNode(LastNode prev) { - super(prev); - } - - @Specialization - public Object last(RubyArray array) { - final int size = array.size(); - if (size == 0) { - return NilPlaceholder.INSTANCE; - } else { - return array.get(size - 1); - } - } - - } - - @CoreMethod(names = {"map", "collect"}, needsBlock = true, maxArgs = 0) - public abstract static class MapNode extends YieldingCoreMethodNode { - - public MapNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MapNode(MapNode prev) { - super(prev); - } - - @Specialization - public RubyArray map(VirtualFrame frame, RubyArray array, RubyProc block) { - final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass()); - - for (int n = 0; n < array.size(); n++) { - result.push(yield(frame, block, array.get(n))); - } - - return result; - } - } - - @CoreMethod(names = {"map!", "collect!"}, needsBlock = true, maxArgs = 0) - public abstract static class MapInPlaceNode extends YieldingCoreMethodNode { - - public MapInPlaceNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MapInPlaceNode(MapInPlaceNode prev) { - super(prev); - } - - @Specialization - public RubyArray mapInPlace(VirtualFrame frame, RubyArray array, RubyProc block) { - for (int n = 0; n < array.size(); n++) { - array.set(n, yield(frame, block, array.get(n))); - } - - return array; - } - } - - @CoreMethod(names = "pop", maxArgs = 0) - public abstract static class PopNode extends ArrayCoreMethodNode { - - public PopNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PopNode(PopNode prev) { - super(prev); - } - - @Specialization - public Object pop(RubyArray array) { - final int size = array.size(); - - if (size == 0) { - return NilPlaceholder.INSTANCE; - } else { - return array.deleteAt(size - 1); - } - } - - } - - @CoreMethod(names = "product", isSplatted = true) - public abstract static class ProductNode extends ArrayCoreMethodNode { - - public ProductNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ProductNode(ProductNode prev) { - super(prev); - } - - @Specialization - public Object product(RubyArray array, Object... args) { - final RubyArray[] arrays = new RubyArray[1 + args.length]; - arrays[0] = array; - System.arraycopy(args, 0, arrays, 1, args.length); - return RubyArray.product(array.getRubyClass().getContext().getCoreLibrary().getArrayClass(), arrays, arrays.length); - } - - } - - @CoreMethod(names = {"push", "<<"}, isSplatted = true) - public abstract static class PushNode extends CoreMethodNode { - - public PushNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PushNode(PushNode prev) { - super(prev); - } - - @Specialization - public RubyArray push(RubyArray array, Object... args) { - for (int n = 0; n < args.length; n++) { - array.push(args[n]); - } - - return array; - } - - } - - @CoreMethod(names = "reject!", needsBlock = true, maxArgs = 0) - public abstract static class RejectInPlaceNode extends YieldingCoreMethodNode { - - public RejectInPlaceNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RejectInPlaceNode(RejectInPlaceNode prev) { - super(prev); - } - - @Specialization - public Object rejectInPlace(VirtualFrame frame, RubyArray array, RubyProc block) { - boolean modified = false; - int n = 0; - - while (n < array.size()) { - if (yieldBoolean(frame, block, array.get(n))) { - array.deleteAt(n); - modified = true; - } else { - n++; - } - } - - if (modified) { - return array; - } else { - return NilPlaceholder.INSTANCE; - } - } - - } - - @CoreMethod(names = "select", needsBlock = true, maxArgs = 0) - public abstract static class SelectNode extends YieldingCoreMethodNode { - - public SelectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SelectNode(SelectNode prev) { - super(prev); - } - - @Specialization - public Object select(VirtualFrame frame, RubyArray array, RubyProc block) { - final RubyArray result = new RubyArray(getContext().getCoreLibrary().getArrayClass()); - - for (int n = 0; n < array.size(); n++) { - final Object value = array.get(n); - - if (yieldBoolean(frame, block, value)) { - result.push(value); - } - } - - return result; - } - - } - - @CoreMethod(names = "shift", maxArgs = 0) - public abstract static class ShiftNode extends CoreMethodNode { - - public ShiftNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ShiftNode(ShiftNode prev) { - super(prev); - } - - @Specialization - public Object shift(RubyArray array) { - final int size = array.size(); - - if (size == 0) { - return NilPlaceholder.INSTANCE; - } else { - return array.deleteAt(0); - } - } - - } - - @CoreMethod(names = {"size", "length"}, maxArgs = 0) - public abstract static class SizeNode extends ArrayCoreMethodNode { - - public SizeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SizeNode(SizeNode prev) { - super(prev); - } - - @Specialization - public int size(RubyArray array) { - return array.size(); - } - - } - - @CoreMethod(names = "sort", maxArgs = 0) - public abstract static class SortNode extends CoreMethodNode { - - public SortNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SortNode(SortNode prev) { - super(prev); - } - - @Specialization - public RubyArray sort(RubyArray array) { - final RubyContext context = array.getRubyClass().getContext(); - - final Object[] objects = array.asList().toArray(); - - Arrays.sort(objects, new Comparator() { - - @Override - public int compare(Object a, Object b) { - final RubyBasicObject aBoxed = context.getCoreLibrary().box(a); - return (int) aBoxed.getLookupNode().lookupMethod("<=>").call(null, aBoxed, null, b); - } - - }); - - return RubyArray.specializedFromObjects(context.getCoreLibrary().getArrayClass(), objects); - } - - } - - @CoreMethod(names = "unshift", isSplatted = true) - public abstract static class UnshiftNode extends CoreMethodNode { - - public UnshiftNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public UnshiftNode(UnshiftNode prev) { - super(prev); - } - - @Specialization - public Object unshift(RubyArray array, Object... args) { - for (int n = 0; n < args.length; n++) { - array.unshift(args[n]); - } - - return array; - } - - } - - @CoreMethod(names = "zip", isSplatted = true) - public abstract static class ZipNode extends CoreMethodNode { - - public ZipNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ZipNode(ZipNode prev) { - super(prev); - } - - @Specialization - public RubyArray zip(RubyArray array, Object... args) { - final RubyContext context = getContext(); - final RubyClass arrayClass = context.getCoreLibrary().getArrayClass(); - - final RubyArray result = new RubyArray(arrayClass); - - for (int n = 0; n < array.size(); n++) { - final RubyArray tuple = new RubyArray(arrayClass); - - tuple.push(array.get(n)); - - for (Object arg : args) { - final RubyArray argArray = (RubyArray) arg; - tuple.push(argArray.get(n)); - } - - result.push(tuple); - } - - return result; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayPushNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayPushNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -public class ArrayPushNode extends RubyNode { - - @Child protected RubyNode array; - @Child protected RubyNode pushed; - - public ArrayPushNode(RubyContext context, SourceSection sourceSection, RubyNode array, RubyNode pushed) { - super(context, sourceSection); - this.array = adoptChild(array); - this.pushed = adoptChild(pushed); - } - - @Override - public Object execute(VirtualFrame frame) { - RubyArray a = (RubyArray) array.execute(frame); - a = (RubyArray) a.dup(); - a.push(pushed.execute(frame)); - return a; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayRestNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayRestNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -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.array.*; - -/** - * Take the rest of values in an array after an index, without using any method lookup. This isn't a - * call - it's an operation on a core class. - */ -@NodeInfo(shortName = "array-rest") -public final class ArrayRestNode extends RubyNode { - - final int begin; - @Child protected RubyNode array; - - public ArrayRestNode(RubyContext context, SourceSection sourceSection, int begin, RubyNode array) { - super(context, sourceSection); - this.begin = begin; - this.array = adoptChild(array); - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyArray arrayObject = (RubyArray) array.execute(frame); - return arrayObject.getRangeExclusive(begin, arrayObject.size()); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BasicObjectNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BasicObjectNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -@CoreClass(name = "BasicObject") -public abstract class BasicObjectNodes { - - @CoreMethod(names = "!", needsSelf = false, maxArgs = 0) - public abstract static class NotNode extends CoreMethodNode { - - public NotNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotNode(NotNode prev) { - super(prev); - } - - @Specialization - public boolean not() { - return false; - } - - } - - @CoreMethod(names = "==", minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(Object a, Object b) { - // TODO(CS) ideally all classes would do this in their own nodes - return a.equals(b); - } - - } - - @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1) - public abstract static class NotEqualNode extends CoreMethodNode { - - public NotEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotEqualNode(NotEqualNode prev) { - super(prev); - } - - @Specialization - public boolean notEqual(Object a, Object b) { - // TODO(CS) ideally all classes would do this in their own nodes - return !a.equals(b); - } - - } - - @CoreMethod(names = "equal?", minArgs = 1, maxArgs = 1) - public abstract static class ReferenceEqualNode extends CoreMethodNode { - - public ReferenceEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ReferenceEqualNode(ReferenceEqualNode prev) { - super(prev); - } - - @Specialization(order = 1) - public boolean equal(@SuppressWarnings("unused") NilPlaceholder a, @SuppressWarnings("unused") NilPlaceholder b) { - return true; - } - - @Specialization(order = 2) - public boolean equal(int a, int b) { - return a == b; - } - - @Specialization(order = 3) - public boolean equal(double a, double b) { - return a == b; - } - - @Specialization(order = 4) - public boolean equal(BigInteger a, BigInteger b) { - return a.compareTo(b) == 0; - } - - @Specialization(order = 5) - public boolean equal(RubyBasicObject a, RubyBasicObject b) { - return a == b; - } - } - - @CoreMethod(names = "initialize", needsSelf = false, maxArgs = 0) - public abstract static class InitializeNode extends CoreMethodNode { - - public InitializeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitializeNode(InitializeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initiailze() { - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = {"send", "__send__"}, needsSelf = true, needsBlock = true, minArgs = 1, isSplatted = true) - public abstract static class SendNode extends CoreMethodNode { - - public SendNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SendNode(SendNode prev) { - super(prev); - } - - @Specialization - public Object send(RubyBasicObject self, Object[] args, @SuppressWarnings("unused") UndefinedPlaceholder block) { - final String name = args[0].toString(); - final Object[] sendArgs = Arrays.copyOfRange(args, 1, args.length); - return self.send(name, null, sendArgs); - } - - @Specialization - public Object send(RubyBasicObject self, Object[] args, RubyProc block) { - final String name = args[0].toString(); - final Object[] sendArgs = Arrays.copyOfRange(args, 1, args.length); - return self.send(name, block, sendArgs); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,661 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -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.core.array.*; - -@CoreClass(name = "Bignum") -public abstract class BignumNodes { - - @CoreMethod(names = "+@", maxArgs = 0) - public abstract static class PosNode extends CoreMethodNode { - - public PosNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PosNode(PosNode prev) { - super(prev); - } - - @Specialization - public BigInteger pos(BigInteger value) { - return value; - } - - } - - @CoreMethod(names = "-@", maxArgs = 0) - public abstract static class NegNode extends CoreMethodNode { - - public NegNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NegNode(NegNode prev) { - super(prev); - } - - @Specialization - public BigInteger neg(BigInteger value) { - return value.negate(); - } - - } - - @CoreMethod(names = "+", minArgs = 1, maxArgs = 1) - public abstract static class AddNode extends CoreMethodNode { - - public AddNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AddNode(AddNode prev) { - super(prev); - } - - @Specialization - public Object add(BigInteger a, int b) { - return a.add(BigInteger.valueOf(b)); - } - - @Specialization - public double add(BigInteger a, double b) { - return a.doubleValue() + b; - } - - @Specialization - public Object add(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.add(b)); - } - - } - - @CoreMethod(names = "-", minArgs = 1, maxArgs = 1) - public abstract static class SubNode extends CoreMethodNode { - - public SubNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SubNode(SubNode prev) { - super(prev); - } - - @Specialization - public Object sub(BigInteger a, int b) { - return a.subtract(BigInteger.valueOf(b)); - } - - @Specialization - public double sub(BigInteger a, double b) { - return a.doubleValue() - b; - } - - @Specialization - public Object sub(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.subtract(b)); - } - - } - - @CoreMethod(names = "*", minArgs = 1, maxArgs = 1) - public abstract static class MulNode extends CoreMethodNode { - - public MulNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MulNode(MulNode prev) { - super(prev); - } - - @Specialization - public Object mul(BigInteger a, int b) { - return a.multiply(BigInteger.valueOf(b)); - } - - @Specialization - public double mul(BigInteger a, double b) { - return a.doubleValue() * b; - } - - @Specialization - public Object mul(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.multiply(b)); - } - - } - - @CoreMethod(names = "**", minArgs = 1, maxArgs = 1) - public abstract static class PowNode extends CoreMethodNode { - - public PowNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PowNode(PowNode prev) { - super(prev); - } - - @Specialization - public BigInteger pow(BigInteger a, int b) { - return a.pow(b); - } - - @Specialization - public double pow(BigInteger a, double b) { - return Math.pow(a.doubleValue(), b); - } - - @Specialization - public BigInteger pow(BigInteger a, BigInteger b) { - BigInteger result = BigInteger.ONE; - - for (BigInteger n = BigInteger.ZERO; b.compareTo(b) < 0; n = n.add(BigInteger.ONE)) { - result = result.multiply(a); - } - - return result; - } - - } - - @CoreMethod(names = "/", minArgs = 1, maxArgs = 1) - public abstract static class DivNode extends CoreMethodNode { - - public DivNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DivNode(DivNode prev) { - super(prev); - } - - @Specialization - public Object div(BigInteger a, int b) { - return a.divide(BigInteger.valueOf(b)); - } - - @Specialization - public double div(BigInteger a, double b) { - return a.doubleValue() / b; - } - - @Specialization - public Object div(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.divide(b)); - } - - } - - @CoreMethod(names = "%", minArgs = 1, maxArgs = 1) - public abstract static class ModNode extends CoreMethodNode { - - public ModNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ModNode(ModNode prev) { - super(prev); - } - - @Specialization - public Object mod(BigInteger a, int b) { - return GeneralConversions.fixnumOrBignum(a.mod(BigInteger.valueOf(b))); - } - - @Specialization - public Object mod(@SuppressWarnings("unused") BigInteger a, @SuppressWarnings("unused") double b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public Object mod(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.mod(b)); - } - - } - - @CoreMethod(names = "divmod", minArgs = 1, maxArgs = 1) - public abstract static class DivModNode extends CoreMethodNode { - - public DivModNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DivModNode(DivModNode prev) { - super(prev); - } - - @SuppressWarnings("unused") - @Specialization - public RubyArray divMod(VirtualFrame frame, BigInteger a, int b) { - return RubyBignum.divMod(getContext(), a, BigInteger.valueOf(b)); - } - - @Specialization - public RubyArray divMod(@SuppressWarnings("unused") BigInteger a, @SuppressWarnings("unused") double b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public RubyArray divMod(BigInteger a, BigInteger b) { - return RubyBignum.divMod(getContext(), a, b); - } - - } - - @CoreMethod(names = "<", minArgs = 1, maxArgs = 1) - public abstract static class LessNode extends CoreMethodNode { - - public LessNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessNode(LessNode prev) { - super(prev); - } - - @Specialization - public boolean less(BigInteger a, int b) { - return a.compareTo(BigInteger.valueOf(b)) < 0; - } - - @Specialization - public boolean less(BigInteger a, double b) { - return a.compareTo(BigInteger.valueOf((long) b)) < 0; - } - - @Specialization - public boolean less(BigInteger a, BigInteger b) { - return a.compareTo(b) < 0; - } - } - - @CoreMethod(names = "<=", minArgs = 1, maxArgs = 1) - public abstract static class LessEqualNode extends CoreMethodNode { - - public LessEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessEqualNode(LessEqualNode prev) { - super(prev); - } - - @Specialization - public boolean lessEqual(BigInteger a, int b) { - return a.compareTo(BigInteger.valueOf(b)) <= 0; - } - - @Specialization - public boolean lessEqual(BigInteger a, double b) { - return a.compareTo(BigInteger.valueOf((long) b)) <= 0; - } - - @Specialization - public boolean lessEqual(BigInteger a, BigInteger b) { - return a.compareTo(b) <= 0; - } - } - - @CoreMethod(names = "==", minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(BigInteger a, int b) { - return a.compareTo(BigInteger.valueOf(b)) == 0; - } - - @Specialization - public boolean equal(BigInteger a, double b) { - return a.compareTo(BigInteger.valueOf((long) b)) == 0; - } - - @Specialization - public boolean equal(BigInteger a, BigInteger b) { - return a.compareTo(b) == 0; - } - } - - @CoreMethod(names = "<=>", minArgs = 1, maxArgs = 1) - public abstract static class CompareNode extends CoreMethodNode { - - public CompareNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CompareNode(CompareNode prev) { - super(prev); - } - - @Specialization - public int compare(BigInteger a, int b) { - return a.compareTo(BigInteger.valueOf(b)); - } - - @Specialization - public int compare(BigInteger a, double b) { - return a.compareTo(BigInteger.valueOf((long) b)); - } - - @Specialization - public int compare(BigInteger a, BigInteger b) { - return a.compareTo(b); - } - } - - @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1) - public abstract static class NotEqualNode extends CoreMethodNode { - - public NotEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotEqualNode(NotEqualNode prev) { - super(prev); - } - - @Specialization - public boolean notEqual(BigInteger a, int b) { - return a.compareTo(BigInteger.valueOf(b)) != 0; - } - - @Specialization - public boolean notEqual(BigInteger a, double b) { - return a.compareTo(BigInteger.valueOf((long) b)) != 0; - } - - @Specialization - public boolean notEqual(BigInteger a, BigInteger b) { - return a.compareTo(b) != 0; - } - } - - @CoreMethod(names = ">=", minArgs = 1, maxArgs = 1) - public abstract static class GreaterEqualNode extends CoreMethodNode { - - public GreaterEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterEqualNode(GreaterEqualNode prev) { - super(prev); - } - - @Specialization - public boolean greaterEqual(BigInteger a, int b) { - return a.compareTo(BigInteger.valueOf(b)) >= 0; - } - - @Specialization - public boolean greaterEqual(BigInteger a, double b) { - return a.compareTo(BigInteger.valueOf((long) b)) >= 0; - } - - @Specialization - public boolean greaterEqual(BigInteger a, BigInteger b) { - return a.compareTo(b) >= 0; - } - } - - @CoreMethod(names = ">", minArgs = 1, maxArgs = 1) - public abstract static class GreaterNode extends CoreMethodNode { - - public GreaterNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterNode(GreaterNode prev) { - super(prev); - } - - @Specialization - public boolean equal(BigInteger a, int b) { - return a.compareTo(BigInteger.valueOf(b)) > 0; - } - - @Specialization - public boolean equal(BigInteger a, double b) { - return a.compareTo(BigInteger.valueOf((long) b)) > 0; - } - - @Specialization - public boolean equal(BigInteger a, BigInteger b) { - return a.compareTo(b) > 0; - } - } - - @CoreMethod(names = "&", minArgs = 1, maxArgs = 1) - public abstract static class BitAndNode extends CoreMethodNode { - - public BitAndNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BitAndNode(BitAndNode prev) { - super(prev); - } - - @Specialization - public Object bitAnd(BigInteger a, int b) { - return GeneralConversions.fixnumOrBignum(a.and(BigInteger.valueOf(b))); - } - - @Specialization - public Object bitAnd(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.and(b)); - } - } - - @CoreMethod(names = "|", minArgs = 1, maxArgs = 1) - public abstract static class BitOrNode extends CoreMethodNode { - - public BitOrNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BitOrNode(BitOrNode prev) { - super(prev); - } - - @Specialization - public Object bitOr(BigInteger a, int b) { - return GeneralConversions.fixnumOrBignum(a.or(BigInteger.valueOf(b))); - } - - @Specialization - public Object bitOr(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.or(b)); - } - } - - @CoreMethod(names = "^", minArgs = 1, maxArgs = 1) - public abstract static class BitXOrNode extends CoreMethodNode { - - public BitXOrNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BitXOrNode(BitXOrNode prev) { - super(prev); - } - - @Specialization - public Object bitXOr(BigInteger a, int b) { - return GeneralConversions.fixnumOrBignum(a.xor(BigInteger.valueOf(b))); - } - - @Specialization - public Object bitXOr(BigInteger a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(a.xor(b)); - } - } - - @CoreMethod(names = "<<", minArgs = 1, maxArgs = 1) - public abstract static class LeftShiftNode extends CoreMethodNode { - - public LeftShiftNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LeftShiftNode(LeftShiftNode prev) { - super(prev); - } - - @Specialization - public Object leftShift(BigInteger a, int b) { - if (b >= 0) { - return GeneralConversions.fixnumOrBignum(a.shiftLeft(b)); - } else { - return GeneralConversions.fixnumOrBignum(a.shiftRight(-b)); - } - } - - } - - @CoreMethod(names = ">>", minArgs = 1, maxArgs = 1) - public abstract static class RightShiftNode extends CoreMethodNode { - - public RightShiftNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RightShiftNode(RightShiftNode prev) { - super(prev); - } - - @Specialization - public Object leftShift(BigInteger a, int b) { - if (b >= 0) { - return GeneralConversions.fixnumOrBignum(a.shiftRight(b)); - } else { - return GeneralConversions.fixnumOrBignum(a.shiftLeft(-b)); - } - } - - } - - @CoreMethod(names = "inspect", maxArgs = 0) - public abstract static class InpsectNode extends CoreMethodNode { - - public InpsectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InpsectNode(InpsectNode prev) { - super(prev); - } - - @Specialization - public RubyString inspect(BigInteger n) { - return getContext().makeString(n.toString()); - } - - } - - @CoreMethod(names = "nonzero?", maxArgs = 0) - public abstract static class NonZeroNode extends CoreMethodNode { - - public NonZeroNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NonZeroNode(NonZeroNode prev) { - super(prev); - } - - @Specialization - public Object nonZero(BigInteger value) { - if (value.compareTo(BigInteger.ZERO) == 0) { - return false; - } else { - return value; - } - } - - } - - @CoreMethod(names = "times", needsBlock = true, maxArgs = 0) - public abstract static class TimesNode extends YieldingCoreMethodNode { - - private final BranchProfile breakProfile = new BranchProfile(); - private final BranchProfile nextProfile = new BranchProfile(); - private final BranchProfile redoProfile = new BranchProfile(); - - public TimesNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public TimesNode(TimesNode prev) { - super(prev); - } - - @Specialization - public Object times(VirtualFrame frame, BigInteger n, RubyProc block) { - outer: for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) { - while (true) { - try { - yield(frame, block, i); - continue outer; - } catch (BreakException e) { - breakProfile.enter(); - return e.getResult(); - } catch (NextException e) { - nextProfile.enter(); - continue outer; - } catch (RedoException e) { - redoProfile.enter(); - } - } - } - - return n; - } - - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS(BigInteger value) { - return getContext().makeString(value.toString()); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ClassNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ClassNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -@CoreClass(name = "Class") -public abstract class ClassNodes { - - @CoreMethod(names = "===", minArgs = 1, maxArgs = 1) - public abstract static class ContainsInstanceNode extends CoreMethodNode { - - public ContainsInstanceNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ContainsInstanceNode(ContainsInstanceNode prev) { - super(prev); - } - - @Specialization - public boolean containsInstance(RubyClass rubyClass, RubyBasicObject instance) { - return instance.getRubyClass().assignableTo(rubyClass); - } - } - - @CoreMethod(names = "new", needsBlock = true, isSplatted = true) - public abstract static class NewNode extends CoreMethodNode { - - @Child protected DispatchHeadNode initialize; - - public NewNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - initialize = adoptChild(new DispatchHeadNode(context, getSourceSection(), "initialize", false)); - } - - public NewNode(NewNode prev) { - super(prev); - initialize = adoptChild(prev.initialize); - } - - @Specialization - public RubyBasicObject newInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, @SuppressWarnings("unused") UndefinedPlaceholder block) { - return doNewInstance(frame, rubyClass, args, null); - } - - @Specialization - public RubyBasicObject newInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, RubyProc block) { - return doNewInstance(frame, rubyClass, args, block); - } - - private RubyBasicObject doNewInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, RubyProc block) { - final RubyBasicObject instance = rubyClass.newInstance(); - initialize.dispatch(frame, instance, block, args); - return instance; - } - - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS(RubyClass rubyClass) { - return getContext().makeString(rubyClass.getName()); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ComparableNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ComparableNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -@CoreClass(name = "Comparable") -public abstract class ComparableNodes { - - public abstract static class ComparableCoreMethodNode extends CoreMethodNode { - - @Child protected DispatchHeadNode compareNode; - - public ComparableCoreMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - compareNode = adoptChild(new DispatchHeadNode(context, getSourceSection(), "<=>", false)); - } - - public ComparableCoreMethodNode(ComparableCoreMethodNode prev) { - super(prev); - compareNode = adoptChild(prev.compareNode); - } - - public int compare(VirtualFrame frame, RubyBasicObject receiverObject, Object comparedTo) { - return (int) compareNode.dispatch(frame, receiverObject, null, comparedTo); - } - - } - - @CoreMethod(names = "<", isModuleMethod = true, minArgs = 1, maxArgs = 1) - public abstract static class LessNode extends ComparableCoreMethodNode { - - public LessNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessNode(LessNode prev) { - super(prev); - } - - @Specialization - public boolean less(VirtualFrame frame, RubyBasicObject self, Object comparedTo) { - return compare(frame, self, comparedTo) < 0; - } - - } - - @CoreMethod(names = "<=", isModuleMethod = true, minArgs = 1, maxArgs = 1) - public abstract static class LessEqualNode extends ComparableCoreMethodNode { - - public LessEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessEqualNode(LessEqualNode prev) { - super(prev); - } - - @Specialization - public boolean lessEqual(VirtualFrame frame, RubyBasicObject self, Object comparedTo) { - return compare(frame, self, comparedTo) <= 0; - } - - } - - @CoreMethod(names = "==", isModuleMethod = true, minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends ComparableCoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(VirtualFrame frame, RubyBasicObject self, Object comparedTo) { - if (self == comparedTo) { - return true; - } - - try { - return compare(frame, self, comparedTo) == 0; - } catch (Exception e) { - // Comparable#== catches and ignores all exceptions in <=>, returning false - return false; - } - } - } - - @CoreMethod(names = ">=", isModuleMethod = true, minArgs = 1, maxArgs = 1) - public abstract static class GreaterEqualNode extends ComparableCoreMethodNode { - - public GreaterEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterEqualNode(GreaterEqualNode prev) { - super(prev); - } - - @Specialization - public boolean greaterEqual(VirtualFrame frame, RubyBasicObject self, Object comparedTo) { - return compare(frame, self, comparedTo) >= 0; - } - - } - - @CoreMethod(names = ">", isModuleMethod = true, minArgs = 1, maxArgs = 1) - public abstract static class GreaterNode extends ComparableCoreMethodNode { - - public GreaterNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterNode(GreaterNode prev) { - super(prev); - } - - @Specialization - public boolean greater(VirtualFrame frame, RubyBasicObject self, Object comparedTo) { - return compare(frame, self, comparedTo) > 0; - } - - } - - @CoreMethod(names = "between?", isModuleMethod = true, minArgs = 2, maxArgs = 2) - public abstract static class BetweenNode extends ComparableCoreMethodNode { - - public BetweenNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BetweenNode(BetweenNode prev) { - super(prev); - } - - @Specialization - public boolean between(VirtualFrame frame, RubyBasicObject self, Object min, Object max) { - return !(compare(frame, self, min) < 0 || compare(frame, self, max) > 0); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ContinuationNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ContinuationNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Continuation") -public abstract class ContinuationNodes { - - @CoreMethod(names = "call", isSplatted = true) - public abstract static class CallNode extends CoreMethodNode { - - public CallNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CallNode(CallNode prev) { - super(prev); - } - - @Specialization - public Object call(RubyContinuation continuation, Object[] args) { - continuation.call(args); - return null; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreClass.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreClass.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.lang.annotation.*; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface CoreClass { - - String name(); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethod.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethod.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.core; - -import java.lang.annotation.*; - -import com.oracle.truffle.ruby.runtime.methods.*; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface CoreMethod { - - String[] names(); - - boolean isModuleMethod() default false; - - boolean needsSelf() default true; - - boolean isSplatted() default false; - - boolean needsBlock() default false; - - boolean appendCallNode() default false; - - int minArgs() default Arity.NO_MINIMUM; - - int maxArgs() default Arity.NO_MAXIMUM; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -@NodeChild(value = "arguments", type = RubyNode[].class) -public abstract class CoreMethodNode extends RubyNode { - - public CoreMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CoreMethodNode(CoreMethodNode prev) { - super(prev); - } - -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +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.nodes.core; - -import java.util.*; - -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.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.control.*; -import com.oracle.truffle.ruby.nodes.methods.arguments.*; -import com.oracle.truffle.ruby.nodes.objects.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -public abstract class CoreMethodNodeManager { - - /** - * Register all the nodes that represent core methods as methods with their respective classes, - * 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()) { - addMethod(rubyObjectClass, methodDetails); - } - } - - /** - * Collect up all the core method nodes. Abstracted to allow the SVM to implement at compile - * type. - */ - public static List getMethods() { - final List methods = new ArrayList<>(); - getMethods(methods, ArrayNodesFactory.getFactories()); - getMethods(methods, BasicObjectNodesFactory.getFactories()); - getMethods(methods, BignumNodesFactory.getFactories()); - getMethods(methods, ClassNodesFactory.getFactories()); - getMethods(methods, ContinuationNodesFactory.getFactories()); - getMethods(methods, ComparableNodesFactory.getFactories()); - getMethods(methods, DirNodesFactory.getFactories()); - getMethods(methods, ExceptionNodesFactory.getFactories()); - getMethods(methods, FalseClassNodesFactory.getFactories()); - getMethods(methods, FiberNodesFactory.getFactories()); - getMethods(methods, FileNodesFactory.getFactories()); - getMethods(methods, FixnumNodesFactory.getFactories()); - getMethods(methods, FloatNodesFactory.getFactories()); - getMethods(methods, HashNodesFactory.getFactories()); - getMethods(methods, KernelNodesFactory.getFactories()); - getMethods(methods, MainNodesFactory.getFactories()); - getMethods(methods, MatchDataNodesFactory.getFactories()); - getMethods(methods, MathNodesFactory.getFactories()); - getMethods(methods, ModuleNodesFactory.getFactories()); - getMethods(methods, NilClassNodesFactory.getFactories()); - getMethods(methods, ObjectNodesFactory.getFactories()); - getMethods(methods, ObjectSpaceNodesFactory.getFactories()); - getMethods(methods, ProcessNodesFactory.getFactories()); - getMethods(methods, ProcNodesFactory.getFactories()); - getMethods(methods, RangeNodesFactory.getFactories()); - getMethods(methods, RegexpNodesFactory.getFactories()); - getMethods(methods, SignalNodesFactory.getFactories()); - getMethods(methods, StringNodesFactory.getFactories()); - getMethods(methods, StructNodesFactory.getFactories()); - getMethods(methods, SymbolNodesFactory.getFactories()); - getMethods(methods, ThreadNodesFactory.getFactories()); - getMethods(methods, TimeNodesFactory.getFactories()); - getMethods(methods, TrueClassNodesFactory.getFactories()); - return methods; - } - - /** - * Collect up the core methods created by a factory. - */ - private static void getMethods(List methods, List> nodeFactories) { - for (NodeFactory nodeFactory : nodeFactories) { - final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class); - final Class nodeClass = generatedBy.value(); - final CoreClass classAnnotation = nodeClass.getEnclosingClass().getAnnotation(CoreClass.class); - final CoreMethod methodAnnotation = nodeClass.getAnnotation(CoreMethod.class); - methods.add(new MethodDetails(classAnnotation, methodAnnotation, nodeFactory)); - } - } - - /** - * Take a core method node factory, the annotations for the class and method, and add it as a - * method on the correct class. - */ - private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDetails) { - assert rubyObjectClass != null; - assert methodDetails != null; - - final RubyContext context = rubyObjectClass.getContext(); - - RubyModule module; - - if (methodDetails.getClassAnnotation().name().equals("main")) { - module = context.getCoreLibrary().getMainObject().getSingletonClass(); - } else { - module = (RubyModule) rubyObjectClass.lookupConstant(methodDetails.getClassAnnotation().name()); - } - - assert module != null : methodDetails.getClassAnnotation().name(); - - final List names = Arrays.asList(methodDetails.getMethodAnnotation().names()); - assert names.size() >= 1; - - final String canonicalName = names.get(0); - final List aliases = names.subList(1, names.size()); - - final UniqueMethodIdentifier uniqueIdentifier = new UniqueMethodIdentifier(); - final Visibility visibility = Visibility.PUBLIC; - - final RubyRootNode pristineRootNode = makeGenericMethod(context, methodDetails); - final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode)); - - final String intrinsicName = methodDetails.getClassAnnotation().name() + "#" + canonicalName; - - final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRootNode, true, - methodDetails.getMethodAnnotation().appendCallNode()); - final RubyMethod method = new RubyMethod(pristineRootNode.getSourceSection(), module, uniqueIdentifier, intrinsicName, canonicalName, visibility, false, methodImplementation); - - module.addMethod(method); - - if (methodDetails.getMethodAnnotation().isModuleMethod()) { - module.getSingletonClass().addMethod(method); - } - - for (String alias : aliases) { - final RubyMethod withAlias = method.withNewName(alias); - - module.addMethod(withAlias); - - if (methodDetails.getMethodAnnotation().isModuleMethod()) { - module.getSingletonClass().addMethod(withAlias); - } - } - } - - private static RubyRootNode makeGenericMethod(RubyContext context, MethodDetails methodDetails) { - final SourceSection sourceSection = new CoreSourceSection(methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0]); - - final Arity arity = new Arity(methodDetails.getMethodAnnotation().minArgs(), methodDetails.getMethodAnnotation().maxArgs()); - - final List argumentsNodes = new ArrayList<>(); - - if (methodDetails.getMethodAnnotation().needsSelf()) { - argumentsNodes.add(new SelfNode(context, sourceSection)); - } - - if (methodDetails.getMethodAnnotation().isSplatted()) { - argumentsNodes.add(new ReadAllArgumentsNode(context, sourceSection)); - } else { - assert arity.getMaximum() != Arity.NO_MAXIMUM; - - for (int n = 0; n < arity.getMaximum(); n++) { - argumentsNodes.add(new ReadPreArgumentNode(context, sourceSection, n, true)); - } - } - - if (methodDetails.getMethodAnnotation().needsBlock()) { - argumentsNodes.add(new ReadBlockArgumentNode(context, sourceSection, true)); - } - - final RubyNode methodNode = methodDetails.getNodeFactory().createNode(context, sourceSection, argumentsNodes.toArray(new RubyNode[argumentsNodes.size()])); - final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, arity); - final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, methodNode); - - return new RubyRootNode(sourceSection, null, methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0] + "(core)", block); - } - - public static class MethodDetails { - - private final CoreClass classAnnotation; - private final CoreMethod methodAnnotation; - private final NodeFactory nodeFactory; - - public MethodDetails(CoreClass classAnnotation, CoreMethod methodAnnotation, NodeFactory nodeFactory) { - assert classAnnotation != null; - assert methodAnnotation != null; - assert nodeFactory != null; - this.classAnnotation = classAnnotation; - this.methodAnnotation = methodAnnotation; - this.nodeFactory = nodeFactory; - } - - public CoreClass getClassAnnotation() { - return classAnnotation; - } - - public CoreMethod getMethodAnnotation() { - return methodAnnotation; - } - - public NodeFactory getNodeFactory() { - return nodeFactory; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/DirNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/DirNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.io.*; -import java.nio.file.*; -import java.nio.file.attribute.*; - -import com.oracle.truffle.api.CompilerDirectives.SlowPath; -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -@CoreClass(name = "Dir") -public abstract class DirNodes { - - @CoreMethod(names = "[]", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class GlobNode extends CoreMethodNode { - - public GlobNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GlobNode(GlobNode prev) { - super(prev); - } - - @Specialization - public RubyArray glob(RubyString glob) { - return glob(getContext(), glob.toString()); - } - - @SlowPath - private static RubyArray glob(final RubyContext context, String glob) { - /* - * Globbing is quite complicated. We've implemented a subset of the functionality that - * satisfies MSpec, but it will likely break for anyone else. - */ - - context.implementationMessage("globbing %s", glob); - - String absoluteGlob; - - if (!glob.startsWith("/")) { - absoluteGlob = new File(".", glob).getAbsolutePath().toString(); - } else { - absoluteGlob = glob; - } - - // Get the first star - - final int firstStar = absoluteGlob.indexOf('*'); - assert firstStar >= 0; - - // Walk back from that to the first / before that star - - int prefixLength = firstStar; - - while (prefixLength > 0 && absoluteGlob.charAt(prefixLength) == File.separatorChar) { - prefixLength--; - } - - final String prefix = absoluteGlob.substring(0, prefixLength - 1); - - final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + absoluteGlob.substring(prefixLength)); - - final RubyArray array = new RubyArray(context.getCoreLibrary().getArrayClass()); - - try { - Files.walkFileTree(FileSystems.getDefault().getPath(prefix), new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (matcher.matches(file)) { - array.push(context.makeString(file.toString())); - } - - return FileVisitResult.CONTINUE; - } - - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - - return array; - } - - } - - @CoreMethod(names = "chdir", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 1, maxArgs = 1) - public abstract static class ChdirNode extends YieldingCoreMethodNode { - - public ChdirNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ChdirNode(ChdirNode prev) { - super(prev); - } - - @Specialization - public Object chdir(VirtualFrame frame, RubyString path, RubyProc block) { - final RubyContext context = getContext(); - - final String previous = context.getCurrentDirectory(); - context.setCurrentDirectory(path.toString()); - - if (block != null) { - try { - return yield(frame, block, path); - } finally { - context.setCurrentDirectory(previous); - } - } else { - return 0; - } - } - - } - - @CoreMethod(names = {"exist?", "exists?"}, isModuleMethod = true, needsSelf = false, maxArgs = 1) - public abstract static class ExistsNode extends CoreMethodNode { - - public ExistsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExistsNode(ExistsNode prev) { - super(prev); - } - - @Specialization - public boolean exists(RubyString path) { - return new File(path.toString()).isDirectory(); - } - - } - - @CoreMethod(names = "pwd", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class PwdNode extends CoreMethodNode { - - public PwdNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PwdNode(PwdNode prev) { - super(prev); - } - - @Specialization - public RubyString pwd() { - return getContext().makeString(getContext().getCurrentDirectory()); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ExceptionNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ExceptionNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -@CoreClass(name = "Exception") -public abstract class ExceptionNodes { - - @CoreMethod(names = "initialize", minArgs = 0, maxArgs = 1) - public abstract static class InitializeNode extends CoreMethodNode { - - public InitializeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitializeNode(InitializeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initialize(RubyException exception, @SuppressWarnings("unused") UndefinedPlaceholder message) { - exception.initialize(getContext().makeString(" ")); - return NilPlaceholder.INSTANCE; - } - - @Specialization - public NilPlaceholder initialize(RubyException exception, RubyString message) { - exception.initialize(message); - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "backtrace", needsSelf = false, maxArgs = 0) - public abstract static class BacktraceNode extends CoreMethodNode { - - public BacktraceNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BacktraceNode(BacktraceNode prev) { - super(prev); - } - - @Specialization - public RubyArray backtrace() { - return new RubyArray(getContext().getCoreLibrary().getArrayClass()); - } - - } - - @CoreMethod(names = "message", maxArgs = 0) - public abstract static class MessageNode extends CoreMethodNode { - - public MessageNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MessageNode(MessageNode prev) { - super(prev); - } - - @Specialization - public RubyString message(RubyException exception) { - return exception.getMessage(); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FalseClassNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FalseClassNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "FalseClass") -public abstract class FalseClassNodes { - - @CoreMethod(names = "!", needsSelf = false, maxArgs = 0) - public abstract static class NotNode extends CoreMethodNode { - - public NotNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotNode(NotNode prev) { - super(prev); - } - - @Specialization - public boolean not() { - return true; - } - - } - - @CoreMethod(names = {"==", "===", "=~"}, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(boolean other) { - return !other; - } - - @Specialization - public boolean equal(Object other) { - return other instanceof Boolean && !((boolean) other); - } - - } - - @CoreMethod(names = "^", needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class XorNode extends CoreMethodNode { - - public XorNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public XorNode(XorNode prev) { - super(prev); - } - - @Specialization - public boolean xor(boolean other) { - return false ^ other; - } - - } - - @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS() { - return getContext().makeString("false"); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FiberNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FiberNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Fiber") -public abstract class FiberNodes { - - @CoreMethod(names = "resume", isSplatted = true) - public abstract static class ResumeNode extends CoreMethodNode { - - public ResumeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ResumeNode(ResumeNode prev) { - super(prev); - } - - @Specialization - public Object resume(RubyFiber fiberBeingResumed, Object[] args) { - final RubyFiber sendingFiber = getContext().getFiberManager().getCurrentFiber(); - - fiberBeingResumed.resume(sendingFiber, args); - - return sendingFiber.waitForResume(); - } - - } - - @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0) - public abstract static class InitializeNode extends CoreMethodNode { - - public InitializeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitializeNode(InitializeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initialize(RubyFiber fiber, RubyProc block) { - fiber.initialize(block); - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "yield", isModuleMethod = true, needsSelf = false, isSplatted = true) - public abstract static class YieldNode extends CoreMethodNode { - - public YieldNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public YieldNode(YieldNode prev) { - super(prev); - } - - @Specialization - public Object yield(Object[] args) { - final RubyFiber yieldingFiber = getContext().getFiberManager().getCurrentFiber(); - final RubyFiber fiberYieldedTo = yieldingFiber.lastResumedByFiber; - - fiberYieldedTo.resume(yieldingFiber, args); - - return yieldingFiber.waitForResume(); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FileNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FileNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.io.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -@CoreClass(name = "File") -public abstract class FileNodes { - - @CoreMethod(names = "absolute_path", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class AbsolutePathNode extends CoreMethodNode { - - public AbsolutePathNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AbsolutePathNode(AbsolutePathNode prev) { - super(prev); - } - - @Specialization - public RubyString absolutePath(RubyString path) { - return getContext().makeString(new File(path.toString()).getAbsolutePath()); - } - - } - - @CoreMethod(names = "close", maxArgs = 0) - public abstract static class CloseNode extends CoreMethodNode { - - public CloseNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CloseNode(CloseNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder close(RubyFile file) { - file.close(); - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "directory?", isModuleMethod = true, needsSelf = false, maxArgs = 1) - public abstract static class DirectoryNode extends CoreMethodNode { - - public DirectoryNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DirectoryNode(DirectoryNode prev) { - super(prev); - } - - @Specialization - public boolean directory(RubyString path) { - return new File(path.toString()).isDirectory(); - } - - } - - @CoreMethod(names = "dirname", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class DirnameNode extends CoreMethodNode { - - public DirnameNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DirnameNode(DirnameNode prev) { - super(prev); - } - - @Specialization - public RubyString dirname(RubyString path) { - final String parent = new File(path.toString()).getParent(); - - if (parent == null) { - return getContext().makeString("."); - } else { - return getContext().makeString(parent); - } - } - - } - - @CoreMethod(names = "each_line", needsBlock = true, maxArgs = 0) - public abstract static class EachLineNode extends YieldingCoreMethodNode { - - public EachLineNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EachLineNode(EachLineNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder eachLine(VirtualFrame frame, RubyFile file, RubyProc block) { - final RubyContext context = getContext(); - - // TODO(cs): this buffered reader may consume too much - - final BufferedReader lineReader = new BufferedReader(file.getReader()); - - while (true) { - String line; - - try { - line = lineReader.readLine(); - } catch (IOException e) { - throw new RuntimeException(e); - } - - if (line == null) { - break; - } - - yield(frame, block, context.makeString(line)); - } - - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = {"exist?", "exists?"}, isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class ExistsNode extends CoreMethodNode { - - public ExistsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExistsNode(ExistsNode prev) { - super(prev); - } - - @Specialization - public boolean exists(RubyString path) { - return new File(path.toString()).isFile(); - } - - } - - @CoreMethod(names = "executable?", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class ExecutableNode extends CoreMethodNode { - - public ExecutableNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExecutableNode(ExecutableNode prev) { - super(prev); - } - - @Specialization - public boolean executable(RubyString path) { - return new File(path.toString()).canExecute(); - } - - } - - @CoreMethod(names = "expand_path", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2) - public abstract static class ExpandPathNode extends CoreMethodNode { - - public ExpandPathNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExpandPathNode(ExpandPathNode prev) { - super(prev); - } - - @Specialization - public RubyString expandPath(RubyString path, @SuppressWarnings("unused") UndefinedPlaceholder dir) { - return getContext().makeString(RubyFile.expandPath(path.toString())); - } - - @Specialization - public RubyString expandPath(RubyString path, RubyString dir) { - return getContext().makeString(RubyFile.expandPath(path.toString(), dir.toString())); - } - - } - - @CoreMethod(names = "file?", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class FileNode extends CoreMethodNode { - - public FileNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FileNode(FileNode prev) { - super(prev); - } - - @Specialization - public boolean file(RubyString path) { - return new File(path.toString()).isFile(); - } - - } - - @CoreMethod(names = "join", isModuleMethod = true, needsSelf = false, isSplatted = true) - public abstract static class JoinNode extends CoreMethodNode { - - public JoinNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public JoinNode(JoinNode prev) { - super(prev); - } - - @Specialization - public RubyString join(Object[] parts) { - return getContext().makeString(RubyArray.join(parts, File.separator)); - } - } - - @CoreMethod(names = "open", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 2, maxArgs = 2) - public abstract static class OpenNode extends YieldingCoreMethodNode { - - public OpenNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public OpenNode(OpenNode prev) { - super(prev); - } - - @Specialization - public Object open(VirtualFrame frame, RubyString fileName, RubyString mode, RubyProc block) { - final RubyFile file = RubyFile.open(getContext(), fileName.toString(), mode.toString()); - - if (block != null) { - try { - yield(frame, block, file); - } finally { - file.close(); - } - } - - return file; - } - - } - - @CoreMethod(names = "write", maxArgs = 0) - public abstract static class WriteNode extends CoreMethodNode { - - public WriteNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public WriteNode(WriteNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder write(RubyFile file, RubyString string) { - try { - final Writer writer = file.getWriter(); - writer.write(string.toString()); - writer.flush(); - } catch (IOException e) { - throw new RuntimeException(e); - } - - return NilPlaceholder.INSTANCE; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,889 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -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.core.array.*; - -@CoreClass(name = "Fixnum") -public abstract class FixnumNodes { - - @CoreMethod(names = "+@", maxArgs = 0) - public abstract static class PosNode extends CoreMethodNode { - - public PosNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PosNode(PosNode prev) { - super(prev); - } - - @Specialization - public int pos(int value) { - return value; - } - - } - - @CoreMethod(names = "-@", maxArgs = 0) - public abstract static class NegNode extends CoreMethodNode { - - public NegNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NegNode(NegNode prev) { - super(prev); - } - - @Specialization(rewriteOn = ArithmeticException.class) - public int neg(int value) { - return ExactMath.subtractExact(0, value); - } - - @Specialization - public BigInteger negWithOverflow(int value) { - return BigInteger.valueOf(value).negate(); - } - - } - - @CoreMethod(names = "+", minArgs = 1, maxArgs = 1) - public abstract static class AddNode extends CoreMethodNode { - - public AddNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AddNode(AddNode prev) { - super(prev); - } - - @Specialization(rewriteOn = ArithmeticException.class) - public int add(int a, int b) { - return ExactMath.addExact(a, b); - } - - @Specialization - public Object addWithOverflow(int a, int b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).add(BigInteger.valueOf(b))); - } - - @Specialization - public double add(int a, double b) { - return a + b; - } - - @Specialization - public Object add(int a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).add(b)); - } - - } - - @CoreMethod(names = "-", minArgs = 1, maxArgs = 1) - public abstract static class SubNode extends CoreMethodNode { - - public SubNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SubNode(SubNode prev) { - super(prev); - } - - @Specialization(rewriteOn = ArithmeticException.class) - public int sub(int a, int b) { - return ExactMath.subtractExact(a, b); - } - - @Specialization - public Object subWithOverflow(int a, int b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).subtract(BigInteger.valueOf(b))); - } - - @Specialization - public double sub(int a, double b) { - return a - b; - } - - @Specialization - public Object sub(int a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).subtract(b)); - } - - } - - @CoreMethod(names = "*", minArgs = 1, maxArgs = 1) - public abstract static class MulNode extends CoreMethodNode { - - public MulNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MulNode(MulNode prev) { - super(prev); - } - - @Specialization(rewriteOn = ArithmeticException.class) - public int mul(int a, int b) { - return ExactMath.multiplyExact(a, b); - } - - @Specialization - public Object mulWithOverflow(int a, int b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).multiply(BigInteger.valueOf(b))); - } - - @Specialization - public double mul(int a, double b) { - return a * b; - } - - @Specialization - public Object mul(int a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).multiply(b)); - } - - } - - @CoreMethod(names = "**", minArgs = 1, maxArgs = 1) - public abstract static class PowNode extends CoreMethodNode { - - public PowNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PowNode(PowNode prev) { - super(prev); - } - - @Specialization - public Object pow(int a, int b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).pow(b)); - } - - @Specialization - public double pow(int a, double b) { - return Math.pow(a, b); - } - - @Specialization - public Object pow(int a, BigInteger b) { - final BigInteger bigA = BigInteger.valueOf(a); - - BigInteger result = BigInteger.ONE; - - for (BigInteger n = BigInteger.ZERO; b.compareTo(b) < 0; n = n.add(BigInteger.ONE)) { - result = result.multiply(bigA); - } - - return result; - } - - } - - @CoreMethod(names = "/", minArgs = 1, maxArgs = 1) - public abstract static class DivNode extends CoreMethodNode { - - public DivNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DivNode(DivNode prev) { - super(prev); - } - - @Specialization - public int div(int a, int b) { - return a / b; - } - - @Specialization - public double div(int a, double b) { - return a / b; - } - - @Specialization - public int div(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") BigInteger b) { - return 0; - } - } - - @CoreMethod(names = "%", minArgs = 1, maxArgs = 1) - public abstract static class ModNode extends CoreMethodNode { - - public ModNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ModNode(ModNode prev) { - super(prev); - } - - @Specialization - public int mod(int a, int b) { - return a % b; - } - - @Specialization - public double mod(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") double b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public BigInteger mod(@SuppressWarnings("unused") int a, BigInteger b) { - return b; - } - } - - @CoreMethod(names = "divmod", minArgs = 1, maxArgs = 1) - public abstract static class DivModNode extends CoreMethodNode { - - public DivModNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DivModNode(DivModNode prev) { - super(prev); - } - - @Specialization - public RubyArray divMod(int a, int b) { - int q; - - if (b < 0) { - if (a < 0) { - q = -a / -b; - } else { - q = -(a / -b); - } - } else { - if (a < 0) { - q = -(-a / b); - } else { - q = a / b; - } - } - - int r = a - q * b; - - if ((r < 0 && b > 0) || (r > 0 && b < 0)) { - r += b; - q -= 1; - } - - final FixnumImmutablePairArrayStore store = new FixnumImmutablePairArrayStore(q, r); - return new RubyArray(getContext().getCoreLibrary().getArrayClass(), store); - } - - @Specialization - public RubyArray divMod(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") double b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public RubyArray divMod(int a, BigInteger b) { - return RubyBignum.divMod(getContext(), BigInteger.valueOf(a), b); - } - } - - @CoreMethod(names = "<", minArgs = 1, maxArgs = 1) - public abstract static class LessNode extends CoreMethodNode { - - public LessNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessNode(LessNode prev) { - super(prev); - } - - @Specialization - public boolean less(int a, int b) { - return a < b; - } - - @Specialization - public boolean less(int a, double b) { - return a < b; - } - - @Specialization - public boolean less(int a, BigInteger b) { - return BigInteger.valueOf(a).compareTo(b) < 0; - } - } - - @CoreMethod(names = "<=", minArgs = 1, maxArgs = 1) - public abstract static class LessEqualNode extends CoreMethodNode { - - public LessEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessEqualNode(LessEqualNode prev) { - super(prev); - } - - @Specialization - public boolean lessEqual(int a, int b) { - return a <= b; - } - - @Specialization - public boolean lessEqual(int a, double b) { - return a <= b; - } - - @Specialization - public boolean lessEqual(int a, BigInteger b) { - return BigInteger.valueOf(a).compareTo(b) <= 0; - } - } - - @CoreMethod(names = {"==", "==="}, minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(int a, int b) { - return a == b; - } - - @Specialization - public boolean equal(int a, double b) { - return a == b; - } - - @Specialization - public boolean equal(int a, BigInteger b) { - return BigInteger.valueOf(a).compareTo(b) == 0; - } - } - - @CoreMethod(names = "<=>", minArgs = 1, maxArgs = 1) - public abstract static class CompareNode extends CoreMethodNode { - - public CompareNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CompareNode(CompareNode prev) { - super(prev); - } - - @Specialization - public int compare(int a, int b) { - return Integer.compare(a, b); - } - - @Specialization - public int compare(int a, double b) { - return Double.compare(a, b); - } - - @Specialization - public int compare(int a, BigInteger b) { - return BigInteger.valueOf(a).compareTo(b); - } - } - - @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1) - public abstract static class NotEqualNode extends CoreMethodNode { - - public NotEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotEqualNode(NotEqualNode prev) { - super(prev); - } - - @Specialization - public boolean notEqual(int a, int b) { - return a != b; - } - - @Specialization - public boolean notEqual(int a, double b) { - return a != b; - } - - @Specialization - public boolean notEqual(int a, BigInteger b) { - return BigInteger.valueOf(a).compareTo(b) != 0; - } - } - - @CoreMethod(names = ">=", minArgs = 1, maxArgs = 1) - public abstract static class GreaterEqualNode extends CoreMethodNode { - - public GreaterEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterEqualNode(GreaterEqualNode prev) { - super(prev); - } - - @Specialization - public boolean greaterEqual(int a, int b) { - return a >= b; - } - - @Specialization - public boolean greaterEqual(int a, double b) { - return a >= b; - } - - @Specialization - public boolean greaterEqual(int a, BigInteger b) { - return BigInteger.valueOf(a).compareTo(b) >= 0; - } - } - - @CoreMethod(names = ">", minArgs = 1, maxArgs = 1) - public abstract static class GreaterNode extends CoreMethodNode { - - public GreaterNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterNode(GreaterNode prev) { - super(prev); - } - - @Specialization - public boolean equal(int a, int b) { - return a > b; - } - - @Specialization - public boolean equal(int a, double b) { - return a > b; - } - - @Specialization - public boolean equal(int a, BigInteger b) { - return BigInteger.valueOf(a).compareTo(b) > 0; - } - } - - @CoreMethod(names = "~", maxArgs = 0) - public abstract static class ComplementNode extends CoreMethodNode { - - public ComplementNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ComplementNode(ComplementNode prev) { - super(prev); - } - - @Specialization - public int complement(int n) { - return ~n; - } - - } - - @CoreMethod(names = "&", minArgs = 1, maxArgs = 1) - public abstract static class BitAndNode extends CoreMethodNode { - - public BitAndNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BitAndNode(BitAndNode prev) { - super(prev); - } - - @Specialization - public int bitAnd(int a, int b) { - return a & b; - } - - @Specialization - public Object bitAnd(int a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).and(b)); - } - } - - @CoreMethod(names = "|", minArgs = 1, maxArgs = 1) - public abstract static class BitOrNode extends CoreMethodNode { - - public BitOrNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BitOrNode(BitOrNode prev) { - super(prev); - } - - @Specialization - public int bitOr(int a, int b) { - return a | b; - } - - @Specialization - public Object bitOr(int a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).or(b)); - } - } - - @CoreMethod(names = "^", minArgs = 1, maxArgs = 1) - public abstract static class BitXOrNode extends CoreMethodNode { - - public BitXOrNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BitXOrNode(BitXOrNode prev) { - super(prev); - } - - @Specialization - public int bitXOr(int a, int b) { - return a ^ b; - } - - @Specialization - public Object bitXOr(int a, BigInteger b) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).xor(b)); - } - } - - @CoreMethod(names = "<<", minArgs = 1, maxArgs = 1) - public abstract static class LeftShiftNode extends CoreMethodNode { - - public LeftShiftNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LeftShiftNode(LeftShiftNode prev) { - super(prev); - } - - @Specialization - public Object leftShift(int a, int b) { - if (b > 0) { - if (RubyFixnum.SIZE - Integer.numberOfLeadingZeros(a) + b > RubyFixnum.SIZE - 1) { - return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).shiftLeft(b)); - } else { - return a << b; - } - } else { - if (-b >= Integer.SIZE) { - return 0; - } else { - return a >> -b; - } - } - } - - } - - @CoreMethod(names = ">>", minArgs = 1, maxArgs = 1) - public abstract static class RightShiftNode extends CoreMethodNode { - - public RightShiftNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RightShiftNode(RightShiftNode prev) { - super(prev); - } - - @Specialization - public int rightShift(int a, int b) { - if (b > 0) { - return a >> b; - } else { - if (-b >= RubyFixnum.SIZE) { - return 0; - } else { - return a >> -b; - } - } - } - - } - - @CoreMethod(names = "[]", minArgs = 1, maxArgs = 1) - public abstract static class GetIndexNode extends CoreMethodNode { - - public GetIndexNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GetIndexNode(GetIndexNode prev) { - super(prev); - } - - @Specialization - public int getIndex(int self, int index) { - if ((self & (1 << index)) == 0) { - return 0; - } else { - return 1; - } - } - - } - - @CoreMethod(names = "chr", maxArgs = 0) - public abstract static class ChrNode extends CoreMethodNode { - - public ChrNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ChrNode(ChrNode prev) { - super(prev); - } - - @Specialization - public RubyString chr(int n) { - // TODO(CS): not sure about encoding here - return getContext().makeString((char) n); - } - - } - - @CoreMethod(names = "inspect", maxArgs = 0) - public abstract static class InpsectNode extends CoreMethodNode { - - public InpsectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InpsectNode(InpsectNode prev) { - super(prev); - } - - @Specialization - public RubyString inspect(int n) { - return getContext().makeString(Integer.toString(n)); - } - - } - - @CoreMethod(names = "nonzero?", maxArgs = 0) - public abstract static class NonZeroNode extends CoreMethodNode { - - public NonZeroNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NonZeroNode(NonZeroNode prev) { - super(prev); - } - - @Specialization - public Object nonZero(int value) { - if (value == 0) { - return false; - } else { - return value; - } - } - - } - - @CoreMethod(names = "size", needsSelf = false, maxArgs = 0) - public abstract static class SizeNode extends CoreMethodNode { - - public SizeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SizeNode(SizeNode prev) { - super(prev); - } - - @Specialization - public int size() { - return Integer.SIZE / Byte.SIZE; - } - - } - - @CoreMethod(names = "step", needsBlock = true, minArgs = 2, maxArgs = 2) - public abstract static class StepNode extends YieldingCoreMethodNode { - - public StepNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public StepNode(StepNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder step(VirtualFrame frame, int from, int to, int step, RubyProc block) { - for (int i = from; i <= to; i += step) { - yield(frame, block, i); - } - - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "times", needsBlock = true, maxArgs = 0) - public abstract static class TimesNode extends YieldingCoreMethodNode { - - private final BranchProfile breakProfile = new BranchProfile(); - private final BranchProfile nextProfile = new BranchProfile(); - private final BranchProfile redoProfile = new BranchProfile(); - - public TimesNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public TimesNode(TimesNode prev) { - super(prev); - } - - @Specialization - public Object times(VirtualFrame frame, int n, RubyProc block) { - outer: for (int i = 0; i < n; i++) { - while (true) { - try { - yield(frame, block, i); - continue outer; - } catch (BreakException e) { - breakProfile.enter(); - return e.getResult(); - } catch (NextException e) { - nextProfile.enter(); - continue outer; - } catch (RedoException e) { - redoProfile.enter(); - } - } - } - - return n; - } - - } - - @CoreMethod(names = {"to_i", "to_int"}, maxArgs = 0) - public abstract static class ToINode extends CoreMethodNode { - - public ToINode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToINode(ToINode prev) { - super(prev); - } - - @Specialization - public int toI(int n) { - return n; - } - - } - - @CoreMethod(names = "to_f", maxArgs = 0) - public abstract static class ToFNode extends CoreMethodNode { - - public ToFNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToFNode(ToFNode prev) { - super(prev); - } - - @Specialization - public double toF(int n) { - return n; - } - - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS(int n) { - return getContext().makeString(Integer.toString(n)); - } - - } - - @CoreMethod(names = "upto", needsBlock = true, minArgs = 1, maxArgs = 1) - public abstract static class UpToNode extends YieldingCoreMethodNode { - - private final BranchProfile breakProfile = new BranchProfile(); - private final BranchProfile nextProfile = new BranchProfile(); - private final BranchProfile redoProfile = new BranchProfile(); - - public UpToNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public UpToNode(UpToNode prev) { - super(prev); - } - - @Specialization - public Object upto(VirtualFrame frame, int from, int to, RubyProc block) { - outer: for (int i = from; i <= to; i++) { - while (true) { - try { - yield(frame, block, i); - continue outer; - } catch (BreakException e) { - breakProfile.enter(); - return e.getResult(); - } catch (NextException e) { - nextProfile.enter(); - continue outer; - } catch (RedoException e) { - redoProfile.enter(); - } - } - } - - return NilPlaceholder.INSTANCE; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FloatNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FloatNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,493 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -@CoreClass(name = "Float") -public abstract class FloatNodes { - - @CoreMethod(names = "+@", maxArgs = 0) - public abstract static class PosNode extends CoreMethodNode { - - public PosNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PosNode(PosNode prev) { - super(prev); - } - - @Specialization - public double pos(double value) { - return value; - } - - } - - @CoreMethod(names = "-@", maxArgs = 0) - public abstract static class NegNode extends CoreMethodNode { - - public NegNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NegNode(NegNode prev) { - super(prev); - } - - @Specialization - public double neg(double value) { - return -value; - } - - } - - @CoreMethod(names = "+", minArgs = 1, maxArgs = 1) - public abstract static class AddNode extends CoreMethodNode { - - public AddNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AddNode(AddNode prev) { - super(prev); - } - - @Specialization - public double add(double a, int b) { - return a + b; - } - - @Specialization - public double add(double a, double b) { - return a + b; - } - - @Specialization - public double add(double a, BigInteger b) { - return a + b.doubleValue(); - } - - } - - @CoreMethod(names = "-", minArgs = 1, maxArgs = 1) - public abstract static class SubNode extends CoreMethodNode { - - public SubNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SubNode(SubNode prev) { - super(prev); - } - - @Specialization - public double sub(double a, int b) { - return a - b; - } - - @Specialization - public double sub(double a, double b) { - return a - b; - } - - @Specialization - public double sub(double a, BigInteger b) { - return a - b.doubleValue(); - } - - } - - @CoreMethod(names = "*", minArgs = 1, maxArgs = 1) - public abstract static class MulNode extends CoreMethodNode { - - public MulNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MulNode(MulNode prev) { - super(prev); - } - - @Specialization - public double mul(double a, int b) { - return a * b; - } - - @Specialization - public double mul(double a, double b) { - return a * b; - } - - @Specialization - public double mul(double a, BigInteger b) { - return a * b.doubleValue(); - } - - } - - @CoreMethod(names = "**", minArgs = 1, maxArgs = 1) - public abstract static class PowNode extends CoreMethodNode { - - public PowNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PowNode(PowNode prev) { - super(prev); - } - - @Specialization - public double mul(double a, int b) { - return Math.pow(a, b); - } - - @Specialization - public double mul(double a, double b) { - return Math.pow(a, b); - } - - @Specialization - public double mul(double a, BigInteger b) { - return Math.pow(a, b.doubleValue()); - } - - } - - @CoreMethod(names = "/", minArgs = 1, maxArgs = 1) - public abstract static class DivNode extends CoreMethodNode { - - public DivNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DivNode(DivNode prev) { - super(prev); - } - - @Specialization - public double div(double a, int b) { - return a / b; - } - - @Specialization - public double div(double a, double b) { - return a / b; - } - - @Specialization - public double div(double a, BigInteger b) { - return a / b.doubleValue(); - } - - } - - @CoreMethod(names = "%", minArgs = 1, maxArgs = 1) - public abstract static class ModNode extends CoreMethodNode { - - public ModNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ModNode(ModNode prev) { - super(prev); - } - - @Specialization - public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") int b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") double b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") BigInteger b) { - throw new UnsupportedOperationException(); - } - - } - - @CoreMethod(names = "divmod", minArgs = 1, maxArgs = 1) - public abstract static class DivModNode extends CoreMethodNode { - - public DivModNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DivModNode(DivModNode prev) { - super(prev); - } - - @Specialization - public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") int b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") double b) { - throw new UnsupportedOperationException(); - } - - @Specialization - public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") BigInteger b) { - throw new UnsupportedOperationException(); - } - - } - - @CoreMethod(names = "<", minArgs = 1, maxArgs = 1) - public abstract static class LessNode extends CoreMethodNode { - - public LessNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessNode(LessNode prev) { - super(prev); - } - - @Specialization - public boolean less(double a, int b) { - return a < b; - } - - @Specialization - public boolean less(double a, double b) { - return a < b; - } - - @Specialization - public boolean less(double a, BigInteger b) { - return BigInteger.valueOf((long) a).compareTo(b) < 0; - } - } - - @CoreMethod(names = "<=", minArgs = 1, maxArgs = 1) - public abstract static class LessEqualNode extends CoreMethodNode { - - public LessEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LessEqualNode(LessEqualNode prev) { - super(prev); - } - - @Specialization - public boolean lessEqual(double a, int b) { - return a <= b; - } - - @Specialization - public boolean lessEqual(double a, double b) { - return a <= b; - } - - @Specialization - public boolean lessEqual(double a, BigInteger b) { - return BigInteger.valueOf((long) a).compareTo(b) <= 0; - } - } - - @CoreMethod(names = "==", minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(double a, int b) { - return a == b; - } - - @Specialization - public boolean equal(double a, double b) { - return a == b; - } - - @Specialization - public boolean equal(double a, BigInteger b) { - return BigInteger.valueOf((long) a).compareTo(b) == 0; - } - } - - @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1) - public abstract static class NotEqualNode extends CoreMethodNode { - - public NotEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotEqualNode(NotEqualNode prev) { - super(prev); - } - - @Specialization - public boolean notEqual(double a, int b) { - return a != b; - } - - @Specialization - public boolean notEqual(double a, double b) { - return a != b; - } - - @Specialization - public boolean notEqual(double a, BigInteger b) { - return BigInteger.valueOf((long) a).compareTo(b) != 0; - } - } - - @CoreMethod(names = ">=", minArgs = 1, maxArgs = 1) - public abstract static class GreaterEqualNode extends CoreMethodNode { - - public GreaterEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterEqualNode(GreaterEqualNode prev) { - super(prev); - } - - @Specialization - public boolean greaterEqual(double a, int b) { - return a >= b; - } - - @Specialization - public boolean greaterEqual(double a, double b) { - return a >= b; - } - - @Specialization - public boolean greaterEqual(double a, BigInteger b) { - return BigInteger.valueOf((long) a).compareTo(b) >= 0; - } - } - - @CoreMethod(names = ">", minArgs = 1, maxArgs = 1) - public abstract static class GreaterNode extends CoreMethodNode { - - public GreaterNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GreaterNode(GreaterNode prev) { - super(prev); - } - - @Specialization - public boolean equal(double a, int b) { - return a > b; - } - - @Specialization - public boolean equal(double a, double b) { - return a > b; - } - - @Specialization - public boolean equal(double a, BigInteger b) { - return BigInteger.valueOf((long) a).compareTo(b) > 0; - } - } - - @CoreMethod(names = "abs", maxArgs = 0) - public abstract static class AbsNode extends CoreMethodNode { - - public AbsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AbsNode(AbsNode prev) { - super(prev); - } - - @Specialization - public double abs(double n) { - return Math.abs(n); - } - - } - - @CoreMethod(names = "inspect", maxArgs = 0) - public abstract static class InpsectNode extends CoreMethodNode { - - public InpsectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InpsectNode(InpsectNode prev) { - super(prev); - } - - @Specialization - public RubyString inspect(double n) { - return getContext().makeString(Double.toString(n)); - } - - } - - @CoreMethod(names = "nonzero?", maxArgs = 0) - public abstract static class NonZeroNode extends CoreMethodNode { - - public NonZeroNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NonZeroNode(NonZeroNode prev) { - super(prev); - } - - @Specialization - public Object nonZero(double value) { - if (value == 0) { - return false; - } else { - return value; - } - } - - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS(double value) { - return getContext().makeString(Double.toString(value)); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -@CoreClass(name = "Hash") -public abstract class HashNodes { - - @CoreMethod(names = "[]", isModuleMethod = true, needsSelf = false, isSplatted = true) - public abstract static class ConstructNode extends CoreMethodNode { - - public ConstructNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ConstructNode(ConstructNode prev) { - super(prev); - } - - @Specialization - public RubyHash construct(Object[] args) { - final RubyHash hash = new RubyHash(getContext().getCoreLibrary().getHashClass()); - - if (args.length == 1) { - final RubyArray array = (RubyArray) args[0]; - - for (int n = 0; n < array.size(); n++) { - final RubyArray keyValue = (RubyArray) array.get(n); - hash.put(keyValue.get(0), keyValue.get(1)); - } - } else { - if (args.length % 2 != 0) { - // TODO(CS): figure out what error to throw here - throw new UnsupportedOperationException(); - } - - for (int n = 0; n < args.length; n += 2) { - hash.put(args[n], args[n + 1]); - } - } - - return hash; - } - - } - - @CoreMethod(names = "[]", minArgs = 1, maxArgs = 1) - public abstract static class GetIndexNode extends CoreMethodNode { - - public GetIndexNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GetIndexNode(GetIndexNode prev) { - super(prev); - } - - @Specialization - public Object construct(VirtualFrame frame, RubyHash hash, Object index) { - final Object value = hash.get(index); - - if (value == null) { - if (hash.defaultBlock == null) { - return NilPlaceholder.INSTANCE; - } else { - return hash.defaultBlock.call(frame.pack(), hash, index); - } - } else { - return value; - } - } - - } - - @CoreMethod(names = "[]=", minArgs = 2, maxArgs = 2) - public abstract static class SetIndexNode extends CoreMethodNode { - - public SetIndexNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SetIndexNode(SetIndexNode prev) { - super(prev); - } - - @Specialization - public Object construct(RubyHash hash, Object index, Object value) { - hash.put(index, value); - return value; - } - - } - - @CoreMethod(names = "delete", minArgs = 1, maxArgs = 1) - public abstract static class DeleteNode extends CoreMethodNode { - - public DeleteNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DeleteNode(DeleteNode prev) { - super(prev); - } - - @Specialization - public Object delete(RubyHash hash, Object index) { - hash.checkFrozen(); - - final Object value = hash.getMap().remove(index); - - if (value == null) { - return NilPlaceholder.INSTANCE; - } else { - return value; - } - } - - } - - @CoreMethod(names = "each", needsBlock = true, maxArgs = 0) - public abstract static class EachNode extends YieldingCoreMethodNode { - - public EachNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EachNode(EachNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder each(VirtualFrame frame, RubyHash hash, RubyProc block) { - for (Map.Entry entry : hash.storage.entrySet()) { - yield(frame, block, entry.getKey(), entry.getValue()); - } - - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "empty?", maxArgs = 0) - public abstract static class EmptyNode extends CoreMethodNode { - - public EmptyNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EmptyNode(EmptyNode prev) { - super(prev); - } - - @Specialization - public boolean empty(RubyHash hash) { - return hash.storage.isEmpty(); - } - - } - - @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0) - public abstract static class InitializeNode extends CoreMethodNode { - - public InitializeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitializeNode(InitializeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initialize(RubyHash hash, @SuppressWarnings("unused") UndefinedPlaceholder block) { - hash.initialize(null); - return NilPlaceholder.INSTANCE; - } - - @Specialization - public NilPlaceholder initialize(RubyHash hash, RubyProc block) { - hash.initialize(block); - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = {"map", "collect"}, needsBlock = true, maxArgs = 0) - public abstract static class MapNode extends YieldingCoreMethodNode { - - public MapNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MapNode(MapNode prev) { - super(prev); - } - - @Specialization - public RubyArray map(VirtualFrame frame, RubyHash hash, RubyProc block) { - final RubyArray result = new RubyArray(getContext().getCoreLibrary().getArrayClass()); - - for (Map.Entry entry : hash.storage.entrySet()) { - result.push(yield(frame, block, entry.getKey(), entry.getValue())); - } - - return result; - } - - } - - @CoreMethod(names = "key?", minArgs = 1, maxArgs = 1) - public abstract static class KeyNode extends CoreMethodNode { - - public KeyNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public KeyNode(KeyNode prev) { - super(prev); - } - - @Specialization - public boolean key(RubyHash hash, Object key) { - return hash.storage.containsKey(key); - } - - } - - @CoreMethod(names = "keys", maxArgs = 0) - public abstract static class KeysNode extends CoreMethodNode { - - public KeysNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public KeysNode(KeysNode prev) { - super(prev); - } - - @Specialization - public RubyArray keys(RubyHash hash) { - final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass()); - - for (Object key : hash.storage.keySet()) { - array.push(key); - } - - return array; - } - - } - - @CoreMethod(names = "size", maxArgs = 0) - public abstract static class SizeNode extends CoreMethodNode { - - public SizeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SizeNode(SizeNode prev) { - super(prev); - } - - @Specialization - public int size(RubyHash hash) { - return hash.storage.size(); - } - - } - - @CoreMethod(names = "values", maxArgs = 0) - public abstract static class ValuesNode extends CoreMethodNode { - - public ValuesNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ValuesNode(ValuesNode prev) { - super(prev); - } - - @Specialization - public RubyArray values(RubyHash hash) { - final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass()); - - for (Object value : hash.storage.values()) { - array.push(value); - } - - return array; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/InterpolatedStringNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/InterpolatedStringNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A list of expressions to build up into a string. - */ -@NodeInfo(shortName = "interpolated-string") -public final class InterpolatedStringNode extends RubyNode { - - @CompilationFinal private int expectedLength = 64; - - @Children protected final RubyNode[] children; - - public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, RubyNode[] children) { - super(context, sourceSection); - this.children = adoptChildren(children); - } - - @ExplodeLoop - @Override - public Object execute(VirtualFrame frame) { - final StringBuilder builder = new StringBuilder(expectedLength); - - for (int n = 0; n < children.length; n++) { - builder.append(children[n].execute(frame).toString()); - } - - if (builder.length() > expectedLength) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - expectedLength = builder.length() * 2; - } - - return getContext().makeString(builder.toString()); - } - - @ExplodeLoop - @Override - public void executeVoid(VirtualFrame frame) { - for (int n = 0; n < children.length; n++) { - children[n].executeVoid(frame); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/KernelNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/KernelNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,797 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.io.*; -import java.math.*; -import java.util.*; - -import com.oracle.truffle.api.CompilerDirectives.SlowPath; -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.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.nodes.cast.*; -import com.oracle.truffle.ruby.nodes.control.*; -import com.oracle.truffle.ruby.nodes.literal.*; -import com.oracle.truffle.ruby.nodes.yield.*; -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.core.array.*; -import com.oracle.truffle.ruby.runtime.objects.*; -import com.oracle.truffle.ruby.runtime.subsystems.*; - -@CoreClass(name = "Kernel") -public abstract class KernelNodes { - - @CoreMethod(names = "Array", isModuleMethod = true, needsSelf = false, isSplatted = true) - public abstract static class ArrayNode extends CoreMethodNode { - - public ArrayNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ArrayNode(ArrayNode prev) { - super(prev); - } - - @Specialization - public RubyArray array(Object[] args) { - if (args.length == 1 && args[0] instanceof RubyArray) { - return (RubyArray) args[0]; - } else { - return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), args); - } - } - - } - - @CoreMethod(names = "at_exit", isModuleMethod = true, needsSelf = false, needsBlock = true, maxArgs = 0) - public abstract static class AtExitNode extends CoreMethodNode { - - public AtExitNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AtExitNode(AtExitNode prev) { - super(prev); - } - - @Specialization - public Object atExit(RubyProc block) { - getContext().getAtExitManager().add(block); - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "binding", isModuleMethod = true, needsSelf = true, maxArgs = 0) - public abstract static class BindingNode extends CoreMethodNode { - - public BindingNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BindingNode(BindingNode prev) { - super(prev); - } - - @Specialization - public Object binding(VirtualFrame frame, Object self) { - return new RubyBinding(getContext().getCoreLibrary().getBindingClass(), self, frame.getCaller().unpack().materialize()); - } - } - - @CoreMethod(names = "block_given?", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class BlockGivenNode extends CoreMethodNode { - - public BlockGivenNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BlockGivenNode(BlockGivenNode prev) { - super(prev); - } - - @Specialization - public boolean blockGiven(VirtualFrame frame) { - return frame.getCaller().unpack().getArguments(RubyArguments.class).getBlock() != null; - } - } - - // TODO(CS): should hide this in a feature - - @CoreMethod(names = "callcc", isModuleMethod = true, needsSelf = false, needsBlock = true, maxArgs = 0) - public abstract static class CallccNode extends CoreMethodNode { - - public CallccNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CallccNode(CallccNode prev) { - super(prev); - } - - @Specialization - public Object callcc(RubyProc block) { - final RubyContext context = getContext(); - - if (block == null) { - // TODO(CS): should really have acceptsBlock and needsBlock to do this automatically - throw new RaiseException(context.getCoreLibrary().localJumpError("no block given")); - } - - final RubyContinuation continuation = new RubyContinuation(context.getCoreLibrary().getContinuationClass()); - return continuation.enter(block); - } - } - - @CoreMethod(names = "catch", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 1, maxArgs = 1) - public abstract static class CatchNode extends YieldingCoreMethodNode { - - public CatchNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CatchNode(CatchNode prev) { - super(prev); - } - - @Specialization - public Object doCatch(VirtualFrame frame, Object tag, RubyProc block) { - try { - return yield(frame, block); - } catch (ThrowException e) { - if (e.getTag().equals(tag)) { - // TODO(cs): unset rather than set to Nil? - getContext().getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", NilPlaceholder.INSTANCE); - return e.getValue(); - } else { - throw e; - } - } - } - } - - @CoreMethod(names = "eval", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2) - public abstract static class EvalNode extends CoreMethodNode { - - public EvalNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EvalNode(EvalNode prev) { - super(prev); - } - - @Specialization - public Object eval(RubyString source, @SuppressWarnings("unused") UndefinedPlaceholder binding) { - return getContext().eval(source.toString()); - } - - @Specialization - public Object eval(RubyString source, RubyBinding binding) { - return getContext().eval(source.toString(), binding); - } - - } - - @CoreMethod(names = "exec", isModuleMethod = true, needsSelf = false, minArgs = 1, isSplatted = true) - public abstract static class ExecNode extends CoreMethodNode { - - public ExecNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExecNode(ExecNode prev) { - super(prev); - } - - @Specialization - public Object require(Object[] args) { - final String[] commandLine = new String[args.length]; - - for (int n = 0; n < args.length; n++) { - commandLine[n] = args[n].toString(); - } - - exec(getContext(), commandLine); - - return null; - } - - @SlowPath - private static void exec(RubyContext context, String[] commandLine) { - context.implementationMessage("starting child process to simulate exec: "); - - for (int n = 0; n < commandLine.length; n++) { - if (n > 0) { - System.err.print(" "); - } - - System.err.print(commandLine[n]); - } - - final ProcessBuilder builder = new ProcessBuilder(commandLine); - builder.inheritIO(); - - final RubyHash env = (RubyHash) context.getCoreLibrary().getObjectClass().lookupConstant("ENV"); - - for (Map.Entry entry : env.getMap().entrySet()) { - builder.environment().put(entry.getKey().toString(), entry.getValue().toString()); - } - - Process process; - - try { - process = builder.start(); - } catch (IOException e) { - // TODO(cs): proper Ruby exception - throw new RuntimeException(e); - } - - int exitCode; - - while (true) { - try { - exitCode = process.waitFor(); - break; - } catch (InterruptedException e) { - continue; - } - } - - context.implementationMessage("child process simulating exec finished"); - - System.exit(exitCode); - } - - } - - @CoreMethod(names = "exit", isModuleMethod = true, needsSelf = false, minArgs = 0, maxArgs = 1) - public abstract static class ExitNode extends CoreMethodNode { - - public ExitNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExitNode(ExitNode prev) { - super(prev); - } - - @Specialization - public Object exit(@SuppressWarnings("unused") UndefinedPlaceholder exitCode) { - getContext().shutdown(); - System.exit(0); - return null; - } - - @Specialization - public Object exit(int exitCode) { - getContext().shutdown(); - System.exit(exitCode); - return null; - } - - } - - @CoreMethod(names = "gets", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class GetsNode extends CoreMethodNode { - - public GetsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GetsNode(GetsNode prev) { - super(prev); - } - - @Specialization - public RubyString gets(VirtualFrame frame) { - final RubyContext context = getContext(); - - final ThreadManager threadManager = context.getThreadManager(); - - RubyString line; - - try { - final RubyThread runningThread = threadManager.leaveGlobalLock(); - - try { - line = context.makeString(context.getConfiguration().getInputReader().readLine("")); - } finally { - threadManager.enterGlobalLock(runningThread); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - - // Set the local variable $_ in the caller - - final Frame unpacked = frame.getCaller().unpack(); - final FrameSlot slot = unpacked.getFrameDescriptor().findFrameSlot("$_"); - - if (slot != null) { - unpacked.setObject(slot, line); - } - - return line; - } - } - - @CoreMethod(names = "Integer", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class IntegerNode extends CoreMethodNode { - - @Child protected DispatchHeadNode toInt; - - public IntegerNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - toInt = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_int", false)); - } - - public IntegerNode(IntegerNode prev) { - super(prev); - toInt = adoptChild(prev.toInt); - } - - @Specialization - public int integer(int value) { - return value; - } - - @Specialization - public BigInteger integer(BigInteger value) { - return value; - } - - @Specialization - public int integer(double value) { - return (int) value; - } - - @Specialization - public Object integer(RubyString value) { - return value.toInteger(); - } - - @Specialization - public Object integer(VirtualFrame frame, Object value) { - return toInt.dispatch(frame, value, null); - } - - } - - @CoreMethod(names = "lambda", isModuleMethod = true, needsBlock = true, maxArgs = 0) - public abstract static class LambdaNode extends CoreMethodNode { - - public LambdaNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LambdaNode(LambdaNode prev) { - super(prev); - } - - @Specialization - public RubyProc proc(Object self, RubyProc block) { - return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA, self, block, block.getMethod()); - - } - } - - @CoreMethod(names = "load", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class LoadNode extends CoreMethodNode { - - public LoadNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LoadNode(LoadNode prev) { - super(prev); - } - - @Specialization - public boolean load(RubyString file) { - getContext().loadFile(file.toString()); - return true; - } - } - - @CoreMethod(names = "loop", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class LoopNode extends CoreMethodNode { - - @Child protected WhileNode whileNode; - - public LoopNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - whileNode = adoptChild(new WhileNode(context, sourceSection, BooleanCastNodeFactory.create(context, sourceSection, new BooleanLiteralNode(context, sourceSection, true)), new YieldNode( - context, getSourceSection(), new RubyNode[]{}))); - } - - public LoopNode(LoopNode prev) { - super(prev); - whileNode = adoptChild(prev.whileNode); - } - - @Specialization - public Object loop(VirtualFrame frame) { - return whileNode.execute(frame); - } - } - - @CoreMethod(names = "print", isModuleMethod = true, needsSelf = false, isSplatted = true) - public abstract static class PrintNode extends CoreMethodNode { - - public PrintNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PrintNode(PrintNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder print(Object[] args) { - final RubyContext context = getContext(); - final ThreadManager threadManager = context.getThreadManager(); - - final RubyThread runningThread = threadManager.leaveGlobalLock(); - - try { - for (Object arg : args) { - /* - * TODO(cs): If it's a RubyString and made up of bytes, just write the bytes out - * - using toString will mess up the encoding. We need to stop using toString - * everywhere, and write our own bytes, possibly using JRuby's library for this. - */ - - if (arg instanceof RubyString && !((RubyString) arg).isFromJavaString()) { - try { - context.getConfiguration().getStandardOut().write(((RubyString) arg).getBytes()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } else { - context.getConfiguration().getStandardOut().print(arg); - } - } - } finally { - threadManager.enterGlobalLock(runningThread); - } - - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "printf", isModuleMethod = true, needsSelf = false, isSplatted = true) - public abstract static class PrintfNode extends CoreMethodNode { - - public PrintfNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PrintfNode(PrintfNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder printf(Object[] args) { - final RubyContext context = getContext(); - final ThreadManager threadManager = context.getThreadManager(); - - if (args.length > 0) { - final String format = ((RubyString) args[0]).toString(); - final List values = Arrays.asList(args).subList(1, args.length); - - final RubyThread runningThread = threadManager.leaveGlobalLock(); - - try { - StringFormatter.format(context.getConfiguration().getStandardOut(), format, values); - } finally { - threadManager.enterGlobalLock(runningThread); - } - } - - return NilPlaceholder.INSTANCE; - } - } - - /* - * Kernel#pretty_inspect is normally part of stdlib, in pp.rb, but we aren't able to execute - * that file yet. Instead we implement a very simple version here, which is the solution - * suggested by RubySpec. - */ - - @CoreMethod(names = "pretty_inspect", maxArgs = 0) - public abstract static class PrettyInspectNode extends CoreMethodNode { - - @Child protected DispatchHeadNode toS; - - public PrettyInspectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - toS = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_s", false)); - } - - public PrettyInspectNode(PrettyInspectNode prev) { - super(prev); - toS = adoptChild(prev.toS); - } - - @Specialization - public Object prettyInspect(VirtualFrame frame, Object self) { - return toS.dispatch(frame, self, null); - - } - } - - @CoreMethod(names = "proc", isModuleMethod = true, needsBlock = true, maxArgs = 0) - public abstract static class ProcNode extends CoreMethodNode { - - public ProcNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ProcNode(ProcNode prev) { - super(prev); - } - - @Specialization - public RubyProc proc(Object self, RubyProc block) { - return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC, self, block, block.getMethod()); - - } - } - - @CoreMethod(names = "puts", isModuleMethod = true, needsSelf = false, isSplatted = true) - public abstract static class PutsNode extends CoreMethodNode { - - public PutsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PutsNode(PutsNode prev) { - super(prev); - } - - @ExplodeLoop - @Specialization - public NilPlaceholder puts(Object[] args) { - final RubyContext context = getContext(); - final ThreadManager threadManager = context.getThreadManager(); - final PrintStream standardOut = context.getConfiguration().getStandardOut(); - - final RubyThread runningThread = threadManager.leaveGlobalLock(); - - try { - if (args.length == 0) { - standardOut.println(); - } else { - for (int n = 0; n < args.length; n++) { - puts(context, standardOut, args[n]); - } - } - } finally { - threadManager.enterGlobalLock(runningThread); - } - - return NilPlaceholder.INSTANCE; - } - - @SlowPath - private void puts(RubyContext context, PrintStream standardOut, Object value) { - if (value instanceof RubyArray) { - final RubyArray array = (RubyArray) value; - - for (int n = 0; n < array.size(); n++) { - puts(context, standardOut, array.get(n)); - } - } else { - // TODO(CS): slow path send - standardOut.println(context.getCoreLibrary().box(value).send("to_s", null)); - } - } - - } - - @CoreMethod(names = "raise", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2) - public abstract static class RaiseNode extends CoreMethodNode { - - @Child protected DispatchHeadNode initialize; - - public RaiseNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - initialize = adoptChild(new DispatchHeadNode(context, getSourceSection(), "initialize", false)); - } - - public RaiseNode(RaiseNode prev) { - super(prev); - initialize = adoptChild(prev.initialize); - } - - @Specialization(order = 1) - public Object raise(VirtualFrame frame, RubyString message, @SuppressWarnings("unused") UndefinedPlaceholder undefined) { - return raise(frame, getContext().getCoreLibrary().getRuntimeErrorClass(), message); - } - - @Specialization(order = 2) - public Object raise(VirtualFrame frame, RubyClass exceptionClass, @SuppressWarnings("unused") UndefinedPlaceholder undefined) { - return raise(frame, exceptionClass, getContext().makeString("")); - } - - @Specialization(order = 3) - public Object raise(VirtualFrame frame, RubyClass exceptionClass, RubyString message) { - final RubyBasicObject exception = exceptionClass.newInstance(); - initialize.dispatch(frame, exception, null, message); - throw new RaiseException(exception); - } - - } - - @CoreMethod(names = "require", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class RequireNode extends CoreMethodNode { - - public RequireNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RequireNode(RequireNode prev) { - super(prev); - } - - @Specialization - public boolean require(RubyString feature) { - try { - getContext().getFeatureManager().require(feature.toString()); - } catch (IOException e) { - throw new RuntimeException(e); - } - - return true; - } - } - - @CoreMethod(names = "set_trace_func", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class SetTraceFuncNode extends CoreMethodNode { - - public SetTraceFuncNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SetTraceFuncNode(SetTraceFuncNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder setTraceFunc(NilPlaceholder proc) { - getContext().getTraceManager().setTraceProc(null); - return proc; - } - - @Specialization - public RubyProc setTraceFunc(RubyProc proc) { - getContext().getTraceManager().setTraceProc(proc); - return proc; - } - - } - - @CoreMethod(names = "String", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class StringNode extends CoreMethodNode { - - @Child protected DispatchHeadNode toS; - - public StringNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - toS = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_s", false)); - } - - public StringNode(StringNode prev) { - super(prev); - toS = adoptChild(prev.toS); - } - - @Specialization - public RubyString string(int value) { - return getContext().makeString(Integer.toString(value)); - } - - @Specialization - public RubyString string(BigInteger value) { - return getContext().makeString(value.toString()); - } - - @Specialization - public RubyString string(double value) { - return getContext().makeString(Double.toString(value)); - } - - @Specialization - public RubyString string(RubyString value) { - return value; - } - - @Specialization - public Object string(VirtualFrame frame, Object value) { - return toS.dispatch(frame, value, null); - } - - } - - @CoreMethod(names = "sleep", isModuleMethod = true, needsSelf = false, maxArgs = 1) - public abstract static class SleepNode extends CoreMethodNode { - - public SleepNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SleepNode(SleepNode prev) { - super(prev); - } - - @Specialization - public double sleep(double duration) { - final RubyContext context = getContext(); - - final RubyThread runningThread = context.getThreadManager().leaveGlobalLock(); - - try { - final long start = System.nanoTime(); - - try { - Thread.sleep((long) (duration * 1000)); - } catch (InterruptedException e) { - // Ignore interruption - } - - final long end = System.nanoTime(); - - return (end - start) / 1e9; - } finally { - context.getThreadManager().enterGlobalLock(runningThread); - } - } - - @Specialization - public double sleep(int duration) { - return sleep((double) duration); - } - - } - - @CoreMethod(names = "throw", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2) - public abstract static class ThrowNode extends CoreMethodNode { - - public ThrowNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ThrowNode(ThrowNode prev) { - super(prev); - } - - @Specialization - public Object doThrow(Object tag, UndefinedPlaceholder value) { - return doThrow(tag, (Object) value); - } - - @Specialization - public Object doThrow(Object tag, Object value) { - if (value instanceof UndefinedPlaceholder) { - throw new ThrowException(tag, NilPlaceholder.INSTANCE); - } else { - throw new ThrowException(tag, value); - } - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MainNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MainNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "main") -public abstract class MainNodes { - - @CoreMethod(names = "include", isSplatted = true, minArgs = 1) - public abstract static class IncludeNode extends CoreMethodNode { - - public IncludeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public IncludeNode(IncludeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder include(RubyObject main, Object[] args) { - // TODO(cs): copied from Module - but where does this method really come from? - - // Note that we traverse the arguments backwards - - for (int n = args.length - 1; n >= 0; n--) { - if (args[n] instanceof RubyModule) { - final RubyModule included = (RubyModule) args[n]; - - // Note that we do appear to do full method lookup here - included.getLookupNode().lookupMethod("append_features").call(null, included, null, main.getSingletonClass()); - - // TODO(cs): call included hook - } - } - - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS() { - return getContext().makeString("main"); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MatchDataNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MatchDataNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -@CoreClass(name = "MatchData") -public abstract class MatchDataNodes { - - @CoreMethod(names = "[]", minArgs = 1, maxArgs = 1) - public abstract static class GetIndexNode extends CoreMethodNode { - - public GetIndexNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GetIndexNode(GetIndexNode prev) { - super(prev); - } - - @Specialization - public Object getIndex(RubyMatchData matchData, int index) { - return matchData.getValues()[index]; - } - - } - - @CoreMethod(names = "to_a", maxArgs = 0) - public abstract static class ToANode extends CoreMethodNode { - - public ToANode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToANode(ToANode prev) { - super(prev); - } - - @Specialization - public RubyArray toA(RubyMatchData matchData) { - return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), matchData.getValues()); - } - - } - - @CoreMethod(names = "values_at", isSplatted = true) - public abstract static class ValuesAtNode extends CoreMethodNode { - - public ValuesAtNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ValuesAtNode(ValuesAtNode prev) { - super(prev); - } - - @Specialization - public RubyArray valuesAt(RubyMatchData matchData, Object[] args) { - final int[] indicies = new int[args.length]; - - for (int n = 0; n < args.length; n++) { - indicies[n] = (int) args[n]; - } - - return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), matchData.valuesAt(indicies)); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MathNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MathNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; - -@CoreClass(name = "Math") -public abstract class MathNodes { - - @CoreMethod(names = "sqrt", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class SqrtNode extends CoreMethodNode { - - public SqrtNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SqrtNode(SqrtNode prev) { - super(prev); - } - - @Specialization - public double sqrt(int a) { - return Math.sqrt(a); - } - - @Specialization - public double sqrt(BigInteger a) { - return Math.sqrt(a.doubleValue()); - } - - @Specialization - public double sqrt(double a) { - return Math.sqrt(a); - } - - } - - @CoreMethod(names = "exp", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class ExpNode extends CoreMethodNode { - - public ExpNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExpNode(ExpNode prev) { - super(prev); - } - - @Specialization - public double exp(int a) { - return Math.exp(a); - } - - @Specialization - public double exp(BigInteger a) { - return Math.exp(a.doubleValue()); - } - - @Specialization - public double exp(double a) { - return Math.exp(a); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ModuleNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ModuleNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,652 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -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.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.control.*; -import com.oracle.truffle.ruby.nodes.methods.arguments.*; -import com.oracle.truffle.ruby.nodes.objects.*; -import com.oracle.truffle.ruby.nodes.objects.instancevariables.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.RubyParser.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -@CoreClass(name = "Module") -public abstract class ModuleNodes { - - @CoreMethod(names = "alias_method", minArgs = 2, maxArgs = 2) - public abstract static class AliasMethodNode extends CoreMethodNode { - - public AliasMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AliasMethodNode(AliasMethodNode prev) { - super(prev); - } - - @Specialization - public RubyModule aliasMethod(RubyModule module, RubySymbol newName, RubySymbol oldName) { - module.alias(newName.toString(), oldName.toString()); - return module; - } - } - - @CoreMethod(names = "append_features", minArgs = 1, maxArgs = 1) - public abstract static class AppendFeaturesNode extends CoreMethodNode { - - public AppendFeaturesNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AppendFeaturesNode(AppendFeaturesNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder appendFeatures(RubyModule module, RubyModule other) { - module.appendFeatures(other); - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "attr_reader", isSplatted = true, appendCallNode = true) - public abstract static class AttrReaderNode extends CoreMethodNode { - - public AttrReaderNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AttrReaderNode(AttrReaderNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder attrReader(RubyModule module, Object[] args) { - final Node callSite = (Node) args[args.length - 1]; - final SourceSection sourceSection = callSite.getSourceSection(); - - for (int n = 0; n < args.length - 1; n++) { - attrReader(getContext(), sourceSection, module, args[n].toString()); - } - - return NilPlaceholder.INSTANCE; - } - - public static void attrReader(RubyContext context, SourceSection sourceSection, RubyModule module, String name) { - CompilerDirectives.transferToInterpreter(); - - final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, Arity.NO_ARGS); - - final SelfNode self = new SelfNode(context, sourceSection); - final UninitializedReadInstanceVariableNode readInstanceVariable = new UninitializedReadInstanceVariableNode(context, sourceSection, name, self); - - final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, readInstanceVariable); - - final RubyRootNode pristineRoot = new RubyRootNode(sourceSection, null, name + "(attr_reader)", block); - final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRoot)); - final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRoot, true, false); - final RubyMethod method = new RubyMethod(sourceSection, module, new UniqueMethodIdentifier(), null, name, Visibility.PUBLIC, false, methodImplementation); - - module.addMethod(method); - } - } - - @CoreMethod(names = "attr_writer", isSplatted = true, appendCallNode = true) - public abstract static class AttrWriterNode extends CoreMethodNode { - - public AttrWriterNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AttrWriterNode(AttrWriterNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder attrWriter(RubyModule module, Object[] args) { - final Node callSite = (Node) args[args.length - 1]; - final SourceSection sourceSection = callSite.getSourceSection(); - - for (int n = 0; n < args.length - 1; n++) { - attrWriter(getContext(), sourceSection, module, args[n].toString()); - } - - return NilPlaceholder.INSTANCE; - } - - public static void attrWriter(RubyContext context, SourceSection sourceSection, RubyModule module, String name) { - CompilerDirectives.transferToInterpreter(); - - final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, Arity.ONE_ARG); - - final SelfNode self = new SelfNode(context, sourceSection); - final ReadPreArgumentNode readArgument = new ReadPreArgumentNode(context, sourceSection, 0, false); - final UninitializedWriteInstanceVariableNode writeInstanceVariable = new UninitializedWriteInstanceVariableNode(context, sourceSection, name, self, readArgument); - - final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, writeInstanceVariable); - - final RubyRootNode pristineRoot = new RubyRootNode(sourceSection, null, name + "(attr_writer)", block); - final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRoot)); - final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRoot, true, false); - final RubyMethod method = new RubyMethod(sourceSection, module, new UniqueMethodIdentifier(), null, name + "=", Visibility.PUBLIC, false, methodImplementation); - - module.addMethod(method); - } - } - - @CoreMethod(names = {"attr_accessor", "attr"}, isSplatted = true, appendCallNode = true) - public abstract static class AttrAccessorNode extends CoreMethodNode { - - public AttrAccessorNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AttrAccessorNode(AttrAccessorNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder attrAccessor(RubyModule module, Object[] args) { - final Node callSite = (Node) args[args.length - 1]; - final SourceSection sourceSection = callSite.getSourceSection(); - - for (int n = 0; n < args.length - 1; n++) { - attrAccessor(getContext(), sourceSection, module, args[n].toString()); - } - - return NilPlaceholder.INSTANCE; - } - - public static void attrAccessor(RubyContext context, SourceSection sourceSection, RubyModule module, String name) { - CompilerDirectives.transferToInterpreter(); - AttrReaderNode.attrReader(context, sourceSection, module, name); - AttrWriterNode.attrWriter(context, sourceSection, module, name); - } - - } - - @CoreMethod(names = "class_eval", minArgs = 1, maxArgs = 3) - public abstract static class ClassEvalNode extends CoreMethodNode { - - public ClassEvalNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ClassEvalNode(ClassEvalNode prev) { - super(prev); - } - - @Specialization - public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, @SuppressWarnings("unused") UndefinedPlaceholder file, @SuppressWarnings("unused") UndefinedPlaceholder line) { - final Source source = getContext().getSourceManager().get("(eval)", code.toString()); - return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize()); - } - - @Specialization - public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") UndefinedPlaceholder line) { - final Source source = getContext().getSourceManager().get(file.toString(), code.toString()); - return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize()); - } - - @Specialization - public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") int line) { - final Source source = getContext().getSourceManager().get(file.toString(), code.toString()); - return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize()); - } - - } - - @CoreMethod(names = "class_variable_defined?", maxArgs = 0) - public abstract static class ClassVariableDefinedNode extends CoreMethodNode { - - public ClassVariableDefinedNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ClassVariableDefinedNode(ClassVariableDefinedNode prev) { - super(prev); - } - - @Specialization - public boolean isClassVariableDefined(RubyModule module, RubyString name) { - return module.lookupClassVariable(name.toString()) != null; - } - - @Specialization - public boolean isClassVariableDefined(RubyModule module, RubySymbol name) { - return module.lookupClassVariable(name.toString()) != null; - } - - } - - @CoreMethod(names = "constants", maxArgs = 0) - public abstract static class ConstantsNode extends CoreMethodNode { - - public ConstantsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ConstantsNode(ConstantsNode prev) { - super(prev); - } - - @Specialization - public RubyArray constants(@SuppressWarnings("unused") RubyModule module) { - getContext().implementationMessage("Module#constants returns an empty array"); - return new RubyArray(getContext().getCoreLibrary().getArrayClass()); - } - } - - @CoreMethod(names = "const_defined?", minArgs = 1, maxArgs = 2) - public abstract static class ConstDefinedNode extends CoreMethodNode { - - public ConstDefinedNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ConstDefinedNode(ConstDefinedNode prev) { - super(prev); - } - - @Specialization(order = 1) - public boolean isConstDefined(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) { - return module.lookupConstant(name.toString()) != null; - } - - @Specialization(order = 2) - public boolean isConstDefined(RubyModule module, RubyString name, boolean inherit) { - if (inherit) { - return module.lookupConstant(name.toString()) != null; - } else { - return module.getConstants().containsKey(name.toString()); - } - } - - @Specialization(order = 3) - public boolean isConstDefined(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) { - return module.lookupConstant(name.toString()) != null; - } - - public boolean isConstDefined(RubyModule module, RubySymbol name, boolean inherit) { - if (inherit) { - return module.lookupConstant(name.toString()) != null; - } else { - return module.getConstants().containsKey(name.toString()); - } - } - - } - - @CoreMethod(names = "define_method", needsBlock = true, minArgs = 1, maxArgs = 2) - public abstract static class DefineMethodNode extends CoreMethodNode { - - public DefineMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DefineMethodNode(DefineMethodNode prev) { - super(prev); - } - - @Specialization(order = 1) - public RubyMethod defineMethod(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder proc, RubyProc block) { - final RubyMethod method = block.getMethod(); - module.addMethod(method.withNewName(name.toString())); - return method; - } - - @Specialization(order = 2) - public RubyMethod defineMethod(RubyModule module, RubyString name, RubyProc proc, @SuppressWarnings("unused") UndefinedPlaceholder block) { - final RubyMethod method = proc.getMethod(); - module.addMethod(method.withNewName(name.toString())); - return method; - } - - @Specialization(order = 3) - public RubyMethod defineMethod(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder proc, RubyProc block) { - final RubyMethod method = block.getMethod(); - module.addMethod(method.withNewName(name.toString())); - return method; - } - - @Specialization(order = 4) - public RubyMethod defineMethod(RubyModule module, RubySymbol name, RubyProc proc, @SuppressWarnings("unused") UndefinedPlaceholder block) { - final RubyMethod method = proc.getMethod(); - module.addMethod(method.withNewName(name.toString())); - return method; - } - - } - - @CoreMethod(names = "include", isSplatted = true, minArgs = 1) - public abstract static class IncludeNode extends CoreMethodNode { - - public IncludeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public IncludeNode(IncludeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder include(RubyModule module, Object[] args) { - // Note that we traverse the arguments backwards - - for (int n = args.length - 1; n >= 0; n--) { - if (args[n] instanceof RubyModule) { - final RubyModule included = (RubyModule) args[n]; - - // Note that we do appear to do full method lookup here - included.getLookupNode().lookupMethod("append_features").call(null, included, null, module); - - // TODO(cs): call included hook - } - } - - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "method_defined?", minArgs = 1, maxArgs = 2) - public abstract static class MethodDefinedNode extends CoreMethodNode { - - public MethodDefinedNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MethodDefinedNode(MethodDefinedNode prev) { - super(prev); - } - - @Specialization(order = 1) - public boolean isMethodDefined(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) { - return module.lookupMethod(name.toString()) != null; - } - - @Specialization(order = 2) - public boolean isMethodDefined(RubyModule module, RubyString name, boolean inherit) { - if (inherit) { - return module.lookupMethod(name.toString()) != null; - } else { - return module.getMethods().containsKey(name.toString()); - } - } - - @Specialization(order = 3) - public boolean isMethodDefined(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) { - return module.lookupMethod(name.toString()) != null; - } - - public boolean isMethodDefined(RubyModule module, RubySymbol name, boolean inherit) { - if (inherit) { - return module.lookupMethod(name.toString()) != null; - } else { - return module.getMethods().containsKey(name.toString()); - } - } - } - - @CoreMethod(names = "module_eval", minArgs = 1, maxArgs = 3) - public abstract static class ModuleEvalNode extends CoreMethodNode { - - public ModuleEvalNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ModuleEvalNode(ModuleEvalNode prev) { - super(prev); - } - - @Specialization - public RubyModule moduleEval(RubyModule module, RubyString code, @SuppressWarnings("unused") Object file, @SuppressWarnings("unused") Object line) { - module.moduleEval(code.toString()); - return module; - } - } - - @CoreMethod(names = "module_function", isSplatted = true) - public abstract static class ModuleFunctionNode extends CoreMethodNode { - - public ModuleFunctionNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ModuleFunctionNode(ModuleFunctionNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder moduleFunction(VirtualFrame frame, RubyModule module, Object... args) { - if (args.length == 0) { - final Frame unpacked = frame.getCaller().unpack(); - - final FrameSlot slot = unpacked.getFrameDescriptor().findFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID); - - /* - * setObject, even though it's a boolean, so we can getObject and either get the - * default Nil or the boolean value without triggering deoptimization. - */ - - unpacked.setObject(slot, true); - } else { - for (Object argument : args) { - final String methodName = argument.toString(); - module.getSingletonClass().addMethod(module.lookupMethod(methodName)); - } - } - - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "public", isSplatted = true) - public abstract static class PublicNode extends CoreMethodNode { - - public PublicNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PublicNode(PublicNode prev) { - super(prev); - } - - @Specialization - public RubyModule doPublic(VirtualFrame frame, RubyModule module, Object... args) { - module.visibilityMethod(frame.getCaller(), args, Visibility.PUBLIC); - return module; - } - } - - @CoreMethod(names = "private", isSplatted = true) - public abstract static class PrivateNode extends CoreMethodNode { - - public PrivateNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PrivateNode(PrivateNode prev) { - super(prev); - } - - @Specialization - public RubyModule doPrivate(VirtualFrame frame, RubyModule module, Object... args) { - module.visibilityMethod(frame.getCaller(), args, Visibility.PRIVATE); - return module; - } - } - - @CoreMethod(names = "private_class_method", isSplatted = true) - public abstract static class PrivateClassMethodNode extends CoreMethodNode { - - public PrivateClassMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PrivateClassMethodNode(PrivateClassMethodNode prev) { - super(prev); - } - - @Specialization - public RubyModule privateClassMethod(RubyModule module, Object... args) { - final RubyClass moduleSingleton = module.getSingletonClass(); - - for (Object arg : args) { - final RubyMethod method = moduleSingleton.lookupMethod(arg.toString()); - - if (method == null) { - throw new RuntimeException("Couldn't find method " + arg.toString()); - } - - moduleSingleton.addMethod(method.withNewVisibility(Visibility.PRIVATE)); - } - - return module; - } - } - - @CoreMethod(names = "private_constant", isSplatted = true) - public abstract static class PrivateConstantNode extends CoreMethodNode { - - public PrivateConstantNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PrivateConstantNode(PrivateConstantNode prev) { - super(prev); - } - - @Specialization - public RubyModule privateConstnat(RubyModule module, @SuppressWarnings("unused") Object... args) { - getContext().implementationMessage("private_constant does nothing at the moment"); - return module; - } - } - - @CoreMethod(names = "protected", isSplatted = true) - public abstract static class ProtectedNode extends CoreMethodNode { - - public ProtectedNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ProtectedNode(ProtectedNode prev) { - super(prev); - } - - @Specialization - public RubyModule doProtected(RubyModule module, @SuppressWarnings("unused") Object... args) { - getContext().implementationMessage("protected does nothing at the moment"); - return module; - } - } - - @CoreMethod(names = "remove_class_variable", minArgs = 1, maxArgs = 1) - public abstract static class RemoveClassVariableNode extends CoreMethodNode { - - public RemoveClassVariableNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RemoveClassVariableNode(RemoveClassVariableNode prev) { - super(prev); - } - - @Specialization - public RubyModule removeClassVariable(RubyModule module, RubyString name) { - module.removeClassVariable(name.toString()); - return module; - } - - @Specialization - public RubyModule removeClassVariable(RubyModule module, RubySymbol name) { - module.removeClassVariable(name.toString()); - return module; - } - - } - - @CoreMethod(names = "remove_method", minArgs = 1, maxArgs = 1) - public abstract static class RemoveMethodNode extends CoreMethodNode { - - public RemoveMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RemoveMethodNode(RemoveMethodNode prev) { - super(prev); - } - - @Specialization - public RubyModule removeMethod(RubyModule module, RubyString name) { - module.removeMethod(name.toString()); - return module; - } - - @Specialization - public RubyModule removeMethod(RubyModule module, RubySymbol name) { - module.removeMethod(name.toString()); - return module; - } - - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS(RubyModule module) { - return getContext().makeString(module.getName()); - } - } - - @CoreMethod(names = "undef_method", minArgs = 1, maxArgs = 1) - public abstract static class UndefMethodNode extends CoreMethodNode { - - public UndefMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public UndefMethodNode(UndefMethodNode prev) { - super(prev); - } - - @Specialization - public RubyModule undefMethod(RubyModule module, RubyString name) { - final RubyMethod method = module.lookupMethod(name.toString()); - module.undefMethod(method); - return module; - } - - @Specialization - public RubyModule undefMethod(RubyModule module, RubySymbol name) { - final RubyMethod method = module.lookupMethod(name.toString()); - module.undefMethod(method); - return module; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/NilClassNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/NilClassNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "NilClass") -public abstract class NilClassNodes { - - @CoreMethod(names = "!", needsSelf = false, maxArgs = 0) - public abstract static class NotNode extends CoreMethodNode { - - public NotNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotNode(NotNode prev) { - super(prev); - } - - @Specialization - public boolean not() { - return true; - } - } - - @CoreMethod(names = "==", needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(Object b) { - return b instanceof NilPlaceholder || b instanceof RubyNilClass; - } - - } - - @CoreMethod(names = "!=", needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class NotEqualNode extends CoreMethodNode { - - public NotEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotEqualNode(NotEqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(Object b) { - return !(b instanceof NilPlaceholder || b instanceof RubyNilClass); - } - - } - - @CoreMethod(names = "inspect", needsSelf = false, maxArgs = 0) - public abstract static class InpsectNode extends CoreMethodNode { - - public InpsectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InpsectNode(InpsectNode prev) { - super(prev); - } - - @Specialization - public RubyString inspect() { - return getContext().makeString("nil"); - } - } - - @CoreMethod(names = "nil?", needsSelf = false, maxArgs = 0) - public abstract static class NilNode extends CoreMethodNode { - - public NilNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NilNode(NilNode prev) { - super(prev); - } - - @Specialization - public boolean nil() { - return true; - } - } - - @CoreMethod(names = "to_i", needsSelf = false, maxArgs = 0) - public abstract static class ToINode extends CoreMethodNode { - - public ToINode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToINode(ToINode prev) { - super(prev); - } - - @Specialization - public int toI() { - return 0; - } - } - - @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS() { - return getContext().makeString(""); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,514 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -@CoreClass(name = "Object") -public abstract class ObjectNodes { - - @CoreMethod(names = "class", maxArgs = 0) - public abstract static class ClassNode extends CoreMethodNode { - - public ClassNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ClassNode(ClassNode prev) { - super(prev); - } - - @Specialization - public RubyClass getClass(boolean value) { - if (value) { - return getContext().getCoreLibrary().getTrueClass(); - } else { - return getContext().getCoreLibrary().getFalseClass(); - } - } - - @Specialization - public RubyClass getClass(@SuppressWarnings("unused") int value) { - return getContext().getCoreLibrary().getFixnumClass(); - } - - @Specialization - public RubyClass getClass(@SuppressWarnings("unused") BigInteger value) { - return getContext().getCoreLibrary().getBignumClass(); - } - - @Specialization - public RubyClass getClass(@SuppressWarnings("unused") double value) { - return getContext().getCoreLibrary().getFloatClass(); - } - - @Specialization - public RubyClass getClass(RubyBasicObject self) { - return self.getRubyClass(); - } - - } - - @CoreMethod(names = "dup", maxArgs = 0) - public abstract static class DupNode extends CoreMethodNode { - - public DupNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DupNode(DupNode prev) { - super(prev); - } - - @Specialization - public Object dup(RubyObject self) { - return self.dup(); - } - - } - - @CoreMethod(names = "extend", isSplatted = true, minArgs = 1) - public abstract static class ExtendNode extends CoreMethodNode { - - public ExtendNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExtendNode(ExtendNode prev) { - super(prev); - } - - @Specialization - public RubyBasicObject extend(RubyBasicObject self, Object[] args) { - for (int n = 0; n < args.length; n++) { - self.extend((RubyModule) args[n]); - } - - return self; - } - - } - - @CoreMethod(names = "freeze", maxArgs = 0) - public abstract static class FreezeNode extends CoreMethodNode { - - public FreezeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FreezeNode(FreezeNode prev) { - super(prev); - } - - @Specialization - public RubyObject freeze(RubyObject self) { - self.frozen = true; - return self; - } - - } - - @CoreMethod(names = "frozen?", maxArgs = 0) - public abstract static class FrozenNode extends CoreMethodNode { - - public FrozenNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FrozenNode(FrozenNode prev) { - super(prev); - } - - @Specialization - public boolean isFrozen(RubyObject self) { - return self.frozen; - } - - } - - @CoreMethod(names = "inspect", maxArgs = 0) - public abstract static class InspectNode extends CoreMethodNode { - - public InspectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InspectNode(InspectNode prev) { - super(prev); - } - - @Specialization - public RubyString inspect(boolean value) { - return getContext().makeString(Boolean.toString(value)); - } - - @Specialization - public RubyString inspect(int value) { - return getContext().makeString(Integer.toString(value)); - } - - @Specialization - public RubyString inspect(BigInteger value) { - return getContext().makeString(value.toString()); - } - - @Specialization - public RubyString inspect(double value) { - return getContext().makeString(Double.toString(value)); - } - - @Specialization - public RubyString inspect(RubyObject self) { - return getContext().makeString(self.inspect()); - } - - } - - @CoreMethod(names = "instance_eval", needsBlock = true, maxArgs = 0) - public abstract static class InstanceEvalNode extends CoreMethodNode { - - public InstanceEvalNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InstanceEvalNode(InstanceEvalNode prev) { - super(prev); - } - - @Specialization - public Object instanceEval(VirtualFrame frame, RubyObject self, RubyProc block) { - return block.callWithModifiedSelf(frame.pack(), self); - } - - } - - @CoreMethod(names = "instance_variable_defined?", minArgs = 1, maxArgs = 1) - public abstract static class InstanceVariableDefinedNode extends CoreMethodNode { - - public InstanceVariableDefinedNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InstanceVariableDefinedNode(InstanceVariableDefinedNode prev) { - super(prev); - } - - @Specialization - public boolean isInstanceVariableDefined(RubyBasicObject object, RubyString name) { - return object.isInstanceVariableDefined(RubyObject.checkInstanceVariableName(getContext(), name.toString())); - } - - @Specialization - public boolean isInstanceVariableDefined(RubyBasicObject object, RubySymbol name) { - return object.isInstanceVariableDefined(RubyObject.checkInstanceVariableName(getContext(), name.toString())); - } - - } - - @CoreMethod(names = "instance_variable_get", minArgs = 1, maxArgs = 1) - public abstract static class InstanceVariableGetNode extends CoreMethodNode { - - public InstanceVariableGetNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InstanceVariableGetNode(InstanceVariableGetNode prev) { - super(prev); - } - - @Specialization - public Object isInstanceVariableGet(RubyBasicObject object, RubyString name) { - return object.getInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString())); - } - - @Specialization - public Object isInstanceVariableGet(RubyBasicObject object, RubySymbol name) { - return object.getInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString())); - } - - } - - @CoreMethod(names = "instance_variable_set", minArgs = 2, maxArgs = 2) - public abstract static class InstanceVariableSetNode extends CoreMethodNode { - - public InstanceVariableSetNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InstanceVariableSetNode(InstanceVariableSetNode prev) { - super(prev); - } - - @Specialization - public Object isInstanceVariableSet(RubyBasicObject object, RubyString name, Object value) { - object.setInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString()), value); - return value; - } - - @Specialization - public Object isInstanceVariableSet(RubyBasicObject object, RubySymbol name, Object value) { - object.setInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString()), value); - return value; - } - - } - - @CoreMethod(names = "instance_variables", maxArgs = 0) - public abstract static class InstanceVariablesNode extends CoreMethodNode { - - public InstanceVariablesNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InstanceVariablesNode(InstanceVariablesNode prev) { - super(prev); - } - - @Specialization - public RubyArray instanceVariables(RubyObject self) { - final String[] instanceVariableNames = self.getInstanceVariableNames(); - - Arrays.sort(instanceVariableNames); - - final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass()); - - for (String name : instanceVariableNames) { - array.push(new RubyString(getContext().getCoreLibrary().getStringClass(), name)); - } - - return array; - } - - } - - @CoreMethod(names = {"is_a?", "instance_of?", "kind_of?"}, minArgs = 1, maxArgs = 1) - public abstract static class IsANode extends CoreMethodNode { - - public IsANode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public IsANode(IsANode prev) { - super(prev); - } - - @Specialization - public boolean isA(@SuppressWarnings("unused") RubyObject self, @SuppressWarnings("unused") NilPlaceholder nil) { - return false; - } - - @Specialization - public boolean isA(RubyObject self, RubyClass rubyClass) { - return self.getRubyClass().assignableTo(rubyClass); - } - - } - - @CoreMethod(names = "methods", minArgs = 0, maxArgs = 1) - public abstract static class MethodsNode extends CoreMethodNode { - - public MethodsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MethodsNode(MethodsNode prev) { - super(prev); - } - - @Specialization - public RubyArray methods(RubyObject self, boolean includeInherited) { - if (!includeInherited) { - self.getRubyClass().getContext().implementationMessage("Object#methods always returns inherited methods at the moment"); - } - - return methods(self, UndefinedPlaceholder.INSTANCE); - } - - @Specialization - public RubyArray methods(RubyObject self, @SuppressWarnings("unused") UndefinedPlaceholder includeInherited) { - final RubyArray array = new RubyArray(self.getRubyClass().getContext().getCoreLibrary().getArrayClass()); - - final Map methods = new HashMap<>(); - - self.getLookupNode().getMethods(methods); - - for (RubyMethod method : methods.values()) { - if (method.getVisibility() == Visibility.PUBLIC || method.getVisibility() == Visibility.PROTECTED) { - array.push(new RubySymbol(self.getRubyClass().getContext().getCoreLibrary().getSymbolClass(), method.getName())); - } - } - - return array; - } - - } - - @CoreMethod(names = "nil?", needsSelf = false, maxArgs = 0) - public abstract static class NilNode extends CoreMethodNode { - - public NilNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NilNode(NilNode prev) { - super(prev); - } - - @Specialization - public boolean nil() { - return false; - } - } - - @CoreMethod(names = "object_id", needsSelf = true, maxArgs = 0) - public abstract static class ObjectIDNode extends CoreMethodNode { - - public ObjectIDNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ObjectIDNode(ObjectIDNode prev) { - super(prev); - } - - @Specialization - public Object objectID(RubyBasicObject object) { - return GeneralConversions.fixnumOrBignum(object.getObjectID()); - } - - } - - @CoreMethod(names = "respond_to?", minArgs = 1, maxArgs = 2) - public abstract static class RespondToNode extends CoreMethodNode { - - public RespondToNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RespondToNode(RespondToNode prev) { - super(prev); - } - - @Specialization(order = 1) - public boolean doesRespondTo(Object object, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder checkVisibility) { - return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), false); - } - - @Specialization(order = 2) - public boolean doesRespondTo(Object object, RubyString name, boolean dontCheckVisibility) { - return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), dontCheckVisibility); - } - - @Specialization(order = 3) - public boolean doesRespondTo(Object object, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder checkVisibility) { - return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), false); - } - - @Specialization(order = 4) - public boolean doesRespondTo(Object object, RubySymbol name, boolean dontCheckVisibility) { - return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), dontCheckVisibility); - } - - private static boolean doesRespondTo(RubyBasicObject object, String name, boolean dontCheckVisibility) { - final RubyMethod method = object.getLookupNode().lookupMethod(name); - - if (method == null || method.isUndefined()) { - return false; - } - - if (dontCheckVisibility) { - return true; - } else { - return method.getVisibility() == Visibility.PUBLIC; - } - } - - } - - @CoreMethod(names = "singleton_class", maxArgs = 0) - public abstract static class SingletonClassNode extends CoreMethodNode { - - public SingletonClassNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SingletonClassNode(SingletonClassNode prev) { - super(prev); - } - - @Specialization - public RubyClass singletonClass(RubyBasicObject self) { - return self.getSingletonClass(); - } - - } - - @CoreMethod(names = "singleton_methods", minArgs = 0, maxArgs = 1) - public abstract static class SingletonMethodsNode extends CoreMethodNode { - - public SingletonMethodsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SingletonMethodsNode(SingletonMethodsNode prev) { - super(prev); - } - - @Specialization - public RubyArray singletonMethods(RubyObject self, boolean includeInherited) { - if (!includeInherited) { - self.getRubyClass().getContext().implementationMessage("Object#singleton_methods always returns inherited methods at the moment"); - } - - return singletonMethods(self, UndefinedPlaceholder.INSTANCE); - } - - @Specialization - public RubyArray singletonMethods(RubyObject self, @SuppressWarnings("unused") UndefinedPlaceholder includeInherited) { - final RubyArray array = new RubyArray(self.getRubyClass().getContext().getCoreLibrary().getArrayClass()); - - for (RubyMethod method : self.getSingletonClass().getDeclaredMethods()) { - array.push(new RubySymbol(self.getRubyClass().getContext().getCoreLibrary().getSymbolClass(), method.getName())); - } - - return array; - } - - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS(RubyObject self) { - return getContext().makeString(self.toString()); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectSpaceNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectSpaceNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -@CoreClass(name = "ObjectSpace") -public abstract class ObjectSpaceNodes { - - @CoreMethod(names = "_id2ref", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class ID2RefNode extends CoreMethodNode { - - public ID2RefNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ID2RefNode(ID2RefNode prev) { - super(prev); - } - - @Specialization - public Object id2Ref(int id) { - final Object object = getContext().getObjectSpaceManager().lookupId(id); - - if (object == null) { - return NilPlaceholder.INSTANCE; - } else { - return object; - } - } - - @Specialization - public Object id2Ref(BigInteger id) { - final Object object = getContext().getObjectSpaceManager().lookupId(id.longValue()); - - if (object == null) { - return NilPlaceholder.INSTANCE; - } else { - return object; - } - } - - } - - @CoreMethod(names = "each_object", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 0, maxArgs = 1) - public abstract static class EachObjectNode extends YieldingCoreMethodNode { - - public EachObjectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EachObjectNode(EachObjectNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder eachObject(VirtualFrame frame, @SuppressWarnings("unused") UndefinedPlaceholder ofClass, RubyProc block) { - for (RubyBasicObject object : getContext().getObjectSpaceManager().getObjects()) { - yield(frame, block, object); - } - return NilPlaceholder.INSTANCE; - } - - @Specialization - public NilPlaceholder eachObject(VirtualFrame frame, RubyClass ofClass, RubyProc block) { - for (RubyBasicObject object : getContext().getObjectSpaceManager().getObjects()) { - if (object.getRubyClass().assignableTo(ofClass)) { - yield(frame, block, object); - } - } - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "define_finalizer", isModuleMethod = true, needsSelf = false, minArgs = 2, maxArgs = 2) - public abstract static class DefineFinalizerNode extends CoreMethodNode { - - public DefineFinalizerNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DefineFinalizerNode(DefineFinalizerNode prev) { - super(prev); - } - - @Specialization - public RubyProc defineFinalizer(Object object, RubyProc finalizer) { - getContext().getObjectSpaceManager().defineFinalizer((RubyBasicObject) object, finalizer); - return finalizer; - } - } - - @CoreMethod(names = {"garbage_collect", "start"}, isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class GarbageCollectNode extends CoreMethodNode { - - public GarbageCollectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GarbageCollectNode(GarbageCollectNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder garbageCollect() { - final RubyThread runningThread = getContext().getThreadManager().leaveGlobalLock(); - - try { - System.gc(); - } finally { - getContext().getThreadManager().enterGlobalLock(runningThread); - } - - return NilPlaceholder.INSTANCE; - } - } - - @CoreMethod(names = "undefine_finalizer", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class UndefineFinalizerNode extends CoreMethodNode { - - public UndefineFinalizerNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public UndefineFinalizerNode(UndefineFinalizerNode prev) { - super(prev); - } - - @Specialization - public Object undefineFinalizer(Object object) { - getContext().getObjectSpaceManager().undefineFinalizer((RubyBasicObject) object); - return object; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Proc") -public abstract class ProcNodes { - - @CoreMethod(names = {"call", "[]"}, isSplatted = true) - public abstract static class CallNode extends CoreMethodNode { - - public CallNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CallNode(CallNode prev) { - super(prev); - } - - @Specialization - public Object call(VirtualFrame frame, RubyProc proc, Object[] args) { - return proc.call(frame.getCaller(), args); - } - - } - - @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0) - public abstract static class InitializeNode extends CoreMethodNode { - - public InitializeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitializeNode(InitializeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initialize(VirtualFrame frame, RubyProc proc, RubyProc block) { - final RubyArguments callerArguments = frame.getCaller().unpack().getArguments(RubyArguments.class); - proc.initialize(RubyProc.Type.PROC, callerArguments.getSelf(), callerArguments.getBlock(), block.getMethod()); - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "lambda?", maxArgs = 0) - public abstract static class LambdaNode extends CoreMethodNode { - - public LambdaNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LambdaNode(LambdaNode prev) { - super(prev); - } - - @Specialization - public boolean lambda(RubyProc proc) { - return proc.getType() == RubyProc.Type.LAMBDA; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcessNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcessNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; - -@CoreClass(name = "Process") -public abstract class ProcessNodes { - - @CoreMethod(names = "pid", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class PidNode extends CoreMethodNode { - - public PidNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public PidNode(PidNode prev) { - super(prev); - } - - @Specialization - public int pid() { - return getContext().getPOSIX().getpid(); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.call.*; -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.core.array.*; -import com.oracle.truffle.ruby.runtime.core.range.*; - -@CoreClass(name = "Range") -public abstract class RangeNodes { - - @CoreMethod(names = {"collect", "map"}, needsBlock = true, maxArgs = 0) - public abstract static class CollectNode extends YieldingCoreMethodNode { - - public CollectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CollectNode(CollectNode prev) { - super(prev); - } - - @Specialization - public RubyArray collect(VirtualFrame frame, FixnumRange range, RubyProc block) { - final RubyContext context = getContext(); - - final RubyArray array = new RubyArray(context.getCoreLibrary().getArrayClass()); - - for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) { - array.push(yield(frame, block, n)); - } - - return array; - } - - } - - @CoreMethod(names = "each", needsBlock = true, maxArgs = 0) - public abstract static class EachNode extends YieldingCoreMethodNode { - - private final BranchProfile breakProfile = new BranchProfile(); - private final BranchProfile nextProfile = new BranchProfile(); - private final BranchProfile redoProfile = new BranchProfile(); - - public EachNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EachNode(EachNode prev) { - super(prev); - } - - @Specialization - public Object each(VirtualFrame frame, FixnumRange range, RubyProc block) { - outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) { - while (true) { - try { - yield(frame, block, n); - continue outer; - } catch (BreakException e) { - breakProfile.enter(); - return e.getResult(); - } catch (NextException e) { - nextProfile.enter(); - continue outer; - } catch (RedoException e) { - redoProfile.enter(); - } - } - } - - return range; - } - - } - - @CoreMethod(names = "exclude_end?", maxArgs = 0) - public abstract static class ExcludeEndNode extends CoreMethodNode { - - public ExcludeEndNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ExcludeEndNode(ExcludeEndNode prev) { - super(prev); - } - - @Specialization - public boolean excludeEnd(RubyRange range) { - return range.doesExcludeEnd(); - } - - } - - @CoreMethod(names = "first", maxArgs = 0) - public abstract static class FirstNode extends CoreMethodNode { - - public FirstNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FirstNode(FirstNode prev) { - super(prev); - } - - @Specialization - public int each(FixnumRange range) { - return range.getBegin(); - } - - @Specialization - public Object each(ObjectRange range) { - return range.getBegin(); - } - - } - - @CoreMethod(names = "include?", maxArgs = 1) - public abstract static class IncludeNode extends CoreMethodNode { - - @Child protected DispatchHeadNode callLess; - @Child protected DispatchHeadNode callGreater; - @Child protected DispatchHeadNode callGreaterEqual; - - public IncludeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - callLess = adoptChild(new DispatchHeadNode(context, getSourceSection(), "<", false)); - callGreater = adoptChild(new DispatchHeadNode(context, getSourceSection(), ">", false)); - callGreaterEqual = adoptChild(new DispatchHeadNode(context, getSourceSection(), ">=", false)); - } - - public IncludeNode(IncludeNode prev) { - super(prev); - callLess = adoptChild(prev.callLess); - callGreater = adoptChild(prev.callGreater); - callGreaterEqual = adoptChild(prev.callGreaterEqual); - } - - @Specialization - public boolean include(FixnumRange range, int value) { - return value >= range.getBegin() && value < range.getExclusiveEnd(); - } - - @Specialization - public boolean include(VirtualFrame frame, ObjectRange range, Object value) { - if ((boolean) callLess.dispatch(frame, value, null, range.getBegin())) { - return false; - } - - if (range.doesExcludeEnd()) { - if ((boolean) callGreaterEqual.dispatch(frame, value, null, range.getEnd())) { - return false; - } - } else { - if ((boolean) callGreater.dispatch(frame, value, null, range.getEnd())) { - return false; - } - } - - return true; - } - } - - @CoreMethod(names = "last", maxArgs = 0) - public abstract static class LastNode extends CoreMethodNode { - - public LastNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LastNode(LastNode prev) { - super(prev); - } - - @Specialization - public int last(FixnumRange range) { - return range.getEnd(); - } - - @Specialization - public Object last(ObjectRange range) { - return range.getEnd(); - } - - } - - @CoreMethod(names = "step", needsBlock = true, minArgs = 1, maxArgs = 1) - public abstract static class StepNode extends YieldingCoreMethodNode { - - private final BranchProfile breakProfile = new BranchProfile(); - private final BranchProfile nextProfile = new BranchProfile(); - private final BranchProfile redoProfile = new BranchProfile(); - - public StepNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public StepNode(StepNode prev) { - super(prev); - } - - @Specialization - public Object step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) { - outer: for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) { - while (true) { - try { - yield(frame, block, n); - continue outer; - } catch (BreakException e) { - breakProfile.enter(); - return e.getResult(); - } catch (NextException e) { - nextProfile.enter(); - continue outer; - } catch (RedoException e) { - redoProfile.enter(); - } - } - } - - return range; - } - - } - - @CoreMethod(names = "to_a", maxArgs = 0) - public abstract static class ToANode extends CoreMethodNode { - - public ToANode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToANode(ToANode prev) { - super(prev); - } - - @Specialization - public RubyArray toA(RubyRange range) { - return range.toArray(); - } - - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS(RubyRange range) { - return getContext().makeString(range.toString()); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RegexpNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RegexpNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.regex.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Regexp") -public abstract class RegexpNodes { - - @CoreMethod(names = {"=~", "==="}, minArgs = 1, maxArgs = 1) - public abstract static class MatchOperatorNode extends CoreMethodNode { - - public MatchOperatorNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MatchOperatorNode(MatchOperatorNode prev) { - super(prev); - } - - @Specialization - public Object match(VirtualFrame frame, RubyRegexp regexp, RubyString string) { - return regexp.matchOperator(frame.getCaller().unpack(), string.toString()); - } - - } - - @CoreMethod(names = "!~", minArgs = 1, maxArgs = 1) - public abstract static class NotMatchOperatorNode extends CoreMethodNode { - - public NotMatchOperatorNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotMatchOperatorNode(NotMatchOperatorNode prev) { - super(prev); - } - - @Specialization - public Object match(VirtualFrame frame, RubyRegexp regexp, RubyString string) { - return regexp.matchOperator(frame.getCaller().unpack(), string.toString()) == NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "escape", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class EscapeNode extends CoreMethodNode { - - public EscapeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EscapeNode(EscapeNode prev) { - super(prev); - } - - @Specialization - public RubyString sqrt(RubyString pattern) { - return getContext().makeString(Pattern.quote(pattern.toString())); - } - - } - - @CoreMethod(names = "initialize", minArgs = 1, maxArgs = 1) - public abstract static class InitializeNode extends CoreMethodNode { - - public InitializeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitializeNode(InitializeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initialize(RubyRegexp regexp, RubyString string) { - regexp.initialize(string.toString()); - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "match", minArgs = 1, maxArgs = 1) - public abstract static class MatchNode extends CoreMethodNode { - - public MatchNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MatchNode(MatchNode prev) { - super(prev); - } - - @Specialization - public Object match(RubyRegexp regexp, RubyString string) { - return regexp.match(string.toString()); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SignalNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SignalNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; - -@CoreClass(name = "Signal") -public abstract class SignalNodes { - - @CoreMethod(names = "trap", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class SignalNode extends CoreMethodNode { - - public SignalNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SignalNode(SignalNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder trap(@SuppressWarnings("unused") Object signal) { - getContext().implementationMessage("Signal#trap doesn't do anything"); - return NilPlaceholder.INSTANCE; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,559 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; -import java.util.regex.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -@CoreClass(name = "String") -public abstract class StringNodes { - - @CoreMethod(names = "+", minArgs = 1, maxArgs = 1) - public abstract static class AddNode extends CoreMethodNode { - - public AddNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public AddNode(AddNode prev) { - super(prev); - } - - @Specialization - public RubyString add(RubyString a, RubyString b) { - return new RubyString(a.getRubyClass().getContext().getCoreLibrary().getStringClass(), a.toString() + b.toString()); - } - } - - @CoreMethod(names = {"==", "==="}, minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(@SuppressWarnings("unused") RubyString a, @SuppressWarnings("unused") NilPlaceholder b) { - return false; - } - - @Specialization - public boolean equal(RubyString a, RubyString b) { - return a.toString().equals(b.toString()); - } - } - - @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1) - public abstract static class NotEqualNode extends CoreMethodNode { - - public NotEqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotEqualNode(NotEqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(@SuppressWarnings("unused") RubyString a, @SuppressWarnings("unused") NilPlaceholder b) { - return true; - } - - @Specialization - public boolean notEqual(RubyString a, RubyString b) { - return !a.toString().equals(b.toString()); - } - - } - - @CoreMethod(names = "<=>", minArgs = 1, maxArgs = 1) - public abstract static class CompareNode extends CoreMethodNode { - - public CompareNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public CompareNode(CompareNode prev) { - super(prev); - } - - @Specialization - public int compare(RubyString a, RubyString b) { - return a.toString().compareTo(b.toString()); - } - } - - @CoreMethod(names = "<<", minArgs = 1, maxArgs = 1) - public abstract static class ConcatNode extends CoreMethodNode { - - public ConcatNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ConcatNode(ConcatNode prev) { - super(prev); - } - - @Specialization - public RubyString concat(RubyString string, RubyString other) { - string.replace(string.toString() + other.toString()); - return string; - } - } - - @CoreMethod(names = "%", minArgs = 1, maxArgs = 1, isSplatted = true) - public abstract static class FormatNode extends CoreMethodNode { - - public FormatNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public FormatNode(FormatNode prev) { - super(prev); - } - - @Specialization - public RubyString format(RubyString format, Object[] args) { - final RubyContext context = getContext(); - - if (args.length == 1 && args[0] instanceof RubyArray) { - return context.makeString(StringFormatter.format(format.toString(), ((RubyArray) args[0]).asList())); - } else { - return context.makeString(StringFormatter.format(format.toString(), Arrays.asList(args))); - } - } - } - - @CoreMethod(names = "[]", minArgs = 1, maxArgs = 2, isSplatted = true) - public abstract static class GetIndexNode extends CoreMethodNode { - - public GetIndexNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GetIndexNode(GetIndexNode prev) { - super(prev); - } - - @Specialization - public Object getIndex(RubyString string, Object[] args) { - return RubyString.getIndex(getContext(), string.toString(), args); - } - } - - @CoreMethod(names = "=~", minArgs = 1, maxArgs = 1) - public abstract static class MatchOperatorNode extends CoreMethodNode { - - public MatchOperatorNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MatchOperatorNode(MatchOperatorNode prev) { - super(prev); - } - - @Specialization - public Object match(VirtualFrame frame, RubyString string, RubyRegexp regexp) { - return regexp.matchOperator(frame, string.toString()); - } - } - - @CoreMethod(names = "chomp", maxArgs = 0) - public abstract static class ChompNode extends CoreMethodNode { - - public ChompNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ChompNode(ChompNode prev) { - super(prev); - } - - @Specialization - public RubyString chomp(RubyString string) { - return string.getRubyClass().getContext().makeString(string.toString().trim()); - } - } - - @CoreMethod(names = "chomp!", maxArgs = 0) - public abstract static class ChompBangNode extends CoreMethodNode { - - public ChompBangNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ChompBangNode(ChompBangNode prev) { - super(prev); - } - - @Specialization - public RubyString chompBang(RubyString string) { - string.replace(string.toString().trim()); - return string; - } - } - - @CoreMethod(names = "downcase", maxArgs = 0) - public abstract static class DowncaseNode extends CoreMethodNode { - - public DowncaseNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DowncaseNode(DowncaseNode prev) { - super(prev); - } - - @Specialization - public RubyString downcase(RubyString string) { - return string.getRubyClass().getContext().makeString(string.toString().toLowerCase()); - } - } - - @CoreMethod(names = "downcase!", maxArgs = 0) - public abstract static class DowncaseBangNode extends CoreMethodNode { - - public DowncaseBangNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public DowncaseBangNode(DowncaseBangNode prev) { - super(prev); - } - - @Specialization - public RubyString downcase(RubyString string) { - string.replace(string.toString().toLowerCase()); - return string; - } - } - - @CoreMethod(names = "empty?", maxArgs = 0) - public abstract static class EmptyNode extends CoreMethodNode { - - public EmptyNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EmptyNode(EmptyNode prev) { - super(prev); - } - - @Specialization - public boolean empty(RubyString string) { - return string.toString().isEmpty(); - } - } - - @CoreMethod(names = "end_with?", minArgs = 1, maxArgs = 1) - public abstract static class EndWithNode extends CoreMethodNode { - - public EndWithNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EndWithNode(EndWithNode prev) { - super(prev); - } - - @Specialization - public boolean endWith(RubyString string, RubyString b) { - return string.toString().endsWith(b.toString()); - } - } - - @CoreMethod(names = "gsub", minArgs = 2, maxArgs = 2) - public abstract static class GsubNode extends CoreMethodNode { - - public GsubNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public GsubNode(GsubNode prev) { - super(prev); - } - - @Specialization - public RubyString gsub(RubyString string, RubyString regexpString, RubyString replacement) { - final RubyRegexp regexp = new RubyRegexp(getContext().getCoreLibrary().getRegexpClass(), regexpString.toString()); - return gsub(string, regexp, replacement); - } - - @Specialization - public RubyString gsub(RubyString string, RubyRegexp regexp, RubyString replacement) { - return getContext().makeString(regexp.getPattern().matcher(string.toString()).replaceAll(replacement.toString())); - } - } - - @CoreMethod(names = "inspect", maxArgs = 0) - public abstract static class InspectNode extends CoreMethodNode { - - public InspectNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InspectNode(InspectNode prev) { - super(prev); - } - - @Specialization - public RubyString inspect(RubyString string) { - return getContext().makeString("\"" + string.toString().replace("\\", "\\\\").replace("\"", "\\\"") + "\""); - } - } - - @CoreMethod(names = "ljust", minArgs = 1, maxArgs = 2) - public abstract static class LjustNode extends CoreMethodNode { - - public LjustNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public LjustNode(LjustNode prev) { - super(prev); - } - - @Specialization - public RubyString ljust(RubyString string, int length, @SuppressWarnings("unused") UndefinedPlaceholder padding) { - return getContext().makeString(RubyString.ljust(string.toString(), length, " ")); - } - - @Specialization - public RubyString ljust(RubyString string, int length, RubyString padding) { - return getContext().makeString(RubyString.ljust(string.toString(), length, padding.toString())); - } - - } - - @CoreMethod(names = "size", maxArgs = 0) - public abstract static class SizeNode extends CoreMethodNode { - - public SizeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SizeNode(SizeNode prev) { - super(prev); - } - - @Specialization - public int size(RubyString string) { - return string.toString().length(); - } - } - - @CoreMethod(names = "match", minArgs = 1, maxArgs = 1) - public abstract static class MatchNode extends CoreMethodNode { - - public MatchNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public MatchNode(MatchNode prev) { - super(prev); - } - - @Specialization - public Object match(RubyString string, RubyString regexpString) { - final RubyRegexp regexp = new RubyRegexp(getContext().getCoreLibrary().getRegexpClass(), regexpString.toString()); - return regexp.match(string.toString()); - } - - @Specialization - public Object match(RubyString string, RubyRegexp regexp) { - return regexp.match(string.toString()); - } - } - - @CoreMethod(names = "rjust", minArgs = 1, maxArgs = 2) - public abstract static class RjustNode extends CoreMethodNode { - - public RjustNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RjustNode(RjustNode prev) { - super(prev); - } - - @Specialization - public RubyString rjust(RubyString string, int length, @SuppressWarnings("unused") UndefinedPlaceholder padding) { - return getContext().makeString(RubyString.rjust(string.toString(), length, " ")); - } - - @Specialization - public RubyString rjust(RubyString string, int length, RubyString padding) { - return getContext().makeString(RubyString.rjust(string.toString(), length, padding.toString())); - } - - } - - @CoreMethod(names = "scan", minArgs = 1, maxArgs = 1) - public abstract static class ScanNode extends CoreMethodNode { - - public ScanNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ScanNode(ScanNode prev) { - super(prev); - } - - @Specialization - public RubyArray scan(RubyString string, RubyString regexp) { - return RubyString.scan(getContext(), string.toString(), Pattern.compile(regexp.toString())); - } - - @Specialization - public RubyArray scan(RubyString string, RubyRegexp regexp) { - return RubyString.scan(getContext(), string.toString(), regexp.getPattern()); - } - - } - - @CoreMethod(names = "split", minArgs = 1, maxArgs = 1) - public abstract static class SplitNode extends CoreMethodNode { - - public SplitNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SplitNode(SplitNode prev) { - super(prev); - } - - @Specialization - public RubyArray split(RubyString string, RubyString sep) { - final RubyContext context = getContext(); - - final String[] components = string.toString().split(Pattern.quote(sep.toString())); - - final Object[] objects = new Object[components.length]; - - for (int n = 0; n < objects.length; n++) { - objects[n] = context.makeString(components[n]); - } - - return RubyArray.specializedFromObjects(context.getCoreLibrary().getArrayClass(), objects); - } - - @Specialization - public RubyArray split(RubyString string, RubyRegexp sep) { - final RubyContext context = getContext(); - - final String[] components = string.toString().split(sep.getPattern().pattern()); - - final Object[] objects = new Object[components.length]; - - for (int n = 0; n < objects.length; n++) { - objects[n] = context.makeString(components[n]); - } - - return RubyArray.specializedFromObjects(context.getCoreLibrary().getArrayClass(), objects); - } - } - - @CoreMethod(names = "start_with?", minArgs = 1, maxArgs = 1) - public abstract static class StartWithNode extends CoreMethodNode { - - public StartWithNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public StartWithNode(StartWithNode prev) { - super(prev); - } - - @Specialization - public boolean endWith(RubyString string, RubyString b) { - return string.toString().startsWith(b.toString()); - } - } - - @CoreMethod(names = "to_f", maxArgs = 0) - public abstract static class ToFNode extends CoreMethodNode { - - public ToFNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToFNode(ToFNode prev) { - super(prev); - } - - @Specialization - public double toF(RubyString string) { - return Double.parseDouble(string.toString()); - } - } - - @CoreMethod(names = "to_i", maxArgs = 0) - public abstract static class ToINode extends CoreMethodNode { - - public ToINode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToINode(ToINode prev) { - super(prev); - } - - @Specialization - public Object toI(RubyString string) { - return string.toInteger(); - } - } - - @CoreMethod(names = "to_s", maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toF(RubyString string) { - return string; - } - } - - @CoreMethod(names = {"to_sym", "intern"}, maxArgs = 0) - public abstract static class ToSymNode extends CoreMethodNode { - - public ToSymNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSymNode(ToSymNode prev) { - super(prev); - } - - @Specialization - public RubySymbol toSym(RubyString string) { - return new RubySymbol(getContext().getCoreLibrary().getSymbolClass(), string.toString()); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StructNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StructNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -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.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Struct") -public abstract class StructNodes { - - @CoreMethod(names = "initialize", needsBlock = true, appendCallNode = true, isSplatted = true) - public abstract static class InitalizeNode extends CoreMethodNode { - - public InitalizeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitalizeNode(InitalizeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initialize(VirtualFrame frame, RubyClass struct, Object[] args, Object block, Node callSite) { - CompilerDirectives.transferToInterpreter(); - - final RubySymbol[] symbols = new RubySymbol[args.length]; - - for (int n = 0; n < args.length; n++) { - symbols[n] = (RubySymbol) args[n]; - } - - for (RubySymbol symbol : symbols) { - ModuleNodes.AttrAccessorNode.attrAccessor(getContext(), callSite.getSourceSection(), struct, symbol.toString()); - } - - if (!RubyNilClass.isNil(block)) { - ((RubyProc) block).callWithModifiedSelf(frame.pack(), struct); - } - - return NilPlaceholder.INSTANCE; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SymbolNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SymbolNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Symbol") -public abstract class SymbolNodes { - - @CoreMethod(names = {"==", "==="}, minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(@SuppressWarnings("unused") RubyString a, @SuppressWarnings("unused") NilPlaceholder b) { - return false; - } - - @Specialization - public boolean equal(RubySymbol a, RubySymbol b) { - return a.toString().equals(b.toString()); - } - - @Specialization - public boolean equal(RubySymbol a, RubyString b) { - return a.toString().equals(b.toString()); - } - - @Specialization - public boolean equal(RubySymbol a, int b) { - return a.toString().equals(Integer.toString(b)); - } - - } - - @CoreMethod(names = "empty?", maxArgs = 0) - public abstract static class EmptyNode extends CoreMethodNode { - - public EmptyNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EmptyNode(EmptyNode prev) { - super(prev); - } - - @Specialization - public boolean empty(RubySymbol symbol) { - return symbol.toString().isEmpty(); - } - - } - - @CoreMethod(names = "to_proc", maxArgs = 0) - public abstract static class ToProcNode extends CoreMethodNode { - - public ToProcNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToProcNode(ToProcNode prev) { - super(prev); - } - - @Specialization - public RubyProc toProc(RubySymbol symbol) { - // TODO(CS): this should be doing all kinds of caching - return symbol.toProc(); - } - } - - @CoreMethod(names = "to_sym", maxArgs = 0) - public abstract static class ToSymNode extends CoreMethodNode { - - public ToSymNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSymNode(ToSymNode prev) { - super(prev); - } - - @Specialization - public RubySymbol toSym(RubySymbol symbol) { - return symbol; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SystemNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SystemNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.io.*; - -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.*; - -/** - * Represents an expression that is evaluated by running it as a system command via forking and - * execing, and then taking stdout as a string. - */ -@NodeInfo(shortName = "system") -public class SystemNode extends RubyNode { - - @Child protected RubyNode child; - - public SystemNode(RubyContext context, SourceSection sourceSection, RubyNode child) { - super(context, sourceSection); - this.child = adoptChild(child); - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyContext context = getContext(); - - final String command = child.execute(frame).toString(); - - Process process; - - try { - // We need to run via bash to get the variable and other expansion we expect - process = Runtime.getRuntime().exec(new String[]{"bash", "-c", command}); - } catch (IOException e) { - throw new RuntimeException(e); - } - - final InputStream stdout = process.getInputStream(); - final BufferedReader reader = new BufferedReader(new InputStreamReader(stdout)); - - final StringBuilder resultBuilder = new StringBuilder(); - - String line; - - // TODO(cs): this isn't great for binary output - - try { - while ((line = reader.readLine()) != null) { - resultBuilder.append(line); - resultBuilder.append("\n"); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - - return context.makeString(resultBuilder.toString()); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ThreadNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ThreadNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Thread") -public abstract class ThreadNodes { - - @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0) - public abstract static class InitializeNode extends CoreMethodNode { - - public InitializeNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public InitializeNode(InitializeNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder initialize(RubyThread thread, RubyProc block) { - thread.initialize(block); - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "join", maxArgs = 0) - public abstract static class JoinNode extends CoreMethodNode { - - public JoinNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public JoinNode(JoinNode prev) { - super(prev); - } - - @Specialization - public RubyThread join(RubyThread self) { - self.join(); - return self; - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TimeNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TimeNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "Time") -public abstract class TimeNodes { - - @CoreMethod(names = "-", minArgs = 1, maxArgs = 1) - public abstract static class SubNode extends CoreMethodNode { - - public SubNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public SubNode(SubNode prev) { - super(prev); - } - - @Specialization - public double sub(RubyTime a, RubyTime b) { - return a.subtract(b); - } - - } - - @CoreMethod(names = "now", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class NowNode extends CoreMethodNode { - - public NowNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NowNode(NowNode prev) { - super(prev); - } - - @Specialization - public RubyTime now() { - return RubyTime.fromDate(getContext().getCoreLibrary().getTimeClass(), System.currentTimeMillis()); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TrueClassNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TrueClassNodes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -@CoreClass(name = "TrueClass") -public abstract class TrueClassNodes { - - @CoreMethod(names = "!", needsSelf = false, maxArgs = 0) - public abstract static class NotNode extends CoreMethodNode { - - public NotNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public NotNode(NotNode prev) { - super(prev); - } - - @Specialization - public boolean not() { - return false; - } - - } - - @CoreMethod(names = {"==", "===", "=~"}, needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class EqualNode extends CoreMethodNode { - - public EqualNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EqualNode(EqualNode prev) { - super(prev); - } - - @Specialization - public boolean equal(boolean other) { - return other; - } - - @Specialization - public boolean equal(Object other) { - return other instanceof Boolean && ((boolean) other); - } - - } - - @CoreMethod(names = "^", needsSelf = false, minArgs = 1, maxArgs = 1) - public abstract static class XorNode extends CoreMethodNode { - - public XorNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public XorNode(XorNode prev) { - super(prev); - } - - @Specialization - public boolean xor(boolean other) { - return true ^ other; - } - - } - - @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0) - public abstract static class ToSNode extends CoreMethodNode { - - public ToSNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ToSNode(ToSNode prev) { - super(prev); - } - - @Specialization - public RubyString toS() { - return getContext().makeString("true"); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/YieldingCoreMethodNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/YieldingCoreMethodNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.yield.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -public abstract class YieldingCoreMethodNode extends CoreMethodNode { - - @Child protected YieldDispatchNode dispatchNode; - - public YieldingCoreMethodNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - dispatchNode = adoptChild(new UninitializedYieldDispatchNode(context, getSourceSection())); - } - - public YieldingCoreMethodNode(YieldingCoreMethodNode prev) { - super(prev); - dispatchNode = adoptChild(prev.dispatchNode); - } - - public Object yield(VirtualFrame frame, RubyProc block, Object... arguments) { - return dispatchNode.dispatch(frame, block, arguments); - } - - public boolean yieldBoolean(VirtualFrame frame, RubyProc block, Object... arguments) { - return GeneralConversions.toBoolean(dispatchNode.dispatch(frame, block, arguments)); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/MinimalRubyNodeInstrumenter.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/MinimalRubyNodeInstrumenter.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 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.instrument; - -import com.oracle.truffle.api.nodes.instrument.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.debug.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * Utility for instrumenting Ruby AST nodes to support the language's built-in tracing - * facility. It ignores nodes other than {@linkplain NodePhylum#STATEMENT statements}. - */ -public final class MinimalRubyNodeInstrumenter extends DefaultNodeInstrumenter implements RubyNodeInstrumenter { - - // TODO (mlvdv) convert methods to the general interface? will help with dependencies - - public RubyNode instrumentAsStatement(RubyNode rubyNode) { - assert rubyNode != null; - assert !(rubyNode instanceof RubyProxyNode); - final RubyContext context = rubyNode.getContext(); - 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; - } - - public RubyNode instrumentAsCall(RubyNode node, String callName) { - return node; - } - - public RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName) { - return node; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyNodeInstrumenter.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyNodeInstrumenter.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +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. 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.ruby.nodes.instrument; - -import com.oracle.truffle.api.nodes.instrument.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -public interface RubyNodeInstrumenter extends NodeInstrumenter { - - /** - * Adds instrumentation support at a node that should be considered a member of - * {@link NodePhylum#STATEMENT}, possibly returning a new {@link InstrumentationProxyNode} that - * holds the original as its child. - */ - RubyNode instrumentAsStatement(RubyNode node); - - /** - * Adds instrumentation support at a node that should be considered a member of - * {@link NodePhylum#CALL}, possibly returning a new {@link InstrumentationProxyNode} that holds - * the original as its child. - */ - RubyNode instrumentAsCall(RubyNode node, String callName); - - /** - * Adds instrumentation support at a node that should be considered a member of - * {@link NodePhylum#ASSIGNMENT}, possibly returning a new {@link InstrumentationProxyNode} that - * holds the original as its child. - */ - RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyProxyNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyProxyNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,229 +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.nodes.instrument; - -import java.math.*; -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.debug.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.instrument.*; -import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -/** - * An instrumentation proxy node that forwards all Ruby execution calls through to - * a child node and returns results back to the parent, but which also sends notifications to an - * attached {@linkplain ProbeChain chain} of {@linkplain InstrumentationProbeNode probes}. - */ -public class RubyProxyNode extends RubyNode implements InstrumentationProxyNode { - - @Child private RubyNode child; - - private final ProbeChain probeChain; - - public RubyProxyNode(RubyContext context, RubyNode child) { - super(context, SourceSection.NULL); - assert !(child instanceof RubyProxyNode); - this.child = adoptChild(child); - this.probeChain = context.getDebugContext().getDebugManager().getProbeChain(child.getSourceSection()); - } - - public RubyProxyNode(RubyContext context, RubyNode child, ProbeChain probeChain) { - super(context, SourceSection.NULL); - assert !(child instanceof RubyProxyNode); - this.child = adoptChild(child); - this.probeChain = probeChain; - } - - @Override - public RubyNode getNonProxyNode() { - return child; - } - - public RubyNode getChild() { - return child; - } - - public ProbeChain getProbeChain() { - return probeChain; - } - - @Override - public Object execute(VirtualFrame frame) { - probeChain.notifyEnter(child, frame); - - Object result; - - try { - result = child.execute(frame); - probeChain.notifyLeave(child, frame, result); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - - return result; - } - - @Override - public RubyArray executeArray(VirtualFrame frame) throws UnexpectedResultException { - probeChain.notifyEnter(child, frame); - - RubyArray result; - - try { - result = child.executeArray(frame); - probeChain.notifyLeave(child, frame, result); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - - return result; - } - - @Override - public BigInteger executeBignum(VirtualFrame frame) throws UnexpectedResultException { - probeChain.notifyEnter(child, frame); - - BigInteger result; - - try { - result = child.executeBignum(frame); - probeChain.notifyLeave(child, frame, result); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - - return result; - } - - @Override - public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { - probeChain.notifyEnter(child, frame); - - boolean result; - - try { - result = child.executeBoolean(frame); - probeChain.notifyLeave(child, frame, result); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - - return result; - } - - @Override - public Object isDefined(VirtualFrame frame) { - return child.isDefined(frame); - } - - @Override - public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException { - probeChain.notifyEnter(child, frame); - - int result; - - try { - result = child.executeFixnum(frame); - probeChain.notifyLeave(child, frame, result); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - - return result; - } - - @Override - public double executeFloat(VirtualFrame frame) throws UnexpectedResultException { - probeChain.notifyEnter(child, frame); - - double result; - - try { - result = child.executeFloat(frame); - probeChain.notifyLeave(child, frame, result); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - - return result; - } - - @Override - public RubyString executeString(VirtualFrame frame) throws UnexpectedResultException { - probeChain.notifyEnter(child, frame); - - RubyString result; - - try { - result = child.executeString(frame); - probeChain.notifyLeave(child, frame, result); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - - return result; - } - - @Override - public void executeVoid(VirtualFrame frame) { - probeChain.notifyEnter(child, frame); - - try { - child.executeVoid(frame); - probeChain.notifyLeave(child, frame); - } catch (KillException e) { - throw (e); - } catch (Exception e) { - probeChain.notifyLeaveExceptional(child, frame, e); - throw (e); - } - } - - public boolean isMarkedAs(NodePhylum phylum) { - return probeChain.isMarkedAs(phylum); - } - - public Set getPhylumMarks() { - return probeChain.getPhylumMarks(); - } - - public void markAs(NodePhylum phylum) { - probeChain.markAs(phylum); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BignumLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BignumLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 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.literal; - -import java.math.*; - -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.*; - -@NodeInfo(shortName = "bignum") -public class BignumLiteralNode extends RubyNode { - - private final BigInteger value; - - public BignumLiteralNode(RubyContext context, SourceSection sourceSection, BigInteger value) { - super(context, sourceSection); - this.value = value; - } - - @Override - public BigInteger executeBignum(VirtualFrame frame) { - return value; - } - - @Override - public Object execute(VirtualFrame frame) { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BooleanLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BooleanLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 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.literal; - -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.*; - -@NodeInfo(shortName = "boolean") -public class BooleanLiteralNode extends RubyNode { - - private final boolean value; - - public BooleanLiteralNode(RubyContext context, SourceSection sourceSection, boolean value) { - super(context, sourceSection); - this.value = value; - } - - @Override - public Object execute(VirtualFrame frame) { - return executeBoolean(frame); - } - - @Override - public boolean executeBoolean(VirtualFrame frame) { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FixnumLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FixnumLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +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.nodes.literal; - -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.*; - -@NodeInfo(shortName = "fixnum") -public class FixnumLiteralNode extends RubyNode { - - private final int value; - - public FixnumLiteralNode(RubyContext context, SourceSection sourceSection, int value) { - super(context, sourceSection); - this.value = value; - } - - @Override - public Object execute(VirtualFrame frame) { - return executeFixnum(frame); - } - - @Override - public int executeFixnum(VirtualFrame frame) { - return value; - } - - public int getValue() { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FloatLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FloatLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 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.literal; - -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.*; - -@NodeInfo(shortName = "float") -public class FloatLiteralNode extends RubyNode { - - private final double value; - - public FloatLiteralNode(RubyContext context, SourceSection sourceSection, double value) { - super(context, sourceSection); - this.value = value; - } - - @Override - public Object execute(VirtualFrame frame) { - return executeFloat(frame); - } - - @Override - public double executeFloat(VirtualFrame frame) { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/HashLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/HashLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2013 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.literal; - -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.*; - -@NodeInfo(shortName = "hash") -public class HashLiteralNode extends RubyNode { - - @Children protected final RubyNode[] keys; - @Children protected final RubyNode[] values; - - public HashLiteralNode(SourceSection sourceSection, RubyNode[] keys, RubyNode[] values, RubyContext context) { - super(context, sourceSection); - assert keys.length == values.length; - this.keys = adoptChildren(keys); - this.values = adoptChildren(values); - } - - @ExplodeLoop - @Override - public Object execute(VirtualFrame frame) { - final RubyHash hash = new RubyHash(getContext().getCoreLibrary().getHashClass()); - - for (int n = 0; n < keys.length; n++) { - hash.put(keys[n].execute(frame), values[n].execute(frame)); - } - - return hash; - } - - @Override - public Object isDefined(VirtualFrame frame) { - return getContext().makeString("expression"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/NilNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/NilNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 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.literal; - -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.*; - -/** - * A node that does nothing and evaluates to Nil. A no-op. - */ -@NodeInfo(shortName = "nil") -public final class NilNode extends RubyNode { - - public NilNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public NilPlaceholder executeNilPlaceholder(VirtualFrame frame) { - return NilPlaceholder.INSTANCE; - } - - @Override - public Object execute(VirtualFrame frame) { - return executeNilPlaceholder(frame); - } - - @Override - public void executeVoid(VirtualFrame frame) { - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/ObjectLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/ObjectLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2013 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.literal; - -import java.math.*; - -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.*; - -@NodeInfo(shortName = "object") -public class ObjectLiteralNode extends RubyNode { - - private final Object object; - - public ObjectLiteralNode(RubyContext context, SourceSection sourceSection, Object object) { - super(context, sourceSection); - - assert RubyContext.shouldObjectBeVisible(object); - assert !(object instanceof Integer); - assert !(object instanceof Double); - assert !(object instanceof BigInteger); - assert !(object instanceof String); - assert !(object instanceof RubyString); - - this.object = object; - } - - @Override - public Object execute(VirtualFrame frame) { - return object; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/RangeLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/RangeLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2013 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.literal; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -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.range.*; - -@NodeInfo(shortName = "range") -@NodeChildren({@NodeChild("begin"), @NodeChild("end")}) -public abstract class RangeLiteralNode extends RubyNode { - - private final boolean excludeEnd; - - public RangeLiteralNode(RubyContext context, SourceSection sourceSection, boolean excludeEnd) { - super(context, sourceSection); - this.excludeEnd = excludeEnd; - } - - public RangeLiteralNode(RangeLiteralNode prev) { - this(prev.getContext(), prev.getSourceSection(), prev.excludeEnd); - } - - @Specialization - public FixnumRange doFixnum(int begin, int end) { - return new FixnumRange(getContext().getCoreLibrary().getRangeClass(), begin, end, excludeEnd); - } - - @Generic - public Object doGeneric(Object begin, Object end) { - final RubyContext context = getContext(); - - if ((begin instanceof Integer) && (end instanceof Integer)) { - return doFixnum((int) begin, (int) end); - } else { - return new ObjectRange(context.getCoreLibrary().getRangeClass(), begin, end, excludeEnd); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/StringLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/StringLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.literal; - -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.*; - -@NodeInfo(shortName = "string") -public class StringLiteralNode extends RubyNode { - - private final String string; - - public StringLiteralNode(RubyContext context, SourceSection sourceSection, String string) { - super(context, sourceSection); - - assert string != null; - - this.string = string; - } - - @Override - public Object execute(VirtualFrame frame) { - return getContext().makeString(string); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ArrayLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ArrayLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013 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.literal.array; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -public abstract class ArrayLiteralNode extends RubyNode { - - @Children protected final RubyNode[] values; - - public ArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) { - super(context, sourceSection); - this.values = adoptChildren(values); - } - - protected RubyArray makeGeneric(VirtualFrame frame, Object[] alreadyExecuted) { - CompilerAsserts.neverPartOfCompilation(); - - replace(new ObjectArrayLiteralNode(getContext(), getSourceSection(), values)); - - final Object[] executedValues = new Object[values.length]; - - for (int n = 0; n < values.length; n++) { - if (n < alreadyExecuted.length) { - executedValues[n] = alreadyExecuted[n]; - } else { - executedValues[n] = values[n].execute(frame); - } - } - - return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), executedValues); - } - - @Override - public Object isDefined(VirtualFrame frame) { - return getContext().makeString("expression"); - } - - // TODO(CS): remove this - shouldn't be fiddling with nodes from the outside - public RubyNode[] getValues() { - return values; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/FixnumArrayLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/FixnumArrayLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013 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.literal.array; - -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.array.*; - -@NodeInfo(shortName = "fixnum-array-literal") -public class FixnumArrayLiteralNode extends ArrayLiteralNode { - - public FixnumArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) { - super(context, sourceSection, values); - } - - @ExplodeLoop - @Override - public RubyArray executeArray(VirtualFrame frame) { - final int[] executedValues = new int[values.length]; - - for (int n = 0; n < values.length; n++) { - try { - executedValues[n] = values[n].executeFixnum(frame); - } catch (UnexpectedResultException e) { - final Object[] executedObjects = new Object[n]; - - for (int i = 0; i < n; i++) { - executedObjects[i] = executedValues[i]; - } - - return makeGeneric(frame, executedObjects); - } - } - - return new RubyArray(getContext().getCoreLibrary().getArrayClass(), new FixnumArrayStore(executedValues)); - } - - @ExplodeLoop - @Override - public void executeVoid(VirtualFrame frame) { - for (int n = 0; n < values.length; n++) { - values[n].executeVoid(frame); - } - } - - @Override - public Object execute(VirtualFrame frame) { - return executeArray(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ObjectArrayLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ObjectArrayLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013 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.literal.array; - -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.array.*; - -@NodeInfo(shortName = "object-array-literal") -public class ObjectArrayLiteralNode extends ArrayLiteralNode { - - public ObjectArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) { - super(context, sourceSection, values); - } - - @ExplodeLoop - @Override - public RubyArray executeArray(VirtualFrame frame) { - final Object[] executedValues = new Object[values.length]; - - for (int n = 0; n < values.length; n++) { - executedValues[n] = values[n].execute(frame); - } - - return new RubyArray(getContext().getCoreLibrary().getArrayClass(), new ObjectArrayStore(executedValues)); - } - - @ExplodeLoop - @Override - public void executeVoid(VirtualFrame frame) { - for (int n = 0; n < values.length; n++) { - values[n].executeVoid(frame); - } - } - - @Override - public Object execute(VirtualFrame frame) { - return executeArray(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/UninitialisedArrayLiteralNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/UninitialisedArrayLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2013 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.literal.array; - -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.array.*; - -@NodeInfo(shortName = "uninit-array-literal") -public class UninitialisedArrayLiteralNode extends ArrayLiteralNode { - - public UninitialisedArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) { - super(context, sourceSection, values); - } - - @ExplodeLoop - @Override - public Object execute(VirtualFrame frame) { - CompilerDirectives.transferToInterpreter(); - - final Object[] executedValues = new Object[values.length]; - - for (int n = 0; n < values.length; n++) { - executedValues[n] = values[n].execute(frame); - } - - final RubyArray array = RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), executedValues); - final ArrayStore store = array.getArrayStore(); - - if (store instanceof FixnumArrayStore) { - replace(new FixnumArrayLiteralNode(getContext(), getSourceSection(), values)); - } else { - replace(new ObjectArrayLiteralNode(getContext(), getSourceSection(), values)); - } - - return array; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AddMethodNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AddMethodNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -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.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -@NodeInfo(shortName = "add-method") -public class AddMethodNode extends RubyNode { - - @Child protected RubyNode receiver; - @Child protected MethodDefinitionNode method; - - public AddMethodNode(RubyContext context, SourceSection section, RubyNode receiver, MethodDefinitionNode method) { - super(context, section); - this.receiver = adoptChild(receiver); - this.method = adoptChild(method); - } - - @Override - public Object execute(VirtualFrame frame) { - final Object receiverObject = receiver.execute(frame); - - final RubyMethod methodObject = (RubyMethod) method.execute(frame); - - final FrameSlot moduleFunctionFlagSlot = frame.getFrameDescriptor().findFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID); - - boolean moduleFunctionFlag; - - if (moduleFunctionFlagSlot == null) { - moduleFunctionFlag = false; - } else { - Object moduleFunctionObject; - - try { - moduleFunctionObject = frame.getObject(moduleFunctionFlagSlot); - } catch (FrameSlotTypeException e) { - throw new RuntimeException(e); - } - - if (moduleFunctionObject instanceof Boolean) { - moduleFunctionFlag = (boolean) moduleFunctionObject; - } else { - moduleFunctionFlag = false; - } - } - - final RubyModule module = (RubyModule) receiverObject; - - final RubyMethod methodWithDeclaringModule = methodObject.withDeclaringModule(module); - - module.addMethod(methodWithDeclaringModule); - - if (moduleFunctionFlag) { - module.getSingletonClass().addMethod(methodWithDeclaringModule); - } - - return NilPlaceholder.INSTANCE; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AliasNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AliasNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -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.*; - -@NodeInfo(shortName = "alias") -public class AliasNode extends RubyNode { - - @Child protected RubyNode module; - final String newName; - final String oldName; - - public AliasNode(RubyContext context, SourceSection sourceSection, RubyNode module, String newName, String oldName) { - super(context, sourceSection); - this.module = adoptChild(module); - this.newName = newName; - this.oldName = oldName; - } - - @Override - public void executeVoid(VirtualFrame frame) { - final RubyModule moduleObject = (RubyModule) module.execute(frame); - moduleObject.alias(newName, oldName); - } - - @Override - public Object execute(VirtualFrame frame) { - executeVoid(frame); - return NilPlaceholder.INSTANCE; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/BlockDefinitionNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/BlockDefinitionNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -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.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * Define a block. That is, store the definition of a block and when executed produce the executable - * object that results. - */ -@NodeInfo(shortName = "block-def") -public class BlockDefinitionNode extends MethodDefinitionNode { - - public BlockDefinitionNode(RubyContext context, SourceSection sourceSection, String name, UniqueMethodIdentifier uniqueIdentifier, FrameDescriptor frameDescriptor, - boolean requiresDeclarationFrame, RubyRootNode pristineRootNode, CallTarget callTarget) { - super(context, sourceSection, name, uniqueIdentifier, frameDescriptor, requiresDeclarationFrame, pristineRootNode, callTarget); - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyContext context = getContext(); - - MaterializedFrame declarationFrame; - - if (requiresDeclarationFrame) { - declarationFrame = frame.materialize(); - } else { - declarationFrame = null; - } - - final RubyArguments arguments = frame.getArguments(RubyArguments.class); - - final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, declarationFrame, frameDescriptor, pristineRootNode, true, false); - final RubyMethod method = new RubyMethod(getSourceSection(), null, uniqueIdentifier, null, name, Visibility.PUBLIC, false, methodImplementation); - - return new RubyProc(context.getCoreLibrary().getProcClass(), RubyProc.Type.PROC, arguments.getSelf(), arguments.getBlock(), method); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -/** - * Catch a {@code next} jump at the root of a method. - */ -public class CatchNextNode extends RubyNode { - - @Child protected RubyNode body; - - private final BranchProfile nextProfile = new BranchProfile(); - - public CatchNextNode(RubyContext context, SourceSection sourceSection, RubyNode body) { - super(context, sourceSection); - this.body = adoptChild(body); - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return body.execute(frame); - } catch (NextException e) { - nextProfile.enter(); - return e.getResult(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnAsErrorNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnAsErrorNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -/** - * Catch a {@code return} jump at the root of a method, and report it as an error. - */ -public class CatchReturnAsErrorNode extends RubyNode { - - @Child protected RubyNode body; - - public CatchReturnAsErrorNode(RubyContext context, SourceSection sourceSection, RubyNode body) { - super(context, sourceSection); - this.body = adoptChild(body); - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return body.execute(frame); - } catch (ReturnException e) { - CompilerDirectives.transferToInterpreter(); - throw new RaiseException(getContext().getCoreLibrary().unexpectedReturn()); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -/** - * Catch a {@code return} jump at the root of a method. - */ -public class CatchReturnNode extends RubyNode { - - @Child protected RubyNode body; - private final long returnID; - - private final BranchProfile returnProfile = new BranchProfile(); - private final BranchProfile returnToOtherMethodProfile = new BranchProfile(); - - public CatchReturnNode(RubyContext context, SourceSection sourceSection, RubyNode body, long returnID) { - super(context, sourceSection); - this.body = adoptChild(body); - this.returnID = returnID; - } - - public CatchReturnNode(CatchReturnNode prev) { - super(prev); - returnID = prev.returnID; - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return body.execute(frame); - } catch (ReturnException e) { - returnProfile.enter(); - - if (e.getReturnID() == returnID) { - return e.getValue(); - } else { - returnToOtherMethodProfile.enter(); - throw e; - } - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/MethodDefinitionNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/MethodDefinitionNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +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.nodes.methods; - -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.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * Define a method. That is, store the definition of a method and when executed produce the - * executable object that results. - */ -@NodeInfo(shortName = "method-def") -public class MethodDefinitionNode extends RubyNode { - - protected final String name; - protected final UniqueMethodIdentifier uniqueIdentifier; - - protected final FrameDescriptor frameDescriptor; - protected final RubyRootNode pristineRootNode; - - protected final CallTarget callTarget; - - protected final boolean requiresDeclarationFrame; - - public MethodDefinitionNode(RubyContext context, SourceSection sourceSection, String name, UniqueMethodIdentifier uniqueIdentifier, FrameDescriptor frameDescriptor, - boolean requiresDeclarationFrame, RubyRootNode pristineRootNode, CallTarget callTarget) { - super(context, sourceSection); - this.name = name; - this.uniqueIdentifier = uniqueIdentifier; - this.frameDescriptor = frameDescriptor; - this.requiresDeclarationFrame = requiresDeclarationFrame; - this.pristineRootNode = pristineRootNode; - this.callTarget = callTarget; - } - - public RubyMethod executeMethod(VirtualFrame frame) { - CompilerDirectives.transferToInterpreter(); - - MaterializedFrame declarationFrame; - - if (requiresDeclarationFrame) { - declarationFrame = frame.materialize(); - } else { - declarationFrame = null; - } - - final FrameSlot visibilitySlot = frame.getFrameDescriptor().findFrameSlot(RubyModule.VISIBILITY_FRAME_SLOT_ID); - - Visibility visibility; - - if (visibilitySlot == null) { - visibility = Visibility.PUBLIC; - } else { - Object visibilityObject; - - try { - visibilityObject = frame.getObject(visibilitySlot); - } catch (FrameSlotTypeException e) { - throw new RuntimeException(e); - } - - if (visibilityObject instanceof Visibility) { - visibility = (Visibility) visibilityObject; - } else { - visibility = Visibility.PUBLIC; - } - } - - final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, declarationFrame, frameDescriptor, pristineRootNode, false, false); - return new RubyMethod(getSourceSection(), null, uniqueIdentifier, null, name, visibility, false, methodImplementation); - } - - @Override - public Object execute(VirtualFrame frame) { - return executeMethod(frame); - } - - public String getName() { - return name; - } - - public CallTarget getCallTarget() { - return callTarget; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/ShellResultNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/ShellResultNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Produce a {@link ShellResult} object from a return value and the resulting frame. - */ -public class ShellResultNode extends RubyNode { - - @Child protected RubyNode body; - - public ShellResultNode(RubyContext context, SourceSection sourceSection, RubyNode body) { - super(context, sourceSection); - this.body = adoptChild(body); - } - - @Override - public Object execute(VirtualFrame frame) { - return new ShellResult(body.execute(frame), frame.materialize()); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/BlockDestructureSwitchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/BlockDestructureSwitchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -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.array.*; - -/** - * Switches between loading arguments as normal and doing a destructure. See - * testBlockArgumentsDestructure and MethodTranslator. - */ -@NodeInfo(shortName = "block-destructure-switch") -public class BlockDestructureSwitchNode extends RubyNode { - - @Child protected RubyNode loadIndividualArguments; - @Child protected RubyNode destructureArguments; - @Child protected RubyNode body; - - public BlockDestructureSwitchNode(RubyContext context, SourceSection sourceSection, RubyNode loadIndividualArguments, RubyNode destructureArguments, RubyNode body) { - super(context, sourceSection); - this.loadIndividualArguments = adoptChild(loadIndividualArguments); - this.destructureArguments = adoptChild(destructureArguments); - this.body = adoptChild(body); - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyArguments arguments = frame.getArguments(RubyArguments.class); - - if (arguments.getArguments().length == 1 && arguments.getArguments()[0] instanceof RubyArray) { - destructureArguments.executeVoid(frame); - } else { - loadIndividualArguments.executeVoid(frame); - } - - return body.execute(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/CheckArityNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/CheckArityNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -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.methods.*; - -/** - * Check arguments meet the arity of the method. - */ -@NodeInfo(shortName = "check-arity") -public class CheckArityNode extends RubyNode { - - private final Arity arity; - - public CheckArityNode(RubyContext context, SourceSection sourceSection, Arity arity) { - super(context, sourceSection); - this.arity = arity; - } - - @Override - public void executeVoid(VirtualFrame frame) { - final RubyArguments arguments = frame.getArguments(RubyArguments.class); - arity.checkArguments(getContext(), arguments.getArguments()); - } - - @Override - public Object execute(VirtualFrame frame) { - executeVoid(frame); - return NilPlaceholder.INSTANCE; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadAllArgumentsNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadAllArgumentsNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -public class ReadAllArgumentsNode extends RubyNode { - - public ReadAllArgumentsNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public Object[] executeObjectArray(VirtualFrame frame) { - return frame.getArguments(RubyArguments.class).getArguments(); - } - - @Override - public Object execute(VirtualFrame frame) { - return executeObjectArray(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadBlockArgumentNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadBlockArgumentNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -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.*; - -/** - * Read the block as a {@code Proc}. - */ -@NodeInfo(shortName = "read-block-argument") -public class ReadBlockArgumentNode extends RubyNode { - - private final boolean undefinedIfNotPresent; - - public ReadBlockArgumentNode(RubyContext context, SourceSection sourceSection, boolean undefinedIfNotPresent) { - super(context, sourceSection); - this.undefinedIfNotPresent = undefinedIfNotPresent; - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyArguments arguments = frame.getArguments(RubyArguments.class); - final RubyProc block = arguments.getBlock(); - - if (block == null) { - if (undefinedIfNotPresent) { - return UndefinedPlaceholder.INSTANCE; - } else { - return NilPlaceholder.INSTANCE; - } - } else { - return block; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadDestructureArgumentNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadDestructureArgumentNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -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.array.*; - -/** - * Assuming argument 0 is an array, read an element from that array. - */ -@NodeInfo(shortName = "read-destructure-argument") -public class ReadDestructureArgumentNode extends RubyNode { - - private final int index; - - public ReadDestructureArgumentNode(RubyContext context, SourceSection sourceSection, int index) { - super(context, sourceSection); - this.index = index; - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyArray array = (RubyArray) frame.getArguments(RubyArguments.class).getArguments()[0]; - return array.get(index); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadOptionalArgumentNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadOptionalArgumentNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Read an optional argument. - */ -@NodeInfo(shortName = "read-optional-argument") -public class ReadOptionalArgumentNode extends RubyNode { - - private final int index; - private final int minimum; - @Child protected RubyNode defaultValue; - - private final BranchProfile defaultValueProfile = new BranchProfile(); - - public ReadOptionalArgumentNode(RubyContext context, SourceSection sourceSection, int index, int minimum, RubyNode defaultValue) { - super(context, sourceSection); - this.index = index; - this.minimum = minimum; - this.defaultValue = adoptChild(defaultValue); - } - - @Override - public Object execute(VirtualFrame frame) { - final Object[] arguments = frame.getArguments(RubyArguments.class).getArguments(); - - if (arguments.length < minimum) { - defaultValueProfile.enter(); - return defaultValue.execute(frame); - } else { - assert index < arguments.length; - return arguments[index]; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPostArgumentNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPostArgumentNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -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.*; - -/** - * Read a post-optional argument. - */ -@NodeInfo(shortName = "read-post-optional-argument") -public class ReadPostArgumentNode extends RubyNode { - - private final int indexFromEnd; - - public ReadPostArgumentNode(RubyContext context, SourceSection sourceSection, int indexFromEnd) { - super(context, sourceSection); - this.indexFromEnd = indexFromEnd; - } - - @Override - public Object execute(VirtualFrame frame) { - final Object[] arguments = frame.getArguments(RubyArguments.class).getArguments(); - final int effectiveIndex = arguments.length - 1 - indexFromEnd; - assert effectiveIndex < arguments.length; - return arguments[effectiveIndex]; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPreArgumentNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPreArgumentNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Read pre-optional argument. - */ -@NodeInfo(shortName = "read-pre-optional-argument") -public class ReadPreArgumentNode extends RubyNode { - - private final int index; - private final boolean undefinedIfNotPresent; - - private final BranchProfile notPresentProfile = new BranchProfile(); - - public ReadPreArgumentNode(RubyContext context, SourceSection sourceSection, int index, boolean undefinedIfNotPresent) { - super(context, sourceSection); - this.index = index; - this.undefinedIfNotPresent = undefinedIfNotPresent; - } - - @Override - public Object execute(VirtualFrame frame) { - final Object[] arguments = frame.getArguments(RubyArguments.class).getArguments(); - - if (undefinedIfNotPresent) { - if (index >= arguments.length) { - notPresentProfile.enter(); - return UndefinedPlaceholder.INSTANCE; - } - } else { - assert index < arguments.length; - } - - return arguments[index]; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadRestArgumentNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadRestArgumentNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.arguments; - -import java.util.*; - -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.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -/** - * Read the rest of arguments after a certain point into an array. - */ -@NodeInfo(shortName = "read-rest-of-arguments") -public class ReadRestArgumentNode extends RubyNode { - - private final int index; - - public ReadRestArgumentNode(RubyContext context, SourceSection sourceSection, int index) { - super(context, sourceSection); - this.index = index; - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyArguments rubyArguments = frame.getArguments(RubyArguments.class); - - final Object[] arguments = rubyArguments.getArguments(); - - final RubyClass arrayClass = getContext().getCoreLibrary().getArrayClass(); - - if (arguments.length <= index) { - return new RubyArray(arrayClass); - } else if (index == 0) { - return new RubyArray(arrayClass, new ObjectArrayStore(arguments)); - } else { - return new RubyArray(arrayClass, new ObjectArrayStore(Arrays.copyOfRange(arguments, index, arguments.length))); - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FlipFlopStateNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FlipFlopStateNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -public abstract class FlipFlopStateNode extends Node { - - public FlipFlopStateNode(SourceSection sourceSection) { - super(sourceSection); - } - - public abstract boolean getState(VirtualFrame frame); - - public abstract void setState(VirtualFrame frame, boolean state); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FrameSlotNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FrameSlotNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -public abstract class FrameSlotNode extends RubyNode { - - protected final FrameSlot frameSlot; - - protected FrameSlotNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot) { - super(context, sourceSection); - this.frameSlot = frameSlot; - } - - public final FrameSlot getFrameSlot() { - return frameSlot; - } - - @Override - public FrameSlotNode copy() { - return (FrameSlotNode) super.copy(); - } - - protected final void setBoolean(Frame frame, boolean value) { - frame.setBoolean(frameSlot, value); - } - - protected final void setFixnum(Frame frame, int value) { - frame.setInt(frameSlot, value); - } - - protected final void setFloat(Frame frame, double value) { - frame.setDouble(frameSlot, value); - } - - protected final void setObject(Frame frame, Object value) { - frame.setObject(frameSlot, value); - } - - protected final boolean getBoolean(Frame frame) throws FrameSlotTypeException { - return frame.getBoolean(frameSlot); - } - - protected final int getFixnum(Frame frame) throws FrameSlotTypeException { - return frame.getInt(frameSlot); - } - - protected final double getFloat(Frame frame) throws FrameSlotTypeException { - return frame.getDouble(frameSlot); - } - - protected final Object getObject(Frame frame) { - try { - return frame.getObject(frameSlot); - } catch (FrameSlotTypeException e) { - throw new IllegalStateException(); - } - } - - protected final boolean isBooleanKind() { - return isKind(FrameSlotKind.Boolean); - } - - protected final boolean isFixnumKind() { - return isKind(FrameSlotKind.Int); - } - - protected final boolean isFloatKind() { - return isKind(FrameSlotKind.Double); - } - - protected final boolean isObjectKind() { - if (frameSlot.getKind() != FrameSlotKind.Object) { - CompilerDirectives.transferToInterpreter(); - frameSlot.setKind(FrameSlotKind.Object); - } - return true; - } - - private boolean isKind(FrameSlotKind kind) { - return frameSlot.getKind() == kind || initialSetKind(kind); - } - - private boolean initialSetKind(FrameSlotKind kind) { - if (frameSlot.getKind() == FrameSlotKind.Illegal) { - CompilerDirectives.transferToInterpreter(); - frameSlot.setKind(kind); - return true; - } - return false; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/InitFlipFlopSlotNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/InitFlipFlopSlotNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -public class InitFlipFlopSlotNode extends RubyNode { - - private final FrameSlot frameSlot; - - public InitFlipFlopSlotNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot) { - super(context, sourceSection); - this.frameSlot = frameSlot; - } - - @Override - public void executeVoid(VirtualFrame frame) { - frame.setBoolean(frameSlot, false); - } - - @Override - public Object execute(VirtualFrame frame) { - executeVoid(frame); - return null; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LevelFlipFlopStateNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LevelFlipFlopStateNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; - -public class LevelFlipFlopStateNode extends FlipFlopStateNode { - - private final int level; - private final FrameSlot frameSlot; - - public LevelFlipFlopStateNode(SourceSection sourceSection, int level, FrameSlot frameSlot) { - super(sourceSection); - this.level = level; - this.frameSlot = frameSlot; - } - - @Override - public boolean getState(VirtualFrame frame) { - final MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, level); - - try { - return levelFrame.getBoolean(frameSlot); - } catch (FrameSlotTypeException e) { - throw new IllegalStateException(); - } - } - - @Override - public void setState(VirtualFrame frame, boolean state) { - final MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, level); - levelFrame.setBoolean(frameSlot, state); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LocalFlipFlopStateNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LocalFlipFlopStateNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; - -public class LocalFlipFlopStateNode extends FlipFlopStateNode { - - private final FrameSlot frameSlot; - - public LocalFlipFlopStateNode(SourceSection sourceSection, FrameSlot frameSlot) { - super(sourceSection); - this.frameSlot = frameSlot; - } - - @Override - public boolean getState(VirtualFrame frame) { - try { - return frame.getBoolean(frameSlot); - } catch (FrameSlotTypeException e) { - throw new IllegalStateException(); - } - } - - @Override - public void setState(VirtualFrame frame, boolean state) { - frame.setBoolean(frameSlot, state); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLevelVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLevelVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -public abstract class ReadLevelVariableNode extends FrameSlotNode implements ReadNode { - - private final int varLevel; - - public ReadLevelVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot slot, int level) { - super(context, sourceSection, slot); - this.varLevel = level; - } - - public ReadLevelVariableNode(ReadLevelVariableNode prev) { - this(prev.getContext(), prev.getSourceSection(), prev.frameSlot, prev.varLevel); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public boolean doBoolean(VirtualFrame frame) throws FrameSlotTypeException { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - return getBoolean(levelFrame); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public int doFixnum(VirtualFrame frame) throws FrameSlotTypeException { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - return getFixnum(levelFrame); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public double doFloat(VirtualFrame frame) throws FrameSlotTypeException { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - return getFloat(levelFrame); - } - - @Specialization - public Object doObject(VirtualFrame frame) { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - return getObject(levelFrame); - } - - public int getVarLevel() { - return varLevel; - } - - @Override - public RubyNode makeWriteNode(RubyNode rhs) { - return WriteLevelVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot, varLevel, rhs); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLocalVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLocalVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -public abstract class ReadLocalVariableNode extends FrameSlotNode implements ReadNode { - - public ReadLocalVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot slot) { - super(context, sourceSection, slot); - } - - public ReadLocalVariableNode(ReadLocalVariableNode prev) { - this(prev.getContext(), prev.getSourceSection(), prev.frameSlot); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public boolean doBoolean(VirtualFrame frame) throws FrameSlotTypeException { - return getBoolean(frame); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public int doFixnum(VirtualFrame frame) throws FrameSlotTypeException { - return getFixnum(frame); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public double doFloat(VirtualFrame frame) throws FrameSlotTypeException { - return getFloat(frame); - } - - @Specialization - public Object doObject(VirtualFrame frame) { - return getObject(frame); - } - - @Override - public RubyNode makeWriteNode(RubyNode rhs) { - return WriteLocalVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot, rhs); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLevelVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLevelVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -@NodeChild(value = "rhs", type = RubyNode.class) -public abstract class WriteLevelVariableNode extends FrameSlotNode implements WriteNode { - - private final int varLevel; - - public WriteLevelVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot, int level) { - super(context, sourceSection, frameSlot); - this.varLevel = level; - } - - protected WriteLevelVariableNode(WriteLevelVariableNode prev) { - this(prev.getContext(), prev.getSourceSection(), prev.frameSlot, prev.varLevel); - } - - @Specialization(guards = "isBooleanKind") - public boolean doBoolean(VirtualFrame frame, boolean value) { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - setBoolean(levelFrame, value); - return value; - } - - @Specialization(guards = "isFixnumKind") - public int doFixnum(VirtualFrame frame, int value) { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - setFixnum(levelFrame, value); - return value; - } - - @Specialization(guards = "isFloatKind") - public double doFloat(VirtualFrame frame, double value) { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - setFloat(levelFrame, value); - return value; - } - - @Specialization(guards = "isObjectKind") - public Object doObject(VirtualFrame frame, Object value) { - MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel); - setObject(levelFrame, value); - return value; - } - - @Override - public RubyNode makeReadNode() { - return ReadLevelVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot, varLevel); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLocalVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLocalVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2013 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.methods.locals; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -@NodeChild(value = "rhs", type = RubyNode.class) -public abstract class WriteLocalVariableNode extends FrameSlotNode implements WriteNode { - - public WriteLocalVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot) { - super(context, sourceSection, frameSlot); - } - - protected WriteLocalVariableNode(WriteLocalVariableNode prev) { - this(prev.getContext(), prev.getSourceSection(), prev.frameSlot); - } - - @Specialization(guards = "isBooleanKind") - public boolean doFixnum(VirtualFrame frame, boolean value) { - setBoolean(frame, value); - return value; - } - - @Specialization(guards = "isFixnumKind") - public int doFixnum(VirtualFrame frame, int value) { - setFixnum(frame, value); - return value; - } - - @Specialization(guards = "isFloatKind") - public double doFloat(VirtualFrame frame, double value) { - setFloat(frame, value); - return value; - } - - @Specialization(guards = "isObjectKind") - public Object doObject(VirtualFrame frame, Object value) { - setObject(frame, value); - return value; - } - - @Override - public RubyNode makeReadNode() { - return ReadLocalVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ClassNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ClassNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.objects; - -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.objects.*; - -/** - * Reads the class of an object. - */ -@NodeInfo(shortName = "class") -public class ClassNode extends RubyNode { - - @Child protected RubyNode child; - - public ClassNode(RubyContext context, SourceSection sourceSection, RubyNode child) { - super(context, sourceSection); - this.child = adoptChild(child); - } - - @Override - public Object execute(VirtualFrame frame) { - return ((RubyBasicObject) child.execute(frame)).getRubyClass(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetClassNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetClassNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Define a new class, or get the existing one of the same name. - */ -public class DefineOrGetClassNode extends RubyNode { - - private final String name; - @Child protected RubyNode moduleDefinedIn; - @Child protected RubyNode superClass; - - public DefineOrGetClassNode(RubyContext context, SourceSection sourceSection, String name, RubyNode moduleDefinedIn, RubyNode superClass) { - super(context, sourceSection); - this.name = name; - this.moduleDefinedIn = adoptChild(moduleDefinedIn); - this.superClass = adoptChild(superClass); - } - - @Override - public Object execute(VirtualFrame frame) { - CompilerAsserts.neverPartOfCompilation(); - - final RubyContext context = getContext(); - - final RubyModule moduleDefinedInObject = (RubyModule) moduleDefinedIn.execute(frame); - - // Look for a current definition of the class, or create a new one - - final Object constantValue = moduleDefinedInObject.lookupConstant(name); - - RubyClass definingClass; - - if (constantValue == null) { - final Object self = frame.getArguments(RubyArguments.class).getSelf(); - - RubyModule parentModule; - - if (self instanceof RubyModule) { - parentModule = (RubyModule) self; - } else { - // Because it's top level, and so self is the magic main object - parentModule = null; - } - - final RubyClass superClassObject = (RubyClass) superClass.execute(frame); - - if (superClassObject instanceof RubyException.RubyExceptionClass) { - definingClass = new RubyException.RubyExceptionClass(superClassObject, name); - } else { - definingClass = new RubyClass(parentModule, superClassObject, name); - } - - moduleDefinedInObject.setConstant(name, definingClass); - moduleDefinedInObject.getSingletonClass().setConstant(name, definingClass); - - definingClass.getRubyClass().include(moduleDefinedInObject); - } else { - if (constantValue instanceof RubyClass) { - definingClass = (RubyClass) constantValue; - } else { - throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(constantValue.toString(), "class")); - } - } - - return definingClass; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetModuleNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetModuleNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Define a new module, or get the existing one of the same name. - */ -public class DefineOrGetModuleNode extends RubyNode { - - private final String name; - @Child protected RubyNode moduleDefinedIn; - - public DefineOrGetModuleNode(RubyContext context, SourceSection sourceSection, String name, RubyNode moduleDefinedIn) { - super(context, sourceSection); - this.name = name; - this.moduleDefinedIn = adoptChild(moduleDefinedIn); - } - - @Override - public Object execute(VirtualFrame frame) { - CompilerAsserts.neverPartOfCompilation(); - - final RubyContext context = getContext(); - - final RubyModule moduleDefinedInObject = (RubyModule) moduleDefinedIn.execute(frame); - - // Look for a current definition of the module, or create a new one - - final Object constantValue = moduleDefinedInObject.lookupConstant(name); - - RubyModule definingModule; - - if (constantValue == null) { - final Object self = frame.getArguments(RubyArguments.class).getSelf(); - - RubyModule parentModule; - - if (self instanceof RubyModule) { - parentModule = (RubyModule) self; - } else { - // Because it's top level, and so self is the magic main object - parentModule = null; - } - - definingModule = new RubyModule(context.getCoreLibrary().getModuleClass(), parentModule, name); - moduleDefinedInObject.setConstant(name, definingModule); - moduleDefinedInObject.getSingletonClass().setConstant(name, definingModule); - } else { - if (constantValue instanceof RubyModule) { - definingModule = (RubyModule) constantValue; - } else { - throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(constantValue.toString(), "module")); - } - } - - return definingModule; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/OpenModuleNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/OpenModuleNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.methods.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Open a module and execute a method in it - probably to define new methods. - */ -public class OpenModuleNode extends RubyNode { - - @Child protected RubyNode definingModule; - @Child protected MethodDefinitionNode definitionMethod; - - public OpenModuleNode(RubyContext context, SourceSection sourceSection, RubyNode definingModule, MethodDefinitionNode definitionMethod) { - super(context, sourceSection); - this.definingModule = adoptChild(definingModule); - this.definitionMethod = adoptChild(definitionMethod); - } - - @Override - public Object execute(VirtualFrame frame) { - CompilerAsserts.neverPartOfCompilation(); - - // Call the definition method with the module as self - there's no return value - - final RubyModule module = (RubyModule) definingModule.execute(frame); - definitionMethod.executeMethod(frame).call(frame.pack(), module, null); - - return NilPlaceholder.INSTANCE; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ReadClassVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ReadClassVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -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.*; - -@NodeInfo(shortName = "read-class-variable") -public class ReadClassVariableNode extends RubyNode { - - protected final String name; - @Child protected RubyNode module; - - public ReadClassVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode module) { - super(context, sourceSection); - this.name = name; - this.module = adoptChild(module); - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyObject object = (RubyObject) module.execute(frame); - - RubyModule moduleObject; - - // TODO(CS): this cannot be right - - if (object instanceof RubyModule) { - moduleObject = (RubyModule) object; - } else { - moduleObject = object.getRubyClass(); - } - - final Object value = moduleObject.lookupClassVariable(name); - - if (value == null) { - // TODO(CS): is this right? - return NilPlaceholder.INSTANCE; - } - - return value; - } - - @Override - public Object isDefined(VirtualFrame frame) { - final RubyContext context = getContext(); - - final RubyObject object = (RubyObject) module.execute(frame); - - RubyModule moduleObject; - - if (object instanceof RubyModule) { - moduleObject = (RubyModule) object; - } else { - moduleObject = object.getRubyClass(); - } - - final Object value = moduleObject.lookupClassVariable(name); - - if (value == null) { - return NilPlaceholder.INSTANCE; - } else { - return context.makeString("class variable"); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SelfNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SelfNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -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.*; - -@NodeInfo(shortName = "self") -public class SelfNode extends RubyNode { - - public SelfNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public Object execute(VirtualFrame frame) { - final Object self = frame.getArguments(RubyArguments.class).getSelf(); - assert RubyContext.shouldObjectBeVisible(self); - return self; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SingletonClassNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SingletonClassNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import java.math.*; - -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.objects.*; - -/** - * Reads the singleton (meta, eigen) class of an object. - */ -@NodeInfo(shortName = "singleton") -public class SingletonClassNode extends RubyNode { - - @Child protected RubyNode child; - - public SingletonClassNode(RubyContext context, SourceSection sourceSection, RubyNode child) { - super(context, sourceSection); - this.child = adoptChild(child); - } - - @Override - public Object execute(VirtualFrame frame) { - final Object childResult = child.execute(frame); - - final RubyContext context = getContext(); - - if (childResult instanceof NilPlaceholder) { - return context.getCoreLibrary().getNilClass(); - } else if (childResult instanceof BigInteger) { - // TODO(CS): this is problematic - do Bignums have singletons or not? - return context.getCoreLibrary().box(childResult).getSingletonClass(); - } else { - return ((RubyBasicObject) childResult).getSingletonClass(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/WriteClassVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/WriteClassVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -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.*; - -@NodeInfo(shortName = "write-class-variable") -public class WriteClassVariableNode extends RubyNode { - - private final String name; - @Child protected RubyNode module; - @Child protected RubyNode rhs; - - public WriteClassVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode module, RubyNode rhs) { - super(context, sourceSection); - this.name = name; - this.module = adoptChild(module); - this.rhs = adoptChild(rhs); - } - - @Override - public Object execute(VirtualFrame frame) { - // TODO(CS): can module ever not evaluate to a RubyModule? - - final RubyModule moduleObject = (RubyModule) module.execute(frame); - - final Object rhsValue = rhs.execute(frame); - - moduleObject.setClassVariable(name, rhsValue); - - return rhsValue; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFixnumInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFixnumInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@Fixnum") -public class ReadFixnumInstanceVariableNode extends ReadSpecializedInstanceVariableNode { - - private final FixnumStorageLocation storageLocation; - - public ReadFixnumInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, FixnumStorageLocation storageLocation) { - super(context, sourceSection, name, receiver, objectLayout); - this.storageLocation = storageLocation; - } - - @Override - public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException { - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - - final ObjectLayout receiverLayout = receiverObject.getObjectLayout(); - - final boolean condition = receiverLayout == objectLayout; - - if (condition) { - assert receiverLayout != null; - return storageLocation.readFixnum(receiverObject, condition); - } else { - CompilerDirectives.transferToInterpreter(); - replace(respecialize(receiverObject)); - throw new UnexpectedResultException(receiverObject.getInstanceVariable(name)); - } - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return executeFixnum(frame); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFloatInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFloatInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@Float") -public class ReadFloatInstanceVariableNode extends ReadSpecializedInstanceVariableNode { - - private final FloatStorageLocation storageLocation; - - public ReadFloatInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, FloatStorageLocation storageLocation) { - super(context, sourceSection, name, receiver, objectLayout); - this.storageLocation = storageLocation; - } - - @Override - public double executeFloat(VirtualFrame frame) throws UnexpectedResultException { - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - - final ObjectLayout receiverLayout = receiverObject.getObjectLayout(); - - final boolean condition = receiverLayout == objectLayout; - - if (condition) { - assert receiverLayout != null; - return storageLocation.readFloat(receiverObject, condition); - } else { - CompilerDirectives.transferToInterpreter(); - replace(respecialize(receiverObject)); - throw new UnexpectedResultException(receiverObject.getInstanceVariable(name)); - } - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return executeFloat(frame); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -public abstract class ReadInstanceVariableNode extends RubyNode implements ReadNode { - - protected final String name; - @Child protected RubyNode receiver; - - public ReadInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) { - super(context, sourceSection); - this.name = name; - this.receiver = adoptChild(receiver); - } - - public ReadInstanceVariableNode respecialize(RubyBasicObject receiverObject) { - final StorageLocation storageLocation = receiverObject.getUpdatedObjectLayout().findStorageLocation(name); - - if (storageLocation == null) { - return new ReadMissingInstanceVariableNode(getSourceSection(), name, receiver, receiverObject.getObjectLayout(), getContext()); - } - - if (storageLocation instanceof FixnumStorageLocation) { - return new ReadFixnumInstanceVariableNode(getContext(), getSourceSection(), name, receiver, storageLocation.getObjectLayout(), (FixnumStorageLocation) storageLocation); - } else if (storageLocation instanceof FloatStorageLocation) { - return new ReadFloatInstanceVariableNode(getContext(), getSourceSection(), name, receiver, storageLocation.getObjectLayout(), (FloatStorageLocation) storageLocation); - } else { - return new ReadObjectInstanceVariableNode(getContext(), getSourceSection(), name, receiver, storageLocation.getObjectLayout(), (ObjectStorageLocation) storageLocation); - } - } - - public WriteInstanceVariableNode makeWriteNode(RubyNode rhs) { - return new UninitializedWriteInstanceVariableNode(getContext(), getEncapsulatingSourceSection(), name, (RubyNode) receiver.copy(), rhs); - } - - public String getName() { - return name; - } - - public RubyNode getReceiver() { - return receiver; - } - - @Override - public Object isDefined(VirtualFrame frame) { - final RubyContext context = getContext(); - - try { - final Object receiverObject = receiver.execute(frame); - final RubyBasicObject receiverRubyObject = context.getCoreLibrary().box(receiverObject); - - final ObjectLayout layout = receiverRubyObject.getObjectLayout(); - final StorageLocation storageLocation = layout.findStorageLocation(name); - - if (storageLocation.isSet(receiverRubyObject)) { - return context.makeString("instance-variable"); - } else { - return NilPlaceholder.INSTANCE; - } - } catch (Exception e) { - return NilPlaceholder.INSTANCE; - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadMissingInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadMissingInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@missing") -public class ReadMissingInstanceVariableNode extends ReadSpecializedInstanceVariableNode { - - public ReadMissingInstanceVariableNode(SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, RubyContext context) { - super(context, sourceSection, name, receiver, objectLayout); - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - - if (!receiverObject.getObjectLayout().contains(objectLayout)) { - CompilerDirectives.transferToInterpreter(); - replace(respecialize(receiverObject)); - return receiverObject.getInstanceVariable(name); - } - - return NilPlaceholder.INSTANCE; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadObjectInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadObjectInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@Object") -public class ReadObjectInstanceVariableNode extends ReadSpecializedInstanceVariableNode { - - private final ObjectStorageLocation storageLocation; - - public ReadObjectInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, ObjectStorageLocation storageLocation) { - super(context, sourceSection, name, receiver, objectLayout); - this.storageLocation = storageLocation; - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - - final ObjectLayout receiverLayout = receiverObject.getObjectLayout(); - - final boolean condition = receiverLayout == objectLayout; - - if (condition) { - assert receiverLayout != null; - return storageLocation.read(receiverObject, condition); - } else { - CompilerDirectives.transferToInterpreter(); - replace(respecialize(receiverObject)); - return receiverObject.getInstanceVariable(name); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadSpecializedInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadSpecializedInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -public abstract class ReadSpecializedInstanceVariableNode extends ReadInstanceVariableNode { - - protected final ObjectLayout objectLayout; - - public ReadSpecializedInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout) { - super(context, sourceSection, name, receiver); - this.objectLayout = objectLayout; - } - - protected void respecialize() { - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedReadInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedReadInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@uninit") -public class UninitializedReadInstanceVariableNode extends ReadInstanceVariableNode { - - public UninitializedReadInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) { - super(context, sourceSection, name, receiver); - } - - @Override - public Object execute(VirtualFrame frame) { - CompilerDirectives.transferToInterpreter(); - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - replace(respecialize(receiverObject)); - return receiverObject.getInstanceVariable(name); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedWriteInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedWriteInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@uninit=") -public class UninitializedWriteInstanceVariableNode extends WriteInstanceVariableNode { - - public UninitializedWriteInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs) { - super(context, sourceSection, name, receiver, rhs); - } - - @Override - public Object execute(VirtualFrame frame) { - CompilerDirectives.transferToInterpreter(); - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - final Object value = rhs.execute(frame); - receiverObject.setInstanceVariable(name, value); - replace(respecialize(receiverObject)); - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFixnumInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFixnumInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@Fixnum=") -public class WriteFixnumInstanceVariableNode extends WriteSpecializedInstanceVariableNode { - - private final FixnumStorageLocation storageLocation; - - public WriteFixnumInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout, - FixnumStorageLocation storageLocation) { - super(context, sourceSection, name, receiver, rhs, objectLayout); - this.storageLocation = storageLocation; - } - - @Override - public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException { - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - - int value; - - try { - value = rhs.executeFixnum(frame); - } catch (UnexpectedResultException e) { - receiverObject.setInstanceVariable(name, e.getResult()); - replace(respecialize(receiverObject)); - throw e; - } - - final ObjectLayout receiverLayout = receiverObject.getObjectLayout(); - - if (receiverLayout != objectLayout) { - CompilerDirectives.transferToInterpreter(); - receiverObject.setInstanceVariable(name, value); - replace(respecialize(receiverObject)); - return value; - } - - assert receiverLayout != null; - - storageLocation.writeFixnum(receiverObject, value); - return value; - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return executeFixnum(frame); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFloatInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFloatInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@Float=") -public class WriteFloatInstanceVariableNode extends WriteSpecializedInstanceVariableNode { - - private final FloatStorageLocation storageLocation; - - public WriteFloatInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout, - FloatStorageLocation storageLocation) { - super(context, sourceSection, name, receiver, rhs, objectLayout); - this.storageLocation = storageLocation; - } - - @Override - public double executeFloat(VirtualFrame frame) throws UnexpectedResultException { - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - - double value; - - try { - value = rhs.executeFloat(frame); - } catch (UnexpectedResultException e) { - receiverObject.setInstanceVariable(name, e.getResult()); - replace(respecialize(receiverObject)); - throw e; - } - - final ObjectLayout receiverLayout = receiverObject.getObjectLayout(); - - if (receiverLayout != objectLayout) { - CompilerDirectives.transferToInterpreter(); - receiverObject.setInstanceVariable(name, value); - replace(respecialize(receiverObject)); - return value; - } - - assert receiverLayout != null; - - storageLocation.writeFloat(receiverObject, value); - return value; - } - - @Override - public Object execute(VirtualFrame frame) { - try { - return executeFloat(frame); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -public abstract class WriteInstanceVariableNode extends RubyNode implements WriteNode { - - protected final String name; - @Child protected RubyNode receiver; - @Child protected RubyNode rhs; - - public WriteInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs) { - super(context, sourceSection); - this.name = name; - this.receiver = adoptChild(receiver); - this.rhs = adoptChild(rhs); - } - - public WriteInstanceVariableNode respecialize(RubyBasicObject receiverObject) { - StorageLocation storageLocation = receiverObject.getObjectLayout().findStorageLocation(name); - - if (storageLocation == null) { - throw new RuntimeException("Storage location should be found at this point"); - } - - if (storageLocation instanceof FixnumStorageLocation) { - return new WriteFixnumInstanceVariableNode(getContext(), getSourceSection(), name, receiver, rhs, storageLocation.getObjectLayout(), (FixnumStorageLocation) storageLocation); - } else if (storageLocation instanceof FloatStorageLocation) { - return new WriteFloatInstanceVariableNode(getContext(), getSourceSection(), name, receiver, rhs, storageLocation.getObjectLayout(), (FloatStorageLocation) storageLocation); - } else { - return new WriteObjectInstanceVariableNode(getContext(), getSourceSection(), name, receiver, rhs, storageLocation.getObjectLayout(), (ObjectStorageLocation) storageLocation); - } - } - - @Override - public ReadInstanceVariableNode makeReadNode() { - return new UninitializedReadInstanceVariableNode(getContext(), getEncapsulatingSourceSection(), name, (RubyNode) receiver.copy()); - } - - public String getName() { - return name; - } - - public RubyNode getReceiver() { - return receiver; - } - - public RubyNode getRHS() { - return rhs; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteObjectInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteObjectInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -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.objects.*; - -@NodeInfo(shortName = "@Object=") -public class WriteObjectInstanceVariableNode extends WriteSpecializedInstanceVariableNode { - - private final ObjectStorageLocation storageLocation; - - public WriteObjectInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout, - ObjectStorageLocation storageLocation) { - super(context, sourceSection, name, receiver, rhs, objectLayout); - this.storageLocation = storageLocation; - } - - @Override - public Object execute(VirtualFrame frame) { - final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame); - final Object value = rhs.execute(frame); - - final ObjectLayout receiverLayout = receiverObject.getObjectLayout(); - - if (receiverLayout != objectLayout) { - CompilerDirectives.transferToInterpreter(); - receiverObject.setInstanceVariable(name, value); - replace(respecialize(receiverObject)); - return value; - } - - assert receiverLayout != null; - - storageLocation.write(receiverObject, value); - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteSpecializedInstanceVariableNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteSpecializedInstanceVariableNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013 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.objects.instancevariables; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -public abstract class WriteSpecializedInstanceVariableNode extends WriteInstanceVariableNode { - - protected final ObjectLayout objectLayout; - - public WriteSpecializedInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout) { - super(context, sourceSection, name, receiver, rhs); - this.objectLayout = objectLayout; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/GeneralYieldDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/GeneralYieldDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013 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.yield; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * A yield dispatch node that just calls {@link RubyProc#call} as normal. - */ -public class GeneralYieldDispatchNode extends YieldDispatchNode { - - public GeneralYieldDispatchNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) { - return block.call(frame.pack(), argumentsObjects); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/InlinedYieldDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/InlinedYieldDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2013 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.yield; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Dispatch to a known method which has been inlined. - */ -public class InlinedYieldDispatchNode extends YieldDispatchNode { - - private final RubyRootNode pristineRootNode; - - private final FrameDescriptor frameDescriptor; - private final RubyRootNode rootNode; - - public InlinedYieldDispatchNode(RubyContext context, SourceSection sourceSection, InlinableMethodImplementation method) { - super(context, sourceSection); - pristineRootNode = method.getPristineRootNode(); - frameDescriptor = method.getFrameDescriptor(); - rootNode = method.getCloneOfPristineRootNode(); - } - - @Override - public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) { - /* - * We're inlining based on the root node used, checking that root node still matches, and - * then taking the materialized frame from the block we actually got. We can't look for - * RubyMethod or RubyProc, because they're allocated for each call passing a block. - */ - - if (!(block.getMethod().getImplementation() instanceof InlinableMethodImplementation) || - ((InlinableMethodImplementation) block.getMethod().getImplementation()).getPristineRootNode() != pristineRootNode) { - CompilerDirectives.transferToInterpreter(); - - // TODO(CS): at the moment we just go back to uninit, which may cause loops - - final UninitializedYieldDispatchNode dispatch = new UninitializedYieldDispatchNode(getContext(), getSourceSection()); - replace(dispatch); - return dispatch.dispatch(frame, block, argumentsObjects); - } - - final InlinableMethodImplementation implementation = (InlinableMethodImplementation) block.getMethod().getImplementation(); - - final RubyArguments arguments = new RubyArguments(implementation.getDeclarationFrame(), block.getSelf(), block.getBlock(), argumentsObjects); - final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, frameDescriptor); - return rootNode.execute(inlinedFrame); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/UninitializedYieldDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/UninitializedYieldDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.yield; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * An uninitialized node in the yield dispatch chain. - */ -public class UninitializedYieldDispatchNode extends YieldDispatchNode { - - public UninitializedYieldDispatchNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) { - CompilerDirectives.transferToInterpreter(); - - final MethodImplementation implementation = block.getMethod().getImplementation(); - - if (implementation instanceof InlinableMethodImplementation && InlineHeuristic.shouldInlineYield((InlinableMethodImplementation) implementation)) { - final InlinedYieldDispatchNode dispatch = new InlinedYieldDispatchNode(getContext(), getSourceSection(), (InlinableMethodImplementation) implementation); - replace(dispatch); - return dispatch.dispatch(frame, block, argumentsObjects); - } else { - final GeneralYieldDispatchNode dispatch = new GeneralYieldDispatchNode(getContext(), getSourceSection()); - replace(dispatch); - return dispatch.dispatch(frame, block, argumentsObjects); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldDispatchNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldDispatchNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 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.yield; - -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.core.*; - -/** - * A node in the yield dispatch chain. - */ -public abstract class YieldDispatchNode extends Node { - - private final RubyContext context; - - public YieldDispatchNode(RubyContext context, SourceSection sourceSection) { - super(sourceSection); - - assert context != null; - assert sourceSection != null; - - this.context = context; - } - - public abstract Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects); - - public RubyContext getContext() { - return context; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2013 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.yield; - -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.*; - -/** - * Yield to the current block. - */ -@NodeInfo(shortName = "yield") -public class YieldNode extends RubyNode { - - @Children protected final RubyNode[] arguments; - @Child protected YieldDispatchNode dispatch; - - public YieldNode(RubyContext context, SourceSection sourceSection, RubyNode[] arguments) { - super(context, sourceSection); - this.arguments = adoptChildren(arguments); - dispatch = adoptChild(new UninitializedYieldDispatchNode(getContext(), getSourceSection())); - } - - @ExplodeLoop - @Override - public final Object execute(VirtualFrame frame) { - final Object[] argumentsObjects = new Object[arguments.length]; - - for (int i = 0; i < arguments.length; i++) { - argumentsObjects[i] = arguments[i].execute(frame); - } - - final RubyProc block = frame.getArguments(RubyArguments.class).getBlock(); - - if (block == null) { - CompilerDirectives.transferToInterpreter(); - // TODO(CS): convert to the proper Ruby exception - throw new RuntimeException("No block to yield to"); - } - - return dispatch.dispatch(frame, block, argumentsObjects); - } - - @Override - public Object isDefined(VirtualFrame frame) { - final RubyArguments args = frame.getArguments(RubyArguments.class); - - if (args.getBlock() == null) { - return NilPlaceholder.INSTANCE; - } else { - return getContext().makeString("yield"); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DeadNode.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DeadNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013 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.parser; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Dead nodes are removed wherever they are found during translation. They fill in for some missing - * nodes when we're processing the AST. - */ -public class DeadNode extends RubyNode { - - public DeadNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - @Override - public Object execute(VirtualFrame frame) { - throw new UnsupportedOperationException("Dead nodes should have been pruned before execution starts"); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +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.parser; - -import java.io.*; - -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.nodes.control.*; -import com.oracle.truffle.ruby.nodes.literal.*; -import com.oracle.truffle.ruby.nodes.methods.*; -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.methods.*; - -public class JRubyParser implements RubyParser { - - private long nextReturnID = 0; - - public JRubyParser() { - } - - @Override - public RubyParserResult parse(RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame) { - - // Set up the JRuby parser - - final org.jrubyparser.Parser parser = new org.jrubyparser.Parser(); - - // TODO(cs) should this get a new unique method identifier or not? - final TranslatorEnvironment environment = new TranslatorEnvironment(context, environmentForFrame(context, parentFrame), this, allocateReturnID(), true, true, new UniqueMethodIdentifier()); - - // All parsing contexts have a visibility slot at their top level - - environment.addMethodDeclarationSlots(); - - final org.jrubyparser.LocalStaticScope staticScope = new org.jrubyparser.LocalStaticScope(null); - - if (parentFrame != null) { - /* - * Note that jruby-parser will be mistaken about how deep the existing variables are, - * but that doesn't matter as we look them up ourselves after being told their in some - * parent scope. - */ - - MaterializedFrame frame = parentFrame; - - while (frame != null) { - for (FrameSlot slot : frame.getFrameDescriptor().getSlots()) { - if (slot.getIdentifier() instanceof String) { - final String name = (String) slot.getIdentifier(); - if (staticScope.exists(name) == -1) { - staticScope.assign(null, name, null); - } - } - } - - frame = frame.getArguments(RubyArguments.class).getDeclarationFrame(); - } - } - - final org.jrubyparser.parser.ParserConfiguration parserConfiguration = new org.jrubyparser.parser.ParserConfiguration(0, org.jrubyparser.CompatVersion.RUBY2_0, staticScope); - - // Parse to the JRuby AST - - org.jrubyparser.ast.RootNode node; - - try { - node = (org.jrubyparser.ast.RootNode) parser.parse(source.getName(), new StringReader(source.getCode()), parserConfiguration); - } catch (UnsupportedOperationException | org.jrubyparser.lexer.SyntaxException e) { - String message = e.getMessage(); - - if (message == null) { - message = "(no message)"; - } - - throw new RaiseException(new RubyException(context.getCoreLibrary().getSyntaxErrorClass(), message)); - } - - if (context.getConfiguration().getPrintParseTree()) { - System.err.println(node); - } - - // Translate to Ruby Truffle nodes - - final Translator translator; - - if (parserContext == RubyParser.ParserContext.MODULE) { - translator = new ModuleTranslator(context, null, environment, source); - } else { - translator = new Translator(context, null, environment, source); - } - - RubyNode truffleNode; - - try { - context.getDebugContext().getDebugManager().notifyStartLoading(source); - - if (node.getBody() == null) { - truffleNode = new NilNode(context, null); - } else { - truffleNode = (RubyNode) node.getBody().accept(translator); - } - - // Load flip-flop states - - if (environment.getFlipFlopStates().size() > 0) { - truffleNode = new SequenceNode(context, truffleNode.getSourceSection(), translator.initFlipFlopStates(truffleNode.getSourceSection()), truffleNode); - } - - // Catch next - - truffleNode = new CatchNextNode(context, truffleNode.getSourceSection(), truffleNode); - - // Catch return - - truffleNode = new CatchReturnAsErrorNode(context, truffleNode.getSourceSection(), truffleNode); - - // Shell result - - if (parserContext == RubyParser.ParserContext.SHELL) { - truffleNode = new ShellResultNode(context, truffleNode.getSourceSection(), truffleNode); - } - - // Root Node - - String indicativeName; - - switch (parserContext) { - case TOP_LEVEL: - indicativeName = "(main)"; - break; - case SHELL: - indicativeName = "(shell)"; - break; - case MODULE: - indicativeName = "(module)"; - break; - default: - throw new UnsupportedOperationException(); - } - - final RootNode root = new RubyRootNode(truffleNode.getSourceSection(), environment.getFrameDescriptor(), indicativeName, truffleNode); - - // Return the root and the frame descriptor - return new RubyParserResult(root); - } finally { - context.getDebugContext().getDebugManager().notifyFinishedLoading(source); - } - } - - public long allocateReturnID() { - if (nextReturnID == Long.MAX_VALUE) { - throw new RuntimeException("Return IDs exhausted"); - } - - final long allocated = nextReturnID; - nextReturnID++; - return allocated; - } - - private TranslatorEnvironment environmentForFrame(RubyContext context, MaterializedFrame frame) { - if (frame == null) { - return null; - } else { - final MaterializedFrame parent = frame.getArguments(RubyArguments.class).getDeclarationFrame(); - return new TranslatorEnvironment(context, environmentForFrame(context, parent), frame.getFrameDescriptor(), this, allocateReturnID(), true, true, new UniqueMethodIdentifier()); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/MethodTranslator.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/MethodTranslator.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2013 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.parser; - -import java.util.*; - -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.nodes.call.*; -import com.oracle.truffle.ruby.nodes.control.*; -import com.oracle.truffle.ruby.nodes.literal.*; -import com.oracle.truffle.ruby.nodes.methods.*; -import com.oracle.truffle.ruby.nodes.methods.arguments.*; -import com.oracle.truffle.ruby.nodes.methods.locals.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -class MethodTranslator extends Translator { - - private boolean isBlock; - - public MethodTranslator(RubyContext context, Translator parent, TranslatorEnvironment environment, boolean isBlock, Source source) { - super(context, parent, environment, source); - this.isBlock = isBlock; - } - - public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, String methodName, org.jrubyparser.ast.ArgsNode argsNode, org.jrubyparser.ast.Node bodyNode) { - environment.setMethodName(methodName); - - final Arity arity = findParameters(argsNode); - - RubyNode body; - - if (bodyNode != null) { - body = (RubyNode) bodyNode.accept(this); - } else { - body = new NilNode(context, sourceSection); - } - - body = loadArgumentsIntoLocals(arity, body); - - if (environment.getFlipFlopStates().size() > 0) { - body = new SequenceNode(context, sourceSection, initFlipFlopStates(sourceSection), body); - } - - if (isBlock) { - body = new CatchNextNode(context, sourceSection, body); - } else { - body = new CatchReturnNode(context, sourceSection, body, environment.getReturnID()); - body = new CatchNextNode(context, sourceSection, body); - } - - final RubyRootNode pristineRootNode = new RubyRootNode(sourceSection, environment.getFrameDescriptor(), methodName, body); - - final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode)); - - if (isBlock) { - return new BlockDefinitionNode(context, sourceSection, methodName, environment.getUniqueMethodIdentifier(), environment.getFrameDescriptor(), environment.needsDeclarationFrame(), - pristineRootNode, callTarget); - } else { - return new MethodDefinitionNode(context, sourceSection, methodName, environment.getUniqueMethodIdentifier(), environment.getFrameDescriptor(), environment.needsDeclarationFrame(), - pristineRootNode, callTarget); - } - } - - private RubyNode loadArgumentsIntoLocals(Arity arity, RubyNode body) { - final SourceSection sourceSection = body.getEncapsulatingSourceSection(); - - final List loadIndividualArgumentsNodes = new ArrayList<>(); - - if (!isBlock) { - loadIndividualArgumentsNodes.add(new CheckArityNode(context, sourceSection, arity)); - } - - final int preCount = environment.getPreParameters().size(); - final int postCount = environment.getPostParameters().size(); - - for (int n = 0; n < environment.getPreParameters().size(); n++) { - final FrameSlot param = environment.getPreParameters().get(n); - - // ReadPre reads from the start of the arguments array - - final ReadPreArgumentNode readArgumentNode = new ReadPreArgumentNode(context, sourceSection, n, false); - - final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode); - - loadIndividualArgumentsNodes.add(writeLocal); - } - - for (int n = 0; n < environment.getOptionalParameters().size(); n++) { - final FrameSlot param = environment.getOptionalParameters().get(n); - final RubyNode defaultValue = environment.getOptionalParametersDefaultValues().get(param); - - /* - * ReadOptional reads from the start of the arguments array, as long as it is long - * enough, else uses the default value (which may use locals with arguments just loaded, - * either from pre or preceding optionals). - */ - - final ReadOptionalArgumentNode readArgumentNode = new ReadOptionalArgumentNode(context, body.getEncapsulatingSourceSection(), preCount + n, preCount + postCount + n + 1, - (RubyNode) defaultValue.copy()); - - final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode); - - loadIndividualArgumentsNodes.add(writeLocal); - } - - for (int n = 0; n < environment.getPostParameters().size(); n++) { - final FrameSlot param = environment.getPostParameters().get(n); - - // ReadPost reads from the end of the arguments array - - final ReadPostArgumentNode readArgumentNode = new ReadPostArgumentNode(context, sourceSection, postCount - n - 1); - - final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode); - - loadIndividualArgumentsNodes.add(writeLocal); - } - - if (environment.getRestParameter() != null) { - /* - * TODO(cs): this assumes there are no optionals and therefore also no posts, which may - * not be a valid assumption. - */ - - if (postCount != 0) { - context.implementationMessage("post arguments as well as a rest argument - they will conflict"); - } - - final ReadRestArgumentNode readArgumentNode = new ReadRestArgumentNode(context, sourceSection, preCount); - - final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, environment.getRestParameter(), readArgumentNode); - - loadIndividualArgumentsNodes.add(writeLocal); - } - - if (environment.getBlockParameter() != null) { - final FrameSlot param = environment.getBlockParameter(); - - final ReadBlockArgumentNode readArgumentNode = new ReadBlockArgumentNode(context, sourceSection, false); - - final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode); - - loadIndividualArgumentsNodes.add(writeLocal); - } - - final RubyNode loadIndividualArguments = new SequenceNode(context, sourceSection, loadIndividualArgumentsNodes.toArray(new RubyNode[loadIndividualArgumentsNodes.size()])); - - final RubyNode noSwitch = new SequenceNode(context, body.getSourceSection(), loadIndividualArguments, body); - - if (!isBlock) { - return noSwitch; - } - - /* - * See the test testBlockArgumentsDestructure for a motivation for this. See - * BlockDestructureSwitchNode for how it works. - */ - - if (preCount + postCount == 1 && environment.getOptionalParameters().size() == 0) { - return noSwitch; - } - - final List destructureLoadArgumentsNodes = new ArrayList<>(); - - for (int n = 0; n < environment.getPreParameters().size(); n++) { - final FrameSlot param = environment.getPreParameters().get(n); - - final ReadDestructureArgumentNode readArgumentNode = new ReadDestructureArgumentNode(context, sourceSection, n); - - final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode); - - destructureLoadArgumentsNodes.add(writeLocal); - } - - final RubyNode destructureLoadArguments = new SequenceNode(context, body.getSourceSection(), destructureLoadArgumentsNodes.toArray(new RubyNode[destructureLoadArgumentsNodes.size()])); - - return new BlockDestructureSwitchNode(context, body.getEncapsulatingSourceSection(), loadIndividualArguments, destructureLoadArguments, body); - - } - - private Arity findParameters(org.jrubyparser.ast.ArgsNode args) { - if (args == null) { - return Arity.NO_ARGS; - } - - final SourceSection sourceSection = translate(args.getPosition()); - - if (args.getPre() != null) { - for (org.jrubyparser.ast.Node arg : args.getPre().childNodes()) { - if (arg instanceof org.jrubyparser.ast.ArgumentNode) { - final org.jrubyparser.ast.ArgumentNode argNode = (org.jrubyparser.ast.ArgumentNode) arg; - environment.getPreParameters().add(environment.declareVar(argNode.getName())); - } else if (arg instanceof org.jrubyparser.ast.MultipleAsgnNode) { - /* - * TODO(cs): I don't know how to handle this yet, so I just do my best to get - * the names out and define them so the rest of the parser succeeds. - */ - - context.implementationMessage("only extracting names from multiple assignment in arguments"); - - final org.jrubyparser.ast.MultipleAsgnNode multAsgn = (org.jrubyparser.ast.MultipleAsgnNode) arg; - - final List names = new ArrayList<>(); - getNamesFromMultipleAssignment(multAsgn, names); - - for (String name : names) { - environment.getPreParameters().add(environment.declareVar(name)); - } - } - } - } - - // The JRuby parser expresses optional arguments as a block of local assignments - - /* - * Note that default values for optional params can refer to the actual value of previous - * args, so be careful with the order of args here and in loadArgumentsIntoLocals. - */ - - if (args.getOptional() != null) { - for (org.jrubyparser.ast.Node arg : args.getOptional().childNodes()) { - final org.jrubyparser.ast.OptArgNode optArgNode = (org.jrubyparser.ast.OptArgNode) arg; - - String name; - org.jrubyparser.ast.Node valueNode; - - if (optArgNode.getValue() instanceof org.jrubyparser.ast.LocalAsgnNode) { - final org.jrubyparser.ast.LocalAsgnNode optLocalAsgn = (org.jrubyparser.ast.LocalAsgnNode) optArgNode.getValue(); - name = optLocalAsgn.getName(); - valueNode = optLocalAsgn.getValue(); - } else if (optArgNode.getValue() instanceof org.jrubyparser.ast.DAsgnNode) { - final org.jrubyparser.ast.DAsgnNode optLocalAsgn = (org.jrubyparser.ast.DAsgnNode) optArgNode.getValue(); - name = optLocalAsgn.getName(); - valueNode = optLocalAsgn.getValue(); - } else { - throw new UnsupportedOperationException(optArgNode.getValue().getClass().getName()); - } - - RubyNode paramDefaultValue; - - if (valueNode == null) { - paramDefaultValue = new NilNode(context, sourceSection); - } else { - paramDefaultValue = (RubyNode) valueNode.accept(this); - } - - final FrameSlot frameSlot = environment.declareVar(name); - environment.getOptionalParameters().add(frameSlot); - environment.getOptionalParametersDefaultValues().put(frameSlot, paramDefaultValue); - } - } - - if (args.getPost() != null) { - for (org.jrubyparser.ast.Node arg : args.getPost().childNodes()) { - final org.jrubyparser.ast.ArgumentNode argNode = (org.jrubyparser.ast.ArgumentNode) arg; - environment.getPostParameters().add(environment.declareVar(argNode.getName())); - } - } - - if (args.getRest() != null) { - final org.jrubyparser.ast.RestArgNode rest = (org.jrubyparser.ast.RestArgNode) args.getRest(); - environment.setRestParameter(environment.declareVar(rest.getName())); - } - - if (args.getBlock() != null) { - final org.jrubyparser.ast.BlockArgNode blockArgNode = args.getBlock(); - final FrameSlot frameSlot = environment.declareVar(blockArgNode.getName()); - environment.setBlockParameter(frameSlot); - } - - final int minimum = environment.getPreParameters().size() + environment.getPostParameters().size(); - - int maximum = minimum + environment.getOptionalParameters().size(); - - if (args.getRest() != null) { - maximum = Arity.NO_MAXIMUM; - } - - return new Arity(minimum, maximum); - } - - private void getNamesFromMultipleAssignment(org.jrubyparser.ast.MultipleAsgnNode multAsgn, List names) { - for (org.jrubyparser.ast.Node a : multAsgn.getPre().childNodes()) { - if (a instanceof org.jrubyparser.ast.DAsgnNode) { - names.add(((org.jrubyparser.ast.DAsgnNode) a).getName()); - } else if (a instanceof org.jrubyparser.ast.MultipleAsgnNode) { - getNamesFromMultipleAssignment((org.jrubyparser.ast.MultipleAsgnNode) a, names); - } else if (a instanceof org.jrubyparser.ast.LocalAsgnNode) { - names.add(((org.jrubyparser.ast.LocalAsgnNode) a).getName()); - } else { - throw new RuntimeException(a.getClass().getName()); - } - } - } - - @Override - public Object visitSuperNode(org.jrubyparser.ast.SuperNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, node.getIter(), node.getArgs(), null); - - final String name = environment.getMethodName(); - - return new GeneralSuperCallNode(context, sourceSection, name, argumentsAndBlock.getBlock(), argumentsAndBlock.getArguments(), argumentsAndBlock.isSplatted()); - } - - @Override - public Object visitZSuperNode(org.jrubyparser.ast.ZSuperNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, node.getIter(), null, null); - - final String name = environment.getMethodName(); - - return new GeneralSuperCallNode(context, sourceSection, name, argumentsAndBlock.getBlock(), argumentsAndBlock.getArguments(), argumentsAndBlock.isSplatted()); - } - - @Override - protected FlipFlopStateNode createFlipFlopState(SourceSection sourceSection, int depth) { - if (isBlock) { - environment.setNeedsDeclarationFrame(); - return parent.createFlipFlopState(sourceSection, depth + 1); - } else { - return super.createFlipFlopState(sourceSection, depth); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/ModuleTranslator.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/ModuleTranslator.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2013 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.parser; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.constants.*; -import com.oracle.truffle.ruby.nodes.control.*; -import com.oracle.truffle.ruby.nodes.literal.*; -import com.oracle.truffle.ruby.nodes.methods.*; -import com.oracle.truffle.ruby.nodes.objects.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * Translates module and class nodes. - *

- * In Ruby, a module or class definition is somewhat like a method. It has a local scope and a value - * for self, which is the module or class object that is being defined. Therefore for a module or - * class definition we translate into a special method. We run that method with self set to be the - * newly allocated module or class. We then have to treat at least method and constant definitions - * differently. - */ -class ModuleTranslator extends Translator { - - public ModuleTranslator(RubyContext context, Translator parent, TranslatorEnvironment environment, Source source) { - super(context, parent, environment, source); - } - - public MethodDefinitionNode compileClassNode(org.jrubyparser.SourcePosition sourcePosition, String name, org.jrubyparser.ast.Node bodyNode) { - final SourceSection sourceSection = translate(sourcePosition); - - environment.addMethodDeclarationSlots(); - - final String methodName = "(" + name + "-def" + ")"; - environment.setMethodName(methodName); - - RubyNode body; - - if (bodyNode != null) { - body = (RubyNode) bodyNode.accept(this); - } else { - body = new NilNode(context, sourceSection); - } - - if (environment.getFlipFlopStates().size() > 0) { - body = new SequenceNode(context, sourceSection, initFlipFlopStates(sourceSection), body); - } - - body = new CatchReturnNode(context, sourceSection, body, environment.getReturnID()); - - final RubyRootNode pristineRootNode = new RubyRootNode(sourceSection, environment.getFrameDescriptor(), methodName, body); - - final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode)); - - return new MethodDefinitionNode(context, sourceSection, methodName, environment.getUniqueMethodIdentifier(), environment.getFrameDescriptor(), environment.needsDeclarationFrame(), - pristineRootNode, callTarget); - } - - @Override - public Object visitConstDeclNode(org.jrubyparser.ast.ConstDeclNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final SelfNode selfNode = new SelfNode(context, sourceSection); - - return new WriteConstantNode(context, sourceSection, node.getName(), selfNode, (RubyNode) node.getValue().accept(this)); - } - - @Override - public Object visitConstNode(org.jrubyparser.ast.ConstNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final SelfNode selfNode = new SelfNode(context, sourceSection); - - return new UninitializedReadConstantNode(context, sourceSection, node.getName(), selfNode); - } - - @Override - public Object visitDefnNode(org.jrubyparser.ast.DefnNode node) { - /* - * The top-level translator puts methods into Object. We put ours into the self, which is - * the class being defined. - */ - - final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true, - new UniqueMethodIdentifier()); - final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source); - final MethodDefinitionNode functionExprNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), node.getName(), node.getArgs(), node.getBody()); - - final SourceSection sourceSection = translate(node.getPosition()); - return new AddMethodNode(context, sourceSection, new SelfNode(context, sourceSection), functionExprNode); - } - - @Override - public Object visitClassVarAsgnNode(org.jrubyparser.ast.ClassVarAsgnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode receiver = new SelfNode(context, sourceSection); - - final RubyNode rhs = (RubyNode) node.getValue().accept(this); - - return new WriteClassVariableNode(context, sourceSection, node.getName(), receiver, rhs); - } - - @Override - public Object visitClassVarNode(org.jrubyparser.ast.ClassVarNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - return new ReadClassVariableNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection)); - } - - @Override - public Object visitAliasNode(org.jrubyparser.ast.AliasNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final org.jrubyparser.ast.LiteralNode oldName = (org.jrubyparser.ast.LiteralNode) node.getOldName(); - final org.jrubyparser.ast.LiteralNode newName = (org.jrubyparser.ast.LiteralNode) node.getNewName(); - - return new AliasNode(context, sourceSection, new SelfNode(context, sourceSection), newName.getName(), oldName.getName()); - } - - @Override - protected RubyNode getModuleToDefineModulesIn(SourceSection sourceSection) { - return new SelfNode(context, sourceSection); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyFrameTypeConversion.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyFrameTypeConversion.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2013 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.parser; - -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.ruby.runtime.*; - -public final class RubyFrameTypeConversion extends DefaultFrameTypeConversion { - - private static final RubyFrameTypeConversion INSTANCE = new RubyFrameTypeConversion(); - - private RubyFrameTypeConversion() { - } - - @Override - public Object getDefaultValue() { - return NilPlaceholder.INSTANCE; - } - - public static RubyFrameTypeConversion getInstance() { - return INSTANCE; - } -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2066 +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.parser; - -import java.math.*; -import java.util.*; -import java.util.regex.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.nodes.cast.*; -import com.oracle.truffle.ruby.nodes.constants.*; -import com.oracle.truffle.ruby.nodes.control.*; -import com.oracle.truffle.ruby.nodes.core.*; -import com.oracle.truffle.ruby.nodes.instrument.*; -import com.oracle.truffle.ruby.nodes.literal.*; -import com.oracle.truffle.ruby.nodes.literal.array.*; -import com.oracle.truffle.ruby.nodes.methods.*; -import com.oracle.truffle.ruby.nodes.methods.locals.*; -import com.oracle.truffle.ruby.nodes.objects.*; -import com.oracle.truffle.ruby.nodes.objects.instancevariables.*; -import com.oracle.truffle.ruby.nodes.yield.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.range.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * A JRuby parser node visitor which translates JRuby AST nodes into our Ruby nodes, implementing a - * Ruby parser. Therefore there is some namespace contention here! We make all references to JRuby - * explicit. This is the only place though - it doesn't leak out elsewhere. - */ -public class Translator implements org.jrubyparser.NodeVisitor { - - protected final Translator parent; - - protected final RubyContext context; - protected final TranslatorEnvironment environment; - protected final Source source; - protected final RubyNodeInstrumenter instrumenter; - - private boolean translatingForStatement = false; - - private static final Map nodeDefinedNames = new HashMap<>(); - - static { - nodeDefinedNames.put(org.jrubyparser.ast.SelfNode.class, "self"); - nodeDefinedNames.put(org.jrubyparser.ast.NilNode.class, "nil"); - nodeDefinedNames.put(org.jrubyparser.ast.TrueNode.class, "true"); - nodeDefinedNames.put(org.jrubyparser.ast.FalseNode.class, "false"); - nodeDefinedNames.put(org.jrubyparser.ast.LocalAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.DAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.GlobalAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.InstAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.ClassVarAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnAndNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnOrNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.OpElementAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.MultipleAsgnNode.class, "assignment"); - nodeDefinedNames.put(org.jrubyparser.ast.GlobalVarNode.class, "global-variable"); - nodeDefinedNames.put(org.jrubyparser.ast.StrNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.DStrNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.FixnumNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.BignumNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.FloatNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.RegexpNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.DRegexpNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.ArrayNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.HashNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.SymbolNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.DotNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.NotNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.AndNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.OrNode.class, "expression"); - nodeDefinedNames.put(org.jrubyparser.ast.LocalVarNode.class, "local-variable"); - nodeDefinedNames.put(org.jrubyparser.ast.DVarNode.class, "local-variable"); - } - - /** - * Global variables which in common usage have frame local semantics. - */ - public static final Set FRAME_LOCAL_GLOBAL_VARIABLES = new HashSet<>(Arrays.asList("$_")); - - public Translator(RubyContext context, Translator parent, TranslatorEnvironment environment, Source source) { - this.context = context; - this.parent = parent; - this.environment = environment; - this.source = source; - this.instrumenter = environment.getNodeInstrumenter(); - } - - @Override - public Object visitAliasNode(org.jrubyparser.ast.AliasNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final org.jrubyparser.ast.LiteralNode oldName = (org.jrubyparser.ast.LiteralNode) node.getOldName(); - final org.jrubyparser.ast.LiteralNode newName = (org.jrubyparser.ast.LiteralNode) node.getNewName(); - - final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection)); - - return new AliasNode(context, sourceSection, classNode, newName.getName(), oldName.getName()); - } - - @Override - public Object visitAndNode(org.jrubyparser.ast.AndNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode x; - - if (node.getFirst() == null) { - x = new NilNode(context, sourceSection); - } else { - x = (RubyNode) node.getFirst().accept(this); - } - - RubyNode y; - - if (node.getSecond() == null) { - y = new NilNode(context, sourceSection); - } else { - y = (RubyNode) node.getSecond().accept(this); - } - - return AndNodeFactory.create(context, sourceSection, x, y); - } - - @Override - public Object visitArgsCatNode(org.jrubyparser.ast.ArgsCatNode node) { - final List nodes = new ArrayList<>(); - collectArgsCatNodes(nodes, node); - - final List translatedNodes = new ArrayList<>(); - - for (org.jrubyparser.ast.Node catNode : nodes) { - translatedNodes.add((RubyNode) catNode.accept(this)); - } - - return new ArrayConcatNode(context, translate(node.getPosition()), translatedNodes.toArray(new RubyNode[translatedNodes.size()])); - } - - // ArgsCatNodes can be nested - this collects them into a flat list of children - private void collectArgsCatNodes(List nodes, org.jrubyparser.ast.ArgsCatNode node) { - if (node.getFirst() instanceof org.jrubyparser.ast.ArgsCatNode) { - collectArgsCatNodes(nodes, (org.jrubyparser.ast.ArgsCatNode) node.getFirst()); - } else { - nodes.add(node.getFirst()); - } - - if (node.getSecond() instanceof org.jrubyparser.ast.ArgsCatNode) { - collectArgsCatNodes(nodes, (org.jrubyparser.ast.ArgsCatNode) node.getSecond()); - } else { - nodes.add(node.getSecond()); - } - } - - @Override - public Object visitArgsNode(org.jrubyparser.ast.ArgsNode node) { - return unimplemented(node); - } - - @Override - public Object visitArgsPushNode(org.jrubyparser.ast.ArgsPushNode node) { - return new ArrayPushNode(context, translate(node.getPosition()), (RubyNode) node.getFirstNode().accept(this), (RubyNode) node.getSecondNode().accept(this)); - } - - @Override - public Object visitArrayNode(org.jrubyparser.ast.ArrayNode node) { - final List values = node.childNodes(); - - final RubyNode[] translatedValues = new RubyNode[values.size()]; - - for (int n = 0; n < values.size(); n++) { - translatedValues[n] = (RubyNode) values.get(n).accept(this); - } - - return new UninitialisedArrayLiteralNode(context, translate(node.getPosition()), translatedValues); - } - - @Override - public Object visitAttrAssignNode(org.jrubyparser.ast.AttrAssignNode node) { - return visitAttrAssignNodeExtraArgument(node, null); - } - - /** - * See translateDummyAssignment to understand what this is for. - */ - public RubyNode visitAttrAssignNodeExtraArgument(org.jrubyparser.ast.AttrAssignNode node, RubyNode extraArgument) { - final org.jrubyparser.ast.CallNode callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), node.getName(), node.getArgs()); - return visitCallNodeExtraArgument(callNode, extraArgument); - } - - @Override - public Object visitBackRefNode(org.jrubyparser.ast.BackRefNode node) { - return unimplemented(node); - } - - @Override - public Object visitBeginNode(org.jrubyparser.ast.BeginNode node) { - return node.getBody().accept(this); - } - - @Override - public Object visitBignumNode(org.jrubyparser.ast.BignumNode node) { - return new BignumLiteralNode(context, translate(node.getPosition()), node.getValue()); - } - - @Override - public Object visitBlockArg18Node(org.jrubyparser.ast.BlockArg18Node node) { - return unimplemented(node); - } - - @Override - public Object visitBlockArgNode(org.jrubyparser.ast.BlockArgNode node) { - return unimplemented(node); - } - - @Override - public Object visitBlockNode(org.jrubyparser.ast.BlockNode node) { - final List children = node.childNodes(); - - final List translatedChildren = new ArrayList<>(); - - for (int n = 0; n < children.size(); n++) { - final RubyNode translatedChild = (RubyNode) children.get(n).accept(this); - - if (!(translatedChild instanceof DeadNode)) { - translatedChildren.add(translatedChild); - } - } - - if (translatedChildren.size() == 1) { - return translatedChildren.get(0); - } else { - return new SequenceNode(context, translate(node.getPosition()), translatedChildren.toArray(new RubyNode[translatedChildren.size()])); - } - } - - @Override - public Object visitBlockPassNode(org.jrubyparser.ast.BlockPassNode node) { - return unimplemented(node); - } - - @Override - public Object visitBreakNode(org.jrubyparser.ast.BreakNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode resultNode; - - if (node.getValueNode() == null) { - resultNode = new NilNode(context, sourceSection); - } else { - resultNode = (RubyNode) node.getValueNode().accept(this); - } - - return new BreakNode(context, sourceSection, resultNode); - } - - @Override - public Object visitCallNode(org.jrubyparser.ast.CallNode node) { - return visitCallNodeExtraArgument(node, null); - } - - /** - * See translateDummyAssignment to understand what this is for. - */ - public RubyNode visitCallNodeExtraArgument(org.jrubyparser.ast.CallNode node, RubyNode extraArgument) { - final SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode receiverTranslated = (RubyNode) node.getReceiver().accept(this); - - org.jrubyparser.ast.Node args = node.getArgs(); - org.jrubyparser.ast.Node block = node.getIter(); - - if (block == null && args instanceof org.jrubyparser.ast.IterNode) { - final org.jrubyparser.ast.Node temp = args; - args = block; - block = temp; - } - - final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, block, args, extraArgument); - - RubyNode translated = new CallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), argumentsAndBlock.getArguments()); - - return instrumenter.instrumentAsCall(translated, node.getName()); - } - - protected class ArgumentsAndBlockTranslation { - - private final RubyNode block; - private final RubyNode[] arguments; - private final boolean isSplatted; - - public ArgumentsAndBlockTranslation(RubyNode block, RubyNode[] arguments, boolean isSplatted) { - super(); - this.block = block; - this.arguments = arguments; - this.isSplatted = isSplatted; - } - - public RubyNode getBlock() { - return block; - } - - public RubyNode[] getArguments() { - return arguments; - } - - public boolean isSplatted() { - return isSplatted; - } - - } - - protected ArgumentsAndBlockTranslation translateArgumentsAndBlock(SourceSection sourceSection, org.jrubyparser.ast.Node iterNode, org.jrubyparser.ast.Node argsNode, RubyNode extraArgument) { - assert !(argsNode instanceof org.jrubyparser.ast.IterNode); - - final List arguments = new ArrayList<>(); - org.jrubyparser.ast.Node blockPassNode = null; - - boolean isSplatted = false; - - if (argsNode instanceof org.jrubyparser.ast.ListNode) { - arguments.addAll(((org.jrubyparser.ast.ListNode) argsNode).childNodes()); - } else if (argsNode instanceof org.jrubyparser.ast.BlockPassNode) { - final org.jrubyparser.ast.BlockPassNode blockPass = (org.jrubyparser.ast.BlockPassNode) argsNode; - - final org.jrubyparser.ast.Node blockPassArgs = blockPass.getArgs(); - - if (blockPassArgs instanceof org.jrubyparser.ast.ListNode) { - arguments.addAll(((org.jrubyparser.ast.ListNode) blockPassArgs).childNodes()); - } else if (blockPassArgs instanceof org.jrubyparser.ast.ArgsCatNode) { - arguments.add(blockPassArgs); - } else if (blockPassArgs != null) { - throw new UnsupportedOperationException("Don't know how to block pass " + blockPassArgs); - } - - blockPassNode = blockPass.getBody(); - } else if (argsNode instanceof org.jrubyparser.ast.SplatNode) { - isSplatted = true; - arguments.add(argsNode); - } else if (argsNode instanceof org.jrubyparser.ast.ArgsCatNode) { - isSplatted = true; - arguments.add(argsNode); - } else if (argsNode != null) { - isSplatted = true; - arguments.add(argsNode); - } - - RubyNode blockTranslated; - - if (blockPassNode != null && iterNode != null) { - throw new UnsupportedOperationException("Don't know how to pass both an block and a block-pass argument"); - } else if (iterNode != null) { - blockTranslated = (BlockDefinitionNode) iterNode.accept(this); - } else if (blockPassNode != null) { - blockTranslated = ProcCastNodeFactory.create(context, sourceSection, (RubyNode) blockPassNode.accept(this)); - } else { - blockTranslated = null; - } - - final List argumentsTranslated = new ArrayList<>(); - - for (org.jrubyparser.ast.Node argument : arguments) { - argumentsTranslated.add((RubyNode) argument.accept(this)); - } - - if (extraArgument != null) { - argumentsTranslated.add(extraArgument); - } - - final RubyNode[] argumentsTranslatedArray = argumentsTranslated.toArray(new RubyNode[argumentsTranslated.size()]); - - return new ArgumentsAndBlockTranslation(blockTranslated, argumentsTranslatedArray, isSplatted); - } - - @Override - public Object visitCaseNode(org.jrubyparser.ast.CaseNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode elseNode; - - if (node.getElse() != null) { - elseNode = (RubyNode) node.getElse().accept(this); - } else { - elseNode = new NilNode(context, sourceSection); - } - - /* - * There are two sorts of case - one compares a list of expressions against a value, the - * other just checks a list of expressions for truth. - */ - - if (node.getCase() != null) { - // Evaluate the case expression and store it in a local - - final String tempName = environment.allocateLocalTemp(); - - final RubyNode readTemp = environment.findLocalVarNode(tempName, sourceSection); - - final RubyNode assignTemp = ((ReadNode) readTemp).makeWriteNode((RubyNode) node.getCase().accept(this)); - - /* - * Build an if expression from the whens and else. Work backwards because the first if - * contains all the others in its else clause. - */ - - for (int n = node.getCases().size() - 1; n >= 0; n--) { - final org.jrubyparser.ast.WhenNode when = (org.jrubyparser.ast.WhenNode) node.getCases().get(n); - - // Make a condition from the one or more expressions combined in an or expression - - final List expressions; - - if (when.getExpression() instanceof org.jrubyparser.ast.ListNode) { - expressions = ((org.jrubyparser.ast.ListNode) when.getExpression()).childNodes(); - } else { - expressions = Arrays.asList(when.getExpression()); - } - - final List comparisons = new ArrayList<>(); - - for (org.jrubyparser.ast.Node expressionNode : expressions) { - final RubyNode rubyExpression = (RubyNode) expressionNode.accept(this); - - final CallNode comparison = new CallNode(context, sourceSection, "===", rubyExpression, null, false, new RubyNode[]{environment.findLocalVarNode(tempName, sourceSection)}); - - comparisons.add(comparison); - } - - RubyNode conditionNode = comparisons.get(comparisons.size() - 1); - - // As with the if nodes, we work backwards to make it left associative - - for (int i = comparisons.size() - 2; i >= 0; i--) { - conditionNode = OrNodeFactory.create(context, sourceSection, comparisons.get(i), conditionNode); - } - - // Create the if node - - final BooleanCastNode conditionCastNode = BooleanCastNodeFactory.create(context, sourceSection, conditionNode); - - RubyNode thenNode; - - if (when.getBody() == null) { - thenNode = new NilNode(context, sourceSection); - } else { - thenNode = (RubyNode) when.getBody().accept(this); - } - - final IfNode ifNode = new IfNode(context, sourceSection, conditionCastNode, thenNode, elseNode); - - // This if becomes the else for the next if - - elseNode = ifNode; - } - - final RubyNode ifNode = elseNode; - - // A top-level block assigns the temp then runs the if - - return new SequenceNode(context, sourceSection, assignTemp, ifNode); - } else { - for (int n = node.getCases().size() - 1; n >= 0; n--) { - final org.jrubyparser.ast.WhenNode when = (org.jrubyparser.ast.WhenNode) node.getCases().get(n); - - // Make a condition from the one or more expressions combined in an or expression - - final List expressions; - - if (when.getExpression() instanceof org.jrubyparser.ast.ListNode) { - expressions = ((org.jrubyparser.ast.ListNode) when.getExpression()).childNodes(); - } else { - expressions = Arrays.asList(when.getExpression()); - } - - final List tests = new ArrayList<>(); - - for (org.jrubyparser.ast.Node expressionNode : expressions) { - final RubyNode rubyExpression = (RubyNode) expressionNode.accept(this); - tests.add(rubyExpression); - } - - RubyNode conditionNode = tests.get(tests.size() - 1); - - // As with the if nodes, we work backwards to make it left associative - - for (int i = tests.size() - 2; i >= 0; i--) { - conditionNode = OrNodeFactory.create(context, sourceSection, tests.get(i), conditionNode); - } - - // Create the if node - - final BooleanCastNode conditionCastNode = BooleanCastNodeFactory.create(context, sourceSection, conditionNode); - - final RubyNode thenNode = (RubyNode) when.getBody().accept(this); - - final IfNode ifNode = new IfNode(context, sourceSection, conditionCastNode, thenNode, elseNode); - - // This if becomes the else for the next if - - elseNode = ifNode; - } - - return elseNode; - } - } - - @Override - public Object visitClassNode(org.jrubyparser.ast.ClassNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final String name = node.getCPath().getName(); - - final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true, - new UniqueMethodIdentifier()); - final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source); - - final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), node.getCPath().getName(), node.getBody()); - - /* - * See my note in visitDefnNode about where the class gets defined - the same applies here. - */ - - RubyNode superClass; - - if (node.getSuper() != null) { - superClass = (RubyNode) node.getSuper().accept(this); - } else { - superClass = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass()); - } - - final DefineOrGetClassNode defineOrGetClass = new DefineOrGetClassNode(context, sourceSection, name, getModuleToDefineModulesIn(sourceSection), superClass); - - return new OpenModuleNode(context, sourceSection, defineOrGetClass, definitionMethod); - } - - protected RubyNode getModuleToDefineModulesIn(SourceSection sourceSection) { - return new ClassNode(context, sourceSection, new SelfNode(context, sourceSection)); - } - - @Override - public Object visitClassVarAsgnNode(org.jrubyparser.ast.ClassVarAsgnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode receiver = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection)); - - final RubyNode rhs = (RubyNode) node.getValue().accept(this); - - return new WriteClassVariableNode(context, sourceSection, node.getName(), receiver, rhs); - } - - @Override - public Object visitClassVarDeclNode(org.jrubyparser.ast.ClassVarDeclNode node) { - return unimplemented(node); - } - - @Override - public Object visitClassVarNode(org.jrubyparser.ast.ClassVarNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - return new ReadClassVariableNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection)); - } - - @Override - public Object visitColon2Node(org.jrubyparser.ast.Colon2Node node) { - final RubyNode lhs = (RubyNode) node.getLeftNode().accept(this); - - return new UninitializedReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs); - } - - @Override - public Object visitColon3Node(org.jrubyparser.ast.Colon3Node node) { - // Colon3 means the root namespace, as in ::Foo - - final SourceSection sourceSection = translate(node.getPosition()); - - final ObjectLiteralNode root = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getMainObject()); - - return new UninitializedReadConstantNode(context, sourceSection, node.getName(), root); - } - - @Override - public Object visitConstDeclNode(org.jrubyparser.ast.ConstDeclNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection)); - - return new WriteConstantNode(context, sourceSection, node.getName(), classNode, (RubyNode) node.getValue().accept(this)); - } - - @Override - public Object visitConstNode(org.jrubyparser.ast.ConstNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - return new UninitializedReadConstantNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection)); - } - - @Override - public Object visitDAsgnNode(org.jrubyparser.ast.DAsgnNode node) { - return new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), node.getName(), node.getDepth(), node.getValue()).accept(this); - } - - @Override - public Object visitDRegxNode(org.jrubyparser.ast.DRegexpNode node) { - SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode stringNode = translateInterpolatedString(sourceSection, node.childNodes()); - - return StringToRegexpNodeFactory.create(context, sourceSection, stringNode); - } - - @Override - public Object visitDStrNode(org.jrubyparser.ast.DStrNode node) { - return translateInterpolatedString(translate(node.getPosition()), node.childNodes()); - } - - @Override - public Object visitDSymbolNode(org.jrubyparser.ast.DSymbolNode node) { - SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode stringNode = translateInterpolatedString(sourceSection, node.childNodes()); - - return StringToSymbolNodeFactory.create(context, sourceSection, stringNode); - } - - private RubyNode translateInterpolatedString(SourceSection sourceSection, List childNodes) { - final List children = new ArrayList<>(); - - for (org.jrubyparser.ast.Node child : childNodes) { - children.add((RubyNode) child.accept(this)); - } - - return new InterpolatedStringNode(context, sourceSection, children.toArray(new RubyNode[children.size()])); - } - - @Override - public Object visitDVarNode(org.jrubyparser.ast.DVarNode node) { - RubyNode readNode = environment.findLocalVarNode(node.getName(), translate(node.getPosition())); - - if (readNode == null) { - context.implementationMessage("can't find variable %s at %s, using noop", node.getName(), node.getPosition()); - readNode = new NilNode(context, translate(node.getPosition())); - } - - return readNode; - } - - @Override - public Object visitDXStrNode(org.jrubyparser.ast.DXStrNode node) { - SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode string = translateInterpolatedString(sourceSection, node.childNodes()); - - return new SystemNode(context, sourceSection, string); - } - - @Override - public Object visitDefinedNode(org.jrubyparser.ast.DefinedNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - org.jrubyparser.ast.Node expressionNode = node.getExpression(); - - while (expressionNode instanceof org.jrubyparser.ast.NewlineNode) { - expressionNode = ((org.jrubyparser.ast.NewlineNode) expressionNode).getNextNode(); - } - - final String name = nodeDefinedNames.get(expressionNode.getClass()); - - if (name != null) { - final StringLiteralNode literal = new StringLiteralNode(context, sourceSection, name); - return literal; - } - - return new DefinedNode(context, sourceSection, (RubyNode) node.getExpression().accept(this)); - } - - @Override - public Object visitDefnNode(org.jrubyparser.ast.DefnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection)); - return translateMethodDefinition(sourceSection, classNode, node.getName(), node.getArgs(), node.getBody()); - } - - @Override - public Object visitDefsNode(org.jrubyparser.ast.DefsNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode objectNode = (RubyNode) node.getReceiver().accept(this); - - final SingletonClassNode singletonClassNode = new SingletonClassNode(context, sourceSection, objectNode); - - return translateMethodDefinition(sourceSection, singletonClassNode, node.getName(), node.getArgs(), node.getBody()); - } - - private RubyNode translateMethodDefinition(SourceSection sourceSection, RubyNode classNode, String methodName, org.jrubyparser.ast.ArgsNode argsNode, org.jrubyparser.ast.Node bodyNode) { - final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true, - new UniqueMethodIdentifier()); - - // ownScopeForAssignments is the same for the defined method as the current one. - - final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source); - - final MethodDefinitionNode functionExprNode = methodCompiler.compileFunctionNode(sourceSection, methodName, argsNode, bodyNode); - - /* - * In the top-level, methods are defined in the class of the main object. This is - * counter-intuitive - I would have expected them to be defined in the singleton class. - * Apparently this is a design decision to make top-level methods sort of global. - * - * http://stackoverflow.com/questions/1761148/where-are-methods-defined-at-the-ruby-top-level - */ - - return new AddMethodNode(context, sourceSection, classNode, functionExprNode); - } - - @Override - public Object visitDotNode(org.jrubyparser.ast.DotNode node) { - final RubyNode begin = (RubyNode) node.getBegin().accept(this); - final RubyNode end = (RubyNode) node.getEnd().accept(this); - SourceSection sourceSection = translate(node.getPosition()); - - if (begin instanceof FixnumLiteralNode && end instanceof FixnumLiteralNode) { - final int beginValue = ((FixnumLiteralNode) begin).getValue(); - final int endValue = ((FixnumLiteralNode) end).getValue(); - - return new ObjectLiteralNode(context, sourceSection, new FixnumRange(context.getCoreLibrary().getRangeClass(), beginValue, endValue, node.isExclusive())); - } - // See RangeNode for why there is a node specifically for creating this one type - return RangeLiteralNodeFactory.create(context, sourceSection, node.isExclusive(), begin, end); - } - - @Override - public Object visitEncodingNode(org.jrubyparser.ast.EncodingNode node) { - return unimplemented(node); - } - - @Override - public Object visitEnsureNode(org.jrubyparser.ast.EnsureNode node) { - final RubyNode tryPart = (RubyNode) node.getBody().accept(this); - final RubyNode ensurePart = (RubyNode) node.getEnsure().accept(this); - return new EnsureNode(context, translate(node.getPosition()), tryPart, ensurePart); - } - - @Override - public Object visitEvStrNode(org.jrubyparser.ast.EvStrNode node) { - return node.getBody().accept(this); - } - - @Override - public Object visitFCallNode(org.jrubyparser.ast.FCallNode node) { - final org.jrubyparser.ast.Node receiver = new org.jrubyparser.ast.SelfNode(node.getPosition()); - final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, node.getName(), node.getArgs(), node.getIter()); - - return callNode.accept(this); - } - - @Override - public Object visitFalseNode(org.jrubyparser.ast.FalseNode node) { - return new BooleanLiteralNode(context, translate(node.getPosition()), false); - } - - @Override - public Object visitFixnumNode(org.jrubyparser.ast.FixnumNode node) { - final long value = node.getValue(); - - if (value >= RubyFixnum.MIN_VALUE && value <= RubyFixnum.MAX_VALUE) { - return new FixnumLiteralNode(context, translate(node.getPosition()), (int) value); - } - return new BignumLiteralNode(context, translate(node.getPosition()), BigInteger.valueOf(value)); - } - - @Override - public Object visitFlipNode(org.jrubyparser.ast.FlipNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final RubyNode begin = (RubyNode) node.getBegin().accept(this); - final RubyNode end = (RubyNode) node.getEnd().accept(this); - - final BooleanCastNode beginCast = BooleanCastNodeFactory.create(context, sourceSection, begin); - final BooleanCastNode endCast = BooleanCastNodeFactory.create(context, sourceSection, end); - final FlipFlopStateNode stateNode = createFlipFlopState(sourceSection, 0); - - return new FlipFlopNode(context, sourceSection, beginCast, endCast, stateNode, node.isExclusive()); - } - - protected FlipFlopStateNode createFlipFlopState(SourceSection sourceSection, int depth) { - final FrameSlot frameSlot = environment.declareVar(environment.allocateLocalTemp()); - environment.getFlipFlopStates().add(frameSlot); - - if (depth == 0) { - return new LocalFlipFlopStateNode(sourceSection, frameSlot); - } else { - return new LevelFlipFlopStateNode(sourceSection, depth, frameSlot); - } - } - - @Override - public Object visitFloatNode(org.jrubyparser.ast.FloatNode node) { - return new FloatLiteralNode(context, translate(node.getPosition()), node.getValue()); - } - - @Override - public Object visitForNode(org.jrubyparser.ast.ForNode node) { - /** - * A Ruby for-loop, such as: - * - *

-         * for x in y
-         *     z = x
-         *     puts z
-         * end
-         * 
- * - * naively desugars to: - * - *
-         * y.each do |x|
-         *     z = x
-         *     puts z
-         * end
-         * 
- * - * The main difference is that z is always going to be local to the scope outside the block, - * so it's a bit more like: - * - *
-         * z = nil unless z is already defined
-         * y.each do |x|
-         *    z = x
-         *    puts x
-         * end
-         * 
- * - * Which forces z to be defined in the correct scope. The parser already correctly calls z a - * local, but then that causes us a problem as if we're going to translate to a block we - * need a formal parameter - not a local variable. My solution to this is to add a - * temporary: - * - *
-         * z = nil unless z is already defined
-         * y.each do |temp|
-         *    x = temp
-         *    z = x
-         *    puts x
-         * end
-         * 
- * - * We also need that temp because the expression assigned in the for could be index - * assignment, multiple assignment, or whatever: - * - *
-         * for x[0] in y
-         *     z = x[0]
-         *     puts z
-         * end
-         * 
- * - * http://blog.grayproductions.net/articles/the_evils_of_the_for_loop - * http://stackoverflow.com/questions/3294509/for-vs-each-in-ruby - * - * The other complication is that normal locals should be defined in the enclosing scope, - * unlike a normal block. We do that by setting a flag on this translator object when we - * visit the new iter, translatingForStatement, which we recognise when visiting an iter - * node. - * - * Finally, note that JRuby's terminology is strange here. Normally 'iter' is a different - * term for a block. Here, JRuby calls the object being iterated over the 'iter'. - */ - - final String temp = environment.allocateLocalTemp(); - - final org.jrubyparser.ast.Node receiver = node.getIter(); - - /* - * The x in for x in ... is like the nodes in multiple assignment - it has a dummy RHS which - * we need to replace with our temp. Just like in multiple assignment this is really awkward - * with the JRuby AST. - */ - - final org.jrubyparser.ast.LocalVarNode readTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp); - final org.jrubyparser.ast.Node forVar = node.getVar(); - final org.jrubyparser.ast.Node assignTemp = setRHS(forVar, readTemp); - - final org.jrubyparser.ast.BlockNode bodyWithTempAssign = new org.jrubyparser.ast.BlockNode(node.getPosition()); - bodyWithTempAssign.add(assignTemp); - bodyWithTempAssign.add(node.getBody()); - - final org.jrubyparser.ast.ArgumentNode blockVar = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), temp); - final org.jrubyparser.ast.ListNode blockArgsPre = new org.jrubyparser.ast.ListNode(node.getPosition(), blockVar); - final org.jrubyparser.ast.ArgsNode blockArgs = new org.jrubyparser.ast.ArgsNode(node.getPosition(), blockArgsPre, null, null, null, null, null, null); - final org.jrubyparser.ast.IterNode block = new org.jrubyparser.ast.IterNode(node.getPosition(), blockArgs, node.getScope(), bodyWithTempAssign); - - final org.jrubyparser.ast.CallNode callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, "each", null, block); - - translatingForStatement = true; - final RubyNode translated = (RubyNode) callNode.accept(this); - translatingForStatement = false; - - return translated; - } - - private static org.jrubyparser.ast.Node setRHS(org.jrubyparser.ast.Node node, org.jrubyparser.ast.Node rhs) { - if (node instanceof org.jrubyparser.ast.LocalAsgnNode) { - final org.jrubyparser.ast.LocalAsgnNode localAsgnNode = (org.jrubyparser.ast.LocalAsgnNode) node; - return new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), localAsgnNode.getName(), 0, rhs); - } else if (node instanceof org.jrubyparser.ast.DAsgnNode) { - final org.jrubyparser.ast.DAsgnNode dAsgnNode = (org.jrubyparser.ast.DAsgnNode) node; - return new org.jrubyparser.ast.DAsgnNode(node.getPosition(), dAsgnNode.getName(), 0, rhs); - } else if (node instanceof org.jrubyparser.ast.MultipleAsgnNode) { - final org.jrubyparser.ast.MultipleAsgnNode multAsgnNode = (org.jrubyparser.ast.MultipleAsgnNode) node; - return new org.jrubyparser.ast.MultipleAsgnNode(node.getPosition(), multAsgnNode.getPre(), multAsgnNode.getRest(), multAsgnNode.getPost()); - } else if (node instanceof org.jrubyparser.ast.InstAsgnNode) { - final org.jrubyparser.ast.InstAsgnNode instAsgnNode = (org.jrubyparser.ast.InstAsgnNode) node; - return new org.jrubyparser.ast.InstAsgnNode(node.getPosition(), instAsgnNode.getName(), rhs); - } else if (node instanceof org.jrubyparser.ast.ClassVarAsgnNode) { - final org.jrubyparser.ast.ClassVarAsgnNode instAsgnNode = (org.jrubyparser.ast.ClassVarAsgnNode) node; - return new org.jrubyparser.ast.ClassVarAsgnNode(node.getPosition(), instAsgnNode.getName(), rhs); - } else if (node instanceof org.jrubyparser.ast.ConstDeclNode) { - final org.jrubyparser.ast.ConstDeclNode constDeclNode = (org.jrubyparser.ast.ConstDeclNode) node; - return new org.jrubyparser.ast.ConstDeclNode(node.getPosition(), constDeclNode.getName(), (org.jrubyparser.ast.INameNode) constDeclNode.getConstNode(), rhs); - } else { - throw new UnsupportedOperationException("Don't know how to set the RHS of a " + node.getClass().getName()); - } - } - - @Override - public Object visitGlobalAsgnNode(org.jrubyparser.ast.GlobalAsgnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final String name = "$" + node.getName(); - final RubyNode rhs = (RubyNode) node.getValue().accept(this); - - if (FRAME_LOCAL_GLOBAL_VARIABLES.contains(name)) { - context.implementationMessage("Assigning to frame local global variables not implemented at %s", node.getPosition()); - - return rhs; - } else { - final ObjectLiteralNode globalVariablesObjectNode = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject()); - - return new UninitializedWriteInstanceVariableNode(context, sourceSection, name, globalVariablesObjectNode, rhs); - } - } - - @Override - public Object visitGlobalVarNode(org.jrubyparser.ast.GlobalVarNode node) { - final String name = "$" + node.getName(); - final SourceSection sourceSection = translate(node.getPosition()); - - if (FRAME_LOCAL_GLOBAL_VARIABLES.contains(name)) { - // Assignment is implicit for many of these, so we need to declare when we use - - environment.declareVar(name); - - final RubyNode readNode = environment.findLocalVarNode(name, sourceSection); - - return readNode; - } else { - final ObjectLiteralNode globalVariablesObjectNode = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject()); - - return new UninitializedReadInstanceVariableNode(context, sourceSection, name, globalVariablesObjectNode); - } - } - - @Override - public Object visitHashNode(org.jrubyparser.ast.HashNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final List keys = new ArrayList<>(); - final List values = new ArrayList<>(); - - final org.jrubyparser.ast.ListNode entries = node.getListNode(); - - assert entries.size() % 2 == 0; - - for (int n = 0; n < entries.size(); n += 2) { - if (entries.get(n) == null) { - final NilNode nilNode = new NilNode(context, sourceSection); - keys.add(nilNode); - } else { - keys.add((RubyNode) entries.get(n).accept(this)); - } - - if (entries.get(n + 1) == null) { - final NilNode nilNode = new NilNode(context, sourceSection); - values.add(nilNode); - } else { - values.add((RubyNode) entries.get(n + 1).accept(this)); - } - } - - return new HashLiteralNode(translate(node.getPosition()), keys.toArray(new RubyNode[keys.size()]), values.toArray(new RubyNode[values.size()]), context); - } - - @Override - public Object visitIfNode(org.jrubyparser.ast.IfNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - org.jrubyparser.ast.Node thenBody = node.getThenBody(); - - if (thenBody == null) { - thenBody = new org.jrubyparser.ast.NilNode(node.getPosition()); - } - - org.jrubyparser.ast.Node elseBody = node.getElseBody(); - - if (elseBody == null) { - elseBody = new org.jrubyparser.ast.NilNode(node.getPosition()); - } - - RubyNode condition; - - if (node.getCondition() == null) { - condition = new NilNode(context, sourceSection); - } else { - condition = (RubyNode) node.getCondition().accept(this); - } - - final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition); - - final RubyNode thenBodyTranslated = (RubyNode) thenBody.accept(this); - final RubyNode elseBodyTranslated = (RubyNode) elseBody.accept(this); - - return new IfNode(context, sourceSection, conditionCast, thenBodyTranslated, elseBodyTranslated); - } - - @Override - public Object visitInstAsgnNode(org.jrubyparser.ast.InstAsgnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - final String nameWithoutSigil = node.getName(); - - final RubyNode receiver = new SelfNode(context, sourceSection); - - RubyNode rhs; - - if (node.getValue() == null) { - rhs = new DeadNode(context, sourceSection); - } else { - rhs = (RubyNode) node.getValue().accept(this); - } - - return new UninitializedWriteInstanceVariableNode(context, sourceSection, nameWithoutSigil, receiver, rhs); - } - - @Override - public Object visitInstVarNode(org.jrubyparser.ast.InstVarNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - final String nameWithoutSigil = node.getName(); - - final RubyNode receiver = new SelfNode(context, sourceSection); - - return new UninitializedReadInstanceVariableNode(context, sourceSection, nameWithoutSigil, receiver); - } - - @Override - public Object visitIterNode(org.jrubyparser.ast.IterNode node) { - /* - * In a block we do NOT allocate a new return ID - returns will return from the method, not - * the block (in the general case, see Proc and the difference between Proc and Lambda for - * specifics). - */ - - final boolean hasOwnScope = !translatingForStatement; - - // Unset this flag for any for any blocks within the for statement's body - - translatingForStatement = false; - - final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getReturnID(), hasOwnScope, false, - new UniqueMethodIdentifier()); - final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, true, source); - - org.jrubyparser.ast.ArgsNode argsNode; - - if (node.getVar() instanceof org.jrubyparser.ast.ArgsNode) { - argsNode = (org.jrubyparser.ast.ArgsNode) node.getVar(); - } else if (node.getVar() instanceof org.jrubyparser.ast.DAsgnNode) { - final org.jrubyparser.ast.ArgumentNode arg = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), ((org.jrubyparser.ast.DAsgnNode) node.getVar()).getName()); - final org.jrubyparser.ast.ListNode preArgs = new org.jrubyparser.ast.ArrayNode(node.getPosition(), arg); - argsNode = new org.jrubyparser.ast.ArgsNode(node.getPosition(), preArgs, null, null, null, null, null, null); - } else if (node.getVar() == null) { - argsNode = null; - } else { - throw new UnsupportedOperationException(); - } - - return methodCompiler.compileFunctionNode(translate(node.getPosition()), "(block)", argsNode, node.getBody()); - } - - @Override - public Object visitLiteralNode(org.jrubyparser.ast.LiteralNode node) { - return unimplemented(node); - } - - @Override - public Object visitLocalAsgnNode(org.jrubyparser.ast.LocalAsgnNode node) { - - final SourceSection sourceSection = translate(node.getPosition()); - - if (environment.getNeverAssignInParentScope()) { - environment.declareVar(node.getName()); - } - - RubyNode lhs = environment.findLocalVarNode(node.getName(), sourceSection); - - if (lhs == null) { - if (environment.hasOwnScopeForAssignments()) { - environment.declareVar(node.getName()); - } - - TranslatorEnvironment environmentToDeclareIn = environment; - - while (!environmentToDeclareIn.hasOwnScopeForAssignments()) { - environmentToDeclareIn = environmentToDeclareIn.getParent(); - } - - environmentToDeclareIn.declareVar(node.getName()); - lhs = environment.findLocalVarNode(node.getName(), sourceSection); - - if (lhs == null) { - throw new RuntimeException("shoudln't be here"); - } - } - - RubyNode rhs; - - if (node.getValue() == null) { - rhs = new DeadNode(context, sourceSection); - } else { - rhs = (RubyNode) node.getValue().accept(this); - } - - RubyNode translated = ((ReadNode) lhs).makeWriteNode(rhs); - - final UniqueMethodIdentifier methodIdentifier = environment.findMethodForLocalVar(node.getName()); - - return instrumenter.instrumentAsLocalAssignment(translated, methodIdentifier, node.getName()); - } - - @Override - public Object visitLocalVarNode(org.jrubyparser.ast.LocalVarNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final String name = node.getName(); - - RubyNode readNode = environment.findLocalVarNode(name, sourceSection); - - if (readNode == null) { - context.implementationMessage("Local variable found by parser but not by translator - " + name + " at " + node.getPosition()); - readNode = environment.findLocalVarNode(environment.allocateLocalTemp(), sourceSection); - } - - return readNode; - } - - @Override - public Object visitMatch2Node(org.jrubyparser.ast.Match2Node node) { - final org.jrubyparser.ast.Node argsNode = buildArrayNode(node.getPosition(), node.getValue()); - final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), "=~", argsNode, null); - return callNode.accept(this); - } - - @Override - public Object visitMatch3Node(org.jrubyparser.ast.Match3Node node) { - final org.jrubyparser.ast.Node argsNode = buildArrayNode(node.getPosition(), node.getValue()); - final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), "=~", argsNode, null); - return callNode.accept(this); - } - - @Override - public Object visitMatchNode(org.jrubyparser.ast.MatchNode node) { - return unimplemented(node); - } - - @Override - public Object visitModuleNode(org.jrubyparser.ast.ModuleNode node) { - // See visitClassNode - - final SourceSection sourceSection = translate(node.getPosition()); - - final String name = node.getCPath().getName(); - - final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true, - new UniqueMethodIdentifier()); - final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source); - - final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), node.getCPath().getName(), node.getBody()); - - final DefineOrGetModuleNode defineModuleNode = new DefineOrGetModuleNode(context, sourceSection, name, getModuleToDefineModulesIn(sourceSection)); - - return new OpenModuleNode(context, sourceSection, defineModuleNode, definitionMethod); - } - - @Override - public Object visitMultipleAsgnNode(org.jrubyparser.ast.MultipleAsgnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final org.jrubyparser.ast.ArrayNode preArray = (org.jrubyparser.ast.ArrayNode) node.getPre(); - final org.jrubyparser.ast.Node rhs = node.getValue(); - - RubyNode rhsTranslated; - - if (rhs == null) { - context.implementationMessage("warning: no RHS for multiple assignment - using noop"); - rhsTranslated = new NilNode(context, sourceSection); - } else { - rhsTranslated = (RubyNode) rhs.accept(this); - } - - /* - * One very common case is to do - * - * a, b = c, d - */ - - if (preArray != null && node.getPost() == null && node.getRest() == null && rhsTranslated instanceof UninitialisedArrayLiteralNode && - ((UninitialisedArrayLiteralNode) rhsTranslated).getValues().length == preArray.size()) { - /* - * We can deal with this common case be rewriting as - * - * temp1 = c; temp2 = d; a = temp1; b = temp2 - * - * We can't just do - * - * a = c; b = d - * - * As we don't know if d depends on the original value of a. - * - * We also need to return an array [c, d], but we make that result elidable so it isn't - * executed if it isn't actually demanded. - */ - - final RubyNode[] rhsValues = ((UninitialisedArrayLiteralNode) rhsTranslated).getValues(); - final int assignedValuesCount = preArray.size(); - - final RubyNode[] sequence = new RubyNode[assignedValuesCount * 2]; - - final RubyNode[] tempValues = new RubyNode[assignedValuesCount]; - - for (int n = 0; n < assignedValuesCount; n++) { - final String tempName = environment.allocateLocalTemp(); - final RubyNode readTemp = environment.findLocalVarNode(tempName, sourceSection); - final RubyNode assignTemp = ((ReadNode) readTemp).makeWriteNode(rhsValues[n]); - final RubyNode assignFinalValue = translateDummyAssignment(preArray.get(n), readTemp); - - sequence[n] = assignTemp; - sequence[assignedValuesCount + n] = assignFinalValue; - - tempValues[n] = readTemp; - } - - final RubyNode blockNode = new SequenceNode(context, sourceSection, sequence); - - final UninitialisedArrayLiteralNode arrayNode = new UninitialisedArrayLiteralNode(context, sourceSection, tempValues); - - final ElidableResultNode elidableResult = new ElidableResultNode(context, sourceSection, blockNode, arrayNode); - - return elidableResult; - } else if (preArray != null) { - /* - * The other simple case is - * - * a, b, c = x - * - * If x is an array, then it's - * - * a[0] = x[0] etc - * - * If x isn't an array then it's - * - * a, b, c = [x, nil, nil] - * - * Which I believe is the same effect as - * - * a, b, c, = *x - * - * So we insert the splat cast node, even though it isn't there. - */ - - /* - * Create a temp for the array. - */ - - final String tempName = environment.allocateLocalTemp(); - - /* - * Create a sequence of instructions, with the first being the literal array assigned to - * the temp. - */ - - final List sequence = new ArrayList<>(); - - final RubyNode splatCastNode = SplatCastNodeFactory.create(context, sourceSection, rhsTranslated); - - final RubyNode writeTemp = ((ReadNode) environment.findLocalVarNode(tempName, sourceSection)).makeWriteNode(splatCastNode); - - sequence.add(writeTemp); - - /* - * Then index the temp array for each assignment on the LHS. - */ - - for (int n = 0; n < preArray.size(); n++) { - final ArrayIndexNode assignedValue = ArrayIndexNodeFactory.create(context, sourceSection, n, environment.findLocalVarNode(tempName, sourceSection)); - - sequence.add(translateDummyAssignment(preArray.get(n), assignedValue)); - } - - if (node.getRest() != null) { - final ArrayRestNode assignedValue = new ArrayRestNode(context, sourceSection, preArray.size(), environment.findLocalVarNode(tempName, sourceSection)); - - sequence.add(translateDummyAssignment(node.getRest(), assignedValue)); - } - - return new SequenceNode(context, sourceSection, sequence.toArray(new RubyNode[sequence.size()])); - } else if (node.getPre() == null && node.getPost() == null && node.getRest() instanceof org.jrubyparser.ast.StarNode) { - return rhsTranslated; - } else if (node.getPre() == null && node.getPost() == null && node.getRest() != null && rhs != null && !(rhs instanceof org.jrubyparser.ast.ArrayNode)) { - /* - * *a = b - * - * >= 1.8, this seems to be the same as: - * - * a = *b - */ - - final RubyNode restTranslated = ((RubyNode) node.getRest().accept(this)).getNonProxyNode(); - - /* - * Sometimes rest is a corrupt write with no RHS, like in other multiple assignments, - * and sometimes it is already a read. - */ - - ReadNode restRead; - - if (restTranslated instanceof ReadNode) { - restRead = (ReadNode) restTranslated; - } else if (restTranslated instanceof WriteNode) { - restRead = (ReadNode) ((WriteNode) restTranslated).makeReadNode(); - } else { - throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition()); - } - - final SplatCastNode rhsSplatCast = SplatCastNodeFactory.create(context, sourceSection, rhsTranslated); - - return restRead.makeWriteNode(rhsSplatCast); - } else if (node.getPre() == null && node.getPost() == null && node.getRest() != null && rhs != null && rhs instanceof org.jrubyparser.ast.ArrayNode) { - /* - * *a = [b, c] - * - * This seems to be the same as: - * - * a = [b, c] - */ - - final RubyNode restTranslated = ((RubyNode) node.getRest().accept(this)).getNonProxyNode(); - - /* - * Sometimes rest is a corrupt write with no RHS, like in other multiple assignments, - * and sometimes it is already a read. - */ - - ReadNode restRead; - - if (restTranslated instanceof ReadNode) { - restRead = (ReadNode) restTranslated; - } else if (restTranslated instanceof WriteNode) { - restRead = (ReadNode) ((WriteNode) restTranslated).makeReadNode(); - } else { - throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition()); - } - - return restRead.makeWriteNode(rhsTranslated); - } else { - throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition()); - } - } - - private RubyNode translateDummyAssignment(org.jrubyparser.ast.Node dummyAssignment, RubyNode rhs) { - final SourceSection sourceSection = translate(dummyAssignment.getPosition()); - - /* - * This is tricky. To represent the RHS of a multiple assignment they use corrupt assignment - * values, in some cases with no value to be assigned, and in other cases with a dummy - * value. We can't visit them normally, as they're corrupt. We can't just modify them to - * have our RHS, as that's a node in our AST, not theirs. We can't use a dummy value in - * their AST because I can't add new visitors to this interface. - */ - - RubyNode translated; - - if (dummyAssignment instanceof org.jrubyparser.ast.LocalAsgnNode) { - /* - * They have a dummy NilImplicitNode as the RHS. Translate, convert to read, convert to - * write which allows us to set the RHS. - */ - - final WriteNode dummyTranslated = (WriteNode) ((RubyNode) dummyAssignment.accept(this)).getNonProxyNode(); - translated = ((ReadNode) dummyTranslated.makeReadNode()).makeWriteNode(rhs); - } else if (dummyAssignment instanceof org.jrubyparser.ast.InstAsgnNode) { - /* - * Same as before, just a different type of assignment. - */ - - final WriteInstanceVariableNode dummyTranslated = (WriteInstanceVariableNode) dummyAssignment.accept(this); - translated = dummyTranslated.makeReadNode().makeWriteNode(rhs); - } else if (dummyAssignment instanceof org.jrubyparser.ast.AttrAssignNode) { - /* - * They've given us an AttrAssignNode with the final argument, the assigned value, - * missing. If we translate that we'll get foo.[]=(index), so missing the value. To - * solve we have a special version of the visitCallNode that allows us to pass another - * already translated argument, visitCallNodeExtraArgument. However, we initially have - * an AttrAssignNode, so we also need a special version of that. - */ - - final org.jrubyparser.ast.AttrAssignNode dummyAttrAssignment = (org.jrubyparser.ast.AttrAssignNode) dummyAssignment; - translated = visitAttrAssignNodeExtraArgument(dummyAttrAssignment, rhs); - } else if (dummyAssignment instanceof org.jrubyparser.ast.DAsgnNode) { - final RubyNode dummyTranslated = (RubyNode) dummyAssignment.accept(this); - - if (dummyTranslated.getNonProxyNode() instanceof WriteLevelVariableNode) { - translated = ((ReadNode) ((WriteLevelVariableNode) dummyTranslated.getNonProxyNode()).makeReadNode()).makeWriteNode(rhs); - } else { - translated = ((ReadNode) ((WriteLocalVariableNode) dummyTranslated.getNonProxyNode()).makeReadNode()).makeWriteNode(rhs); - } - } else { - translated = ((ReadNode) environment.findLocalVarNode(environment.allocateLocalTemp(), sourceSection)).makeWriteNode(rhs); - } - - return translated; - } - - @Override - public Object visitNewlineNode(org.jrubyparser.ast.NewlineNode node) { - RubyNode translated = (RubyNode) node.getNextNode().accept(this); - return instrumenter.instrumentAsStatement(translated); - } - - @Override - public Object visitNextNode(org.jrubyparser.ast.NextNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode resultNode; - - if (node.getValueNode() == null) { - resultNode = new NilNode(context, sourceSection); - } else { - resultNode = (RubyNode) node.getValueNode().accept(this); - } - - return new NextNode(context, sourceSection, resultNode); - } - - @Override - public Object visitNilNode(org.jrubyparser.ast.NilNode node) { - return new NilNode(context, translate(node.getPosition())); - } - - @Override - public Object visitNotNode(org.jrubyparser.ast.NotNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final BooleanCastNode booleanCastNode = BooleanCastNodeFactory.create(context, sourceSection, (RubyNode) node.getCondition().accept(this)); - - return new NotNode(context, sourceSection, booleanCastNode); - } - - @Override - public Object visitNthRefNode(org.jrubyparser.ast.NthRefNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final String name = "$" + node.getMatchNumber(); - - RubyNode readLocal = environment.findLocalVarNode(name, sourceSection); - - if (readLocal == null) { - environment.declareVar(name); - readLocal = environment.findLocalVarNode(name, sourceSection); - } - - return readLocal; - } - - @Override - public Object visitOpAsgnAndNode(org.jrubyparser.ast.OpAsgnAndNode node) { - final org.jrubyparser.ast.Node lhs = node.getFirst(); - final org.jrubyparser.ast.Node rhs = node.getSecond(); - - return AndNodeFactory.create(context, translate(node.getPosition()), (RubyNode) lhs.accept(this), (RubyNode) rhs.accept(this)); - } - - @Override - public Object visitOpAsgnNode(org.jrubyparser.ast.OpAsgnNode node) { - /* - * We're going to de-sugar a.foo += c into a.foo = a.foo + c. Note that we can't evaluate a - * more than once, so we put it into a temporary, and we're doing something more like: - * - * temp = a; temp.foo = temp.foo + c - */ - - final String temp = environment.allocateLocalTemp(); - final org.jrubyparser.ast.Node writeReceiverToTemp = new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), temp, 0, node.getReceiver()); - final org.jrubyparser.ast.Node readReceiverFromTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp); - - final org.jrubyparser.ast.Node readMethod = new org.jrubyparser.ast.CallNode(node.getPosition(), readReceiverFromTemp, node.getVariableName(), null); - final org.jrubyparser.ast.Node operation = new org.jrubyparser.ast.CallNode(node.getPosition(), readMethod, node.getOperatorName(), buildArrayNode(node.getPosition(), node.getValue())); - final org.jrubyparser.ast.Node writeMethod = new org.jrubyparser.ast.CallNode(node.getPosition(), readReceiverFromTemp, node.getVariableName() + "=", buildArrayNode(node.getPosition(), - operation)); - - final org.jrubyparser.ast.BlockNode block = new org.jrubyparser.ast.BlockNode(node.getPosition()); - block.add(writeReceiverToTemp); - block.add(writeMethod); - - return block.accept(this); - } - - @Override - public Object visitOpAsgnOrNode(org.jrubyparser.ast.OpAsgnOrNode node) { - /* - * De-sugar x ||= y into x || x = y. No repeated evaluations there so it's easy. It's also - * basically how jruby-parser represents it already. We'll do it directly, rather than via - * another JRuby AST node. - */ - - final org.jrubyparser.ast.Node lhs = node.getFirst(); - final org.jrubyparser.ast.Node rhs = node.getSecond(); - - return OrNodeFactory.create(context, translate(node.getPosition()), (RubyNode) lhs.accept(this), (RubyNode) rhs.accept(this)); - } - - @Override - public Object visitOpElementAsgnNode(org.jrubyparser.ast.OpElementAsgnNode node) { - /* - * We're going to de-sugar a[b] += c into a[b] = a[b] + c. See discussion in - * visitOpAsgnNode. - */ - - org.jrubyparser.ast.Node index; - - if (node.getArgs() == null) { - index = null; - } else { - index = node.getArgs().childNodes().get(0); - } - - final org.jrubyparser.ast.Node operand = node.getValue(); - - final String temp = environment.allocateLocalTemp(); - final org.jrubyparser.ast.Node writeArrayToTemp = new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), temp, 0, node.getReceiver()); - final org.jrubyparser.ast.Node readArrayFromTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp); - - final org.jrubyparser.ast.Node arrayRead = new org.jrubyparser.ast.CallNode(node.getPosition(), readArrayFromTemp, "[]", buildArrayNode(node.getPosition(), index)); - - final String op = node.getOperatorName(); - - org.jrubyparser.ast.Node operation = null; - - if (op.equals("||")) { - operation = new org.jrubyparser.ast.OrNode(node.getPosition(), arrayRead, operand); - } else if (op.equals("&&")) { - operation = new org.jrubyparser.ast.AndNode(node.getPosition(), arrayRead, operand); - } else { - operation = new org.jrubyparser.ast.CallNode(node.getPosition(), arrayRead, node.getOperatorName(), buildArrayNode(node.getPosition(), operand)); - } - - final org.jrubyparser.ast.Node arrayWrite = new org.jrubyparser.ast.CallNode(node.getPosition(), readArrayFromTemp, "[]=", buildArrayNode(node.getPosition(), index, operation)); - - final org.jrubyparser.ast.BlockNode block = new org.jrubyparser.ast.BlockNode(node.getPosition()); - block.add(writeArrayToTemp); - block.add(arrayWrite); - - return block.accept(this); - } - - private static org.jrubyparser.ast.ArrayNode buildArrayNode(org.jrubyparser.SourcePosition sourcePosition, org.jrubyparser.ast.Node first, org.jrubyparser.ast.Node... rest) { - if (first == null) { - return new org.jrubyparser.ast.ArrayNode(sourcePosition); - } - - final org.jrubyparser.ast.ArrayNode array = new org.jrubyparser.ast.ArrayNode(sourcePosition, first); - - for (org.jrubyparser.ast.Node node : rest) { - array.add(node); - } - - return array; - } - - @Override - public Object visitOrNode(org.jrubyparser.ast.OrNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode x; - - if (node.getFirst() == null) { - x = new NilNode(context, sourceSection); - } else { - x = (RubyNode) node.getFirst().accept(this); - } - - RubyNode y; - - if (node.getSecond() == null) { - y = new NilNode(context, sourceSection); - } else { - y = (RubyNode) node.getSecond().accept(this); - } - - return OrNodeFactory.create(context, sourceSection, x, y); - } - - @Override - public Object visitPostExeNode(org.jrubyparser.ast.PostExeNode node) { - return unimplemented(node); - } - - @Override - public Object visitPreExeNode(org.jrubyparser.ast.PreExeNode node) { - return unimplemented(node); - } - - @Override - public Object visitRedoNode(org.jrubyparser.ast.RedoNode node) { - return new RedoNode(context, translate(node.getPosition())); - } - - @Override - public Object visitRegexpNode(org.jrubyparser.ast.RegexpNode node) { - RubyRegexp regexp; - - try { - final String patternText = node.getValue(); - - int flags = Pattern.MULTILINE | Pattern.UNIX_LINES; - - final org.jrubyparser.RegexpOptions options = node.getOptions(); - - if (options.isIgnorecase()) { - flags |= Pattern.CASE_INSENSITIVE; - } - - if (options.isMultiline()) { - // TODO(cs): isn't this the default? - flags |= Pattern.MULTILINE; - } - - final Pattern pattern = Pattern.compile(patternText, flags); - - regexp = new RubyRegexp(context.getCoreLibrary().getRegexpClass(), pattern); - } catch (PatternSyntaxException e) { - context.implementationMessage("failed to parse Ruby regexp " + node.getValue() + " as Java regexp - replacing with ."); - regexp = new RubyRegexp(context.getCoreLibrary().getRegexpClass(), "."); - } - - final ObjectLiteralNode literalNode = new ObjectLiteralNode(context, translate(node.getPosition()), regexp); - return literalNode; - } - - @Override - public Object visitRescueBodyNode(org.jrubyparser.ast.RescueBodyNode node) { - return unimplemented(node); - } - - @Override - public Object visitRescueNode(org.jrubyparser.ast.RescueNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode tryPart; - - if (node.getBody() != null) { - tryPart = (RubyNode) node.getBody().accept(this); - } else { - tryPart = new NilNode(context, sourceSection); - } - - final List rescueNodes = new ArrayList<>(); - - org.jrubyparser.ast.RescueBodyNode rescueBody = node.getRescue(); - - while (rescueBody != null) { - if (rescueBody.getExceptions() != null) { - if (rescueBody.getExceptions() instanceof org.jrubyparser.ast.ArrayNode) { - final List exceptionNodes = ((org.jrubyparser.ast.ArrayNode) rescueBody.getExceptions()).childNodes(); - - final RubyNode[] handlingClasses = new RubyNode[exceptionNodes.size()]; - - for (int n = 0; n < handlingClasses.length; n++) { - handlingClasses[n] = (RubyNode) exceptionNodes.get(n).accept(this); - } - - RubyNode translatedBody; - - if (rescueBody.getBody() == null) { - translatedBody = new NilNode(context, sourceSection); - } else { - translatedBody = (RubyNode) rescueBody.getBody().accept(this); - } - - final RescueClassesNode rescueNode = new RescueClassesNode(context, sourceSection, handlingClasses, translatedBody); - rescueNodes.add(rescueNode); - } else if (rescueBody.getExceptions() instanceof org.jrubyparser.ast.SplatNode) { - final org.jrubyparser.ast.SplatNode splat = (org.jrubyparser.ast.SplatNode) rescueBody.getExceptions(); - - RubyNode splatTranslated; - - if (splat.getValue() == null) { - splatTranslated = new NilNode(context, sourceSection); - } else { - splatTranslated = (RubyNode) splat.getValue().accept(this); - } - - RubyNode bodyTranslated; - - if (rescueBody.getBody() == null) { - bodyTranslated = new NilNode(context, sourceSection); - } else { - bodyTranslated = (RubyNode) rescueBody.getBody().accept(this); - } - - final RescueSplatNode rescueNode = new RescueSplatNode(context, sourceSection, splatTranslated, bodyTranslated); - rescueNodes.add(rescueNode); - } else { - unimplemented(node); - } - } else { - RubyNode bodyNode; - - if (rescueBody.getBody() == null) { - bodyNode = new NilNode(context, sourceSection); - } else { - bodyNode = (RubyNode) rescueBody.getBody().accept(this); - } - - final RescueAnyNode rescueNode = new RescueAnyNode(context, sourceSection, bodyNode); - rescueNodes.add(rescueNode); - } - - rescueBody = rescueBody.getOptRescue(); - } - - RubyNode elsePart; - - if (node.getElse() != null) { - elsePart = (RubyNode) node.getElse().accept(this); - } else { - elsePart = new NilNode(context, sourceSection); - } - - return new TryNode(context, sourceSection, tryPart, rescueNodes.toArray(new RescueNode[rescueNodes.size()]), elsePart); - } - - @Override - public Object visitRestArgNode(org.jrubyparser.ast.RestArgNode node) { - return unimplemented(node); - } - - @Override - public Object visitRetryNode(org.jrubyparser.ast.RetryNode node) { - return new RetryNode(context, translate(node.getPosition())); - } - - @Override - public Object visitReturnNode(org.jrubyparser.ast.ReturnNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode translatedChild; - - if (node.getValue() == null) { - translatedChild = new NilNode(context, sourceSection); - } else { - translatedChild = (RubyNode) node.getValue().accept(this); - } - - return new ReturnNode(context, sourceSection, environment.getReturnID(), translatedChild); - } - - @Override - public Object visitRootNode(org.jrubyparser.ast.RootNode node) { - return unimplemented(node); - } - - @Override - public Object visitSClassNode(org.jrubyparser.ast.SClassNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true, - new UniqueMethodIdentifier()); - final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source); - - final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), "singleton", node.getBody()); - - final RubyNode receiverNode = (RubyNode) node.getReceiver().accept(this); - - final SingletonClassNode singletonClassNode = new SingletonClassNode(context, sourceSection, receiverNode); - - return new OpenModuleNode(context, sourceSection, singletonClassNode, definitionMethod); - } - - @Override - public Object visitSValueNode(org.jrubyparser.ast.SValueNode node) { - return node.getValue().accept(this); - } - - @Override - public Object visitSelfNode(org.jrubyparser.ast.SelfNode node) { - return new SelfNode(context, translate(node.getPosition())); - } - - @Override - public Object visitSplatNode(org.jrubyparser.ast.SplatNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode value; - - if (node.getValue() == null) { - value = new NilNode(context, sourceSection); - } else { - value = (RubyNode) node.getValue().accept(this); - } - - return SplatCastNodeFactory.create(context, sourceSection, value); - } - - @Override - public Object visitStrNode(org.jrubyparser.ast.StrNode node) { - return new StringLiteralNode(context, translate(node.getPosition()), node.getValue()); - } - - @Override - public Object visitSuperNode(org.jrubyparser.ast.SuperNode node) { - return unimplemented(node); - } - - @Override - public Object visitSymbolNode(org.jrubyparser.ast.SymbolNode node) { - return new ObjectLiteralNode(context, translate(node.getPosition()), new RubySymbol(context.getCoreLibrary().getSymbolClass(), node.getName())); - } - - @Override - public Object visitToAryNode(org.jrubyparser.ast.ToAryNode node) { - return unimplemented(node); - } - - @Override - public Object visitTrueNode(org.jrubyparser.ast.TrueNode node) { - return new BooleanLiteralNode(context, translate(node.getPosition()), true); - } - - @Override - public Object visitUndefNode(org.jrubyparser.ast.UndefNode node) { - return unimplemented(node); - } - - @Override - public Object visitUntilNode(org.jrubyparser.ast.UntilNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode condition; - - if (node.getCondition() == null) { - condition = new NilNode(context, sourceSection); - } else { - condition = (RubyNode) node.getCondition().accept(this); - } - - final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition); - final NotNode conditionCastNot = new NotNode(context, sourceSection, conditionCast); - final BooleanCastNode conditionCastNotCast = BooleanCastNodeFactory.create(context, sourceSection, conditionCastNot); - - final RubyNode body = (RubyNode) node.getBody().accept(this); - - return new WhileNode(context, sourceSection, conditionCastNotCast, body); - } - - @Override - public Object visitVAliasNode(org.jrubyparser.ast.VAliasNode node) { - return unimplemented(node); - } - - @Override - public Object visitVCallNode(org.jrubyparser.ast.VCallNode node) { - final org.jrubyparser.ast.Node receiver = new org.jrubyparser.ast.SelfNode(node.getPosition()); - final org.jrubyparser.ast.Node args = null; - final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, node.getName(), args); - - return callNode.accept(this); - } - - @Override - public Object visitWhenNode(org.jrubyparser.ast.WhenNode node) { - return unimplemented(node); - } - - @Override - public Object visitWhileNode(org.jrubyparser.ast.WhileNode node) { - final SourceSection sourceSection = translate(node.getPosition()); - - RubyNode condition; - - if (node.getCondition() == null) { - condition = new NilNode(context, sourceSection); - } else { - condition = (RubyNode) node.getCondition().accept(this); - } - - final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition); - - final RubyNode body = (RubyNode) node.getBody().accept(this); - - return new WhileNode(context, sourceSection, conditionCast, body); - } - - @Override - public Object visitXStrNode(org.jrubyparser.ast.XStrNode node) { - SourceSection sourceSection = translate(node.getPosition()); - - final StringLiteralNode literal = new StringLiteralNode(context, sourceSection, node.getValue()); - - return new SystemNode(context, sourceSection, literal); - } - - @Override - public Object visitYieldNode(org.jrubyparser.ast.YieldNode node) { - final List arguments = new ArrayList<>(); - - final org.jrubyparser.ast.Node argsNode = node.getArgs(); - - if (argsNode != null) { - if (argsNode instanceof org.jrubyparser.ast.ListNode) { - arguments.addAll(((org.jrubyparser.ast.ListNode) node.getArgs()).childNodes()); - } else { - arguments.add(node.getArgs()); - } - } - - final List argumentsTranslated = new ArrayList<>(); - - for (org.jrubyparser.ast.Node argument : arguments) { - argumentsTranslated.add((RubyNode) argument.accept(this)); - } - - final RubyNode[] argumentsTranslatedArray = argumentsTranslated.toArray(new RubyNode[argumentsTranslated.size()]); - - return new YieldNode(context, translate(node.getPosition()), argumentsTranslatedArray); - } - - @Override - public Object visitZArrayNode(org.jrubyparser.ast.ZArrayNode node) { - final RubyNode[] values = new RubyNode[0]; - - return new UninitialisedArrayLiteralNode(context, translate(node.getPosition()), values); - } - - @Override - public Object visitZSuperNode(org.jrubyparser.ast.ZSuperNode node) { - return unimplemented(node); - } - - public Object visitArgumentNode(org.jrubyparser.ast.ArgumentNode node) { - return unimplemented(node); - } - - public Object visitCommentNode(org.jrubyparser.ast.CommentNode node) { - return unimplemented(node); - } - - public Object visitKeywordArgNode(org.jrubyparser.ast.KeywordArgNode node) { - return unimplemented(node); - } - - public Object visitKeywordRestArgNode(org.jrubyparser.ast.KeywordRestArgNode node) { - return unimplemented(node); - } - - public Object visitListNode(org.jrubyparser.ast.ListNode node) { - return unimplemented(node); - } - - public Object visitMethodNameNode(org.jrubyparser.ast.MethodNameNode node) { - return unimplemented(node); - } - - public Object visitOptArgNode(org.jrubyparser.ast.OptArgNode node) { - return unimplemented(node); - } - - public Object visitSyntaxNode(org.jrubyparser.ast.SyntaxNode node) { - return unimplemented(node); - } - - public Object visitImplicitNilNode(org.jrubyparser.ast.ImplicitNilNode node) { - return new NilNode(context, translate(node.getPosition())); - } - - public Object visitLambdaNode(org.jrubyparser.ast.LambdaNode node) { - // TODO(cs): code copied and modified from visitIterNode - extract common - - final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getReturnID(), false, false, new UniqueMethodIdentifier()); - final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source); - - org.jrubyparser.ast.ArgsNode argsNode; - - if (node.getVar() instanceof org.jrubyparser.ast.ArgsNode) { - argsNode = (org.jrubyparser.ast.ArgsNode) node.getVar(); - } else if (node.getVar() instanceof org.jrubyparser.ast.DAsgnNode) { - final org.jrubyparser.ast.ArgumentNode arg = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), ((org.jrubyparser.ast.DAsgnNode) node.getVar()).getName()); - final org.jrubyparser.ast.ListNode preArgs = new org.jrubyparser.ast.ArrayNode(node.getPosition(), arg); - argsNode = new org.jrubyparser.ast.ArgsNode(node.getPosition(), preArgs, null, null, null, null, null, null); - } else if (node.getVar() == null) { - argsNode = null; - } else { - throw new UnsupportedOperationException(); - } - - final MethodDefinitionNode definitionNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), "(lambda)", argsNode, node.getBody()); - - return new LambdaNode(context, translate(node.getPosition()), definitionNode); - } - - public Object visitUnaryCallNode(org.jrubyparser.ast.UnaryCallNode node) { - final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), node.getName(), null, null); - return callNode.accept(this); - } - - protected Object unimplemented(org.jrubyparser.ast.Node node) { - context.implementationMessage("warning: %s at %s does nothing", node, node.getPosition()); - return new NilNode(context, translate(node.getPosition())); - } - - protected SourceSection translate(final org.jrubyparser.SourcePosition sourcePosition) { - try { - // TODO(cs): get an identifier - final String identifier = "(identifier)"; - - // TODO(cs): work out the start column - final int startColumn = -1; - - final int charLength = sourcePosition.getEndOffset() - sourcePosition.getStartOffset(); - - return new DefaultSourceSection(source, identifier, sourcePosition.getStartLine() + 1, startColumn, sourcePosition.getStartOffset(), charLength); - } catch (UnsupportedOperationException e) { - // In some circumstances JRuby can't tell you what the position is - return translate(new org.jrubyparser.SourcePosition("(unknown)", 0, 0)); - } - } - - protected SequenceNode initFlipFlopStates(SourceSection sourceSection) { - final RubyNode[] initNodes = new RubyNode[environment.getFlipFlopStates().size()]; - - for (int n = 0; n < initNodes.length; n++) { - initNodes[n] = new InitFlipFlopSlotNode(context, sourceSection, environment.getFlipFlopStates().get(n)); - } - - return new SequenceNode(context, sourceSection, initNodes); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2013 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.parser; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.instrument.*; -import com.oracle.truffle.ruby.nodes.methods.locals.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -public class TranslatorEnvironment { - - private final RubyContext context; - - private final FrameDescriptor frameDescriptor; - - private final List preParameters = new ArrayList<>(); - - private final List optionalParameters = new ArrayList<>(); - private final Map optionalParametersDefaultValues = new HashMap<>(); - - private final List postParameters = new ArrayList<>(); - - private final List flipFlopStates = new ArrayList<>(); - - private FrameSlot restParameter = null; - - private FrameSlot blockParameter = null; - - private JRubyParser parser; - private final long returnID; - - private final boolean ownScopeForAssignments; - private final boolean neverAssignInParentScope; - - protected final TranslatorEnvironment parent; - private String methodName = ""; - private boolean needsDeclarationFrame = false; - private UniqueMethodIdentifier methodIdentifier; - - private int tempIndex; - - public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, FrameDescriptor frameDescriptor, JRubyParser parser, long returnID, boolean ownScopeForAssignments, - boolean neverAssignInParentScope, UniqueMethodIdentifier methodIdentifier) { - this.context = context; - this.parent = parent; - this.frameDescriptor = frameDescriptor; - this.parser = parser; - this.returnID = returnID; - this.ownScopeForAssignments = ownScopeForAssignments; - this.neverAssignInParentScope = neverAssignInParentScope; - this.methodIdentifier = methodIdentifier; - } - - public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, JRubyParser parser, long returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope, - UniqueMethodIdentifier methodIdentifier) { - this(context, parent, new FrameDescriptor(RubyFrameTypeConversion.getInstance()), parser, returnID, ownScopeForAssignments, neverAssignInParentScope, methodIdentifier); - } - - public int getLocalVarCount() { - return getFrameDescriptor().getSize(); - } - - public TranslatorEnvironment getParent() { - return parent; - } - - public List getPreParameters() { - return preParameters; - } - - public List getOptionalParameters() { - return optionalParameters; - } - - public Map getOptionalParametersDefaultValues() { - return optionalParametersDefaultValues; - } - - public List getPostParameters() { - return postParameters; - } - - public TranslatorEnvironment getParent(int level) { - assert level >= 0; - if (level == 0) { - return this; - } else { - return parent.getParent(level - 1); - } - } - - public FrameSlot declareVar(String name) { - return getFrameDescriptor().findOrAddFrameSlot(name); - } - - public UniqueMethodIdentifier findMethodForLocalVar(String name) { - TranslatorEnvironment current = this; - do { - FrameSlot slot = current.getFrameDescriptor().findFrameSlot(name); - if (slot != null) { - return current.methodIdentifier; - } - - current = current.parent; - } while (current != null); - - return null; - } - - public RubyNode findLocalVarNode(String name, SourceSection sourceSection) { - TranslatorEnvironment current = this; - int level = -1; - try { - do { - level++; - FrameSlot slot = current.getFrameDescriptor().findFrameSlot(name); - if (slot != null) { - if (level == 0) { - return ReadLocalVariableNodeFactory.create(context, sourceSection, slot); - } else { - return ReadLevelVariableNodeFactory.create(context, sourceSection, slot, level); - } - } - - current = current.parent; - } while (current != null); - } finally { - if (current != null) { - current = this; - while (level-- > 0) { - current.needsDeclarationFrame = true; - current = current.parent; - } - } - } - - return null; - } - - public void setRestParameter(FrameSlot restParameter) { - this.restParameter = restParameter; - } - - public FrameSlot getRestParameter() { - return restParameter; - } - - public void setBlockParameter(FrameSlot blockParameter) { - this.blockParameter = blockParameter; - } - - public FrameSlot getBlockParameter() { - return blockParameter; - } - - public void declareFunction(String name) { - declareVar(name); - } - - public String getMethodName() { - return methodName; - } - - public void setMethodName(String methodName) { - this.methodName = methodName; - } - - public void setNeedsDeclarationFrame() { - needsDeclarationFrame = true; - } - - public boolean needsDeclarationFrame() { - return needsDeclarationFrame; - } - - public FrameDescriptor getFrameDescriptor() { - return frameDescriptor; - } - - public String allocateLocalTemp() { - final String name = "rubytruffle_temp" + tempIndex; - tempIndex++; - declareVar(name); - return name; - } - - public long getReturnID() { - return returnID; - } - - public JRubyParser getParser() { - return parser; - } - - public boolean hasOwnScopeForAssignments() { - return ownScopeForAssignments; - } - - public boolean getNeverAssignInParentScope() { - return neverAssignInParentScope; - } - - public void addMethodDeclarationSlots() { - frameDescriptor.addFrameSlot(RubyModule.VISIBILITY_FRAME_SLOT_ID); - frameDescriptor.addFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID); - } - - public UniqueMethodIdentifier getUniqueMethodIdentifier() { - return methodIdentifier; - } - - public List getFlipFlopStates() { - return flipFlopStates; - } - - public RubyNodeInstrumenter getNodeInstrumenter() { - return (RubyNodeInstrumenter) context.getDebugContext().getNodeInstrumenter(); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/.checkstyle_checks.xml --- a/graal/com.oracle.truffle.ruby.runtime/.checkstyle_checks.xml Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/InputReader.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/InputReader.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import java.io.*; - -/** - * Interface allowing Ruby {@code Kernel#gets} to be configured to use the standard Java readLine, - * some library like JLine, or to be mocked for testing. - */ -public interface InputReader { - - /** - * Show a prompt and read one line of input. - */ - String readLine(String prompt) throws IOException; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/NilPlaceholder.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/NilPlaceholder.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2013 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; - -/** - * Represents the Ruby {@code Nil} object, but without being a full Ruby object. This allows us to - * have a simple values that is {@code nil}, but more readily available than the particular instance - * for a context. - */ -public final class NilPlaceholder { - - public static final NilPlaceholder INSTANCE = new NilPlaceholder(); - - private NilPlaceholder() { - } - - @Override - public String toString() { - return ""; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyArguments.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyArguments.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Arguments and other context passed to a Ruby method. Includes the central Ruby context object, - * optionally the scope at the point of declaration (forming a closure), the value of self, a passed - * block, and the formal arguments. - */ -public final class RubyArguments extends Arguments { - - private final MaterializedFrame declarationFrame; - private final Object self; - private final RubyProc block; - private final Object[] arguments; - - public RubyArguments(MaterializedFrame declarationFrame, Object self, RubyProc block, Object... arguments) { - assert self != null; - assert arguments != null; - - this.declarationFrame = declarationFrame; - this.self = self; - this.block = block; - this.arguments = arguments; - } - - public MaterializedFrame getDeclarationFrame() { - return declarationFrame; - } - - /** - * Get the declaration frame a certain number of levels up from the current frame, where the - * current frame is 0. - */ - public static MaterializedFrame getDeclarationFrame(VirtualFrame frame, int level) { - assert level > 0; - - MaterializedFrame parentFrame = frame.getArguments(RubyArguments.class).getDeclarationFrame(); - return getDeclarationFrame(parentFrame, level - 1); - } - - /** - * Get the declaration frame a certain number of levels up from the current frame, where the - * current frame is 0. - */ - @ExplodeLoop - private static MaterializedFrame getDeclarationFrame(MaterializedFrame frame, int level) { - assert frame != null; - assert level >= 0; - - MaterializedFrame parentFrame = frame; - - for (int n = 0; n < level; n++) { - parentFrame = parentFrame.getArguments(RubyArguments.class).getDeclarationFrame(); - } - - return parentFrame; - } - - public Object getSelf() { - return self; - } - - public RubyProc getBlock() { - return block; - } - - public Object[] getArguments() { - return arguments; - } - -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,294 +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; - -import java.math.*; -import java.util.concurrent.atomic.*; - -import jnr.posix.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.debug.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.source.*; -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.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; -import com.oracle.truffle.ruby.runtime.subsystems.*; - -/** - * The global state of a running Ruby system. - */ -public class RubyContext implements ExecutionContext { - - private final Configuration configuration; - private final RubyParser parser; - private final CoreLibrary coreLibrary; - private final FeatureManager featureManager; - private final ObjectSpaceManager objectSpaceManager; - private final TraceManager traceManager; - private final ThreadManager threadManager; - private final FiberManager fiberManager; - private final AtExitManager atExitManager; - private final SourceManager sourceManager; - private DebugContext debugContext = null; - - private AtomicLong nextObjectID = new AtomicLong(0); - - private String currentDirectory = System.getProperty("user.dir"); - - private POSIX posix = POSIXFactory.getPOSIX(); - - public RubyContext(RubyParser parser) { - this(new Configuration(new ConfigurationBuilder()), parser); - } - - public RubyContext(Configuration configuration, RubyParser parser) { - assert configuration != null; - - this.configuration = configuration; - this.parser = parser; - objectSpaceManager = new ObjectSpaceManager(this); - traceManager = new TraceManager(this); - - // See note in CoreLibrary#initialize to see why we need to break this into two statements - coreLibrary = new CoreLibrary(this); - coreLibrary.initialize(); - - featureManager = new FeatureManager(this); - atExitManager = new AtExitManager(); - sourceManager = new SourceManager(); - - // Must initialize threads before fibers - - threadManager = new ThreadManager(this); - fiberManager = new FiberManager(this); - } - - public final String getLanguageShortName() { - return "Ruby " + CoreLibrary.RUBY_VERSION; - } - - public SourceManager getSourceManager() { - return sourceManager; - } - - public DebugContext getDebugContext() { - return debugContext; - } - - public void setDebugContext(DebugContext debugContext) { - this.debugContext = debugContext; - } - - public void implementationMessage(String format, Object... arguments) { - System.err.println("rubytruffle: " + String.format(format, arguments)); - } - - public void load(Source source) { - execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null); - } - - public void loadFile(String fileName) { - final Source source = sourceManager.get(fileName); - final String code = source.getCode(); - if (code == null) { - throw new RuntimeException("Can't read file " + fileName); - } - execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null); - } - - /** - * Receives runtime notification that execution has halted. - */ - public void haltedAt(Node node, MaterializedFrame frame) { - runShell(node, frame); - } - - public Object eval(String code) { - final Source source = sourceManager.get("(eval)", code); - return execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null); - } - - public Object eval(String code, RubyModule module) { - final Source source = sourceManager.get("(eval)", code); - return execute(this, source, RubyParser.ParserContext.MODULE, module, null); - } - - public Object eval(String code, RubyBinding binding) { - final Source source = sourceManager.get("(eval)", code); - return execute(this, source, RubyParser.ParserContext.TOP_LEVEL, binding.getSelf(), binding.getFrame()); - } - - public void runShell(Node node, MaterializedFrame frame) { - MaterializedFrame existingLocals = frame; - - String prompt = "Ruby> "; - if (node != null) { - final SourceSection src = node.getSourceSection(); - if (src != null) { - prompt = (src.getSource().getName() + ":" + src.getStartLine() + "> "); - } - } - - while (true) { - try { - final String line = configuration.getInputReader().readLine(prompt); - - final ShellResult result = evalShell(line, existingLocals); - - configuration.getStandardOut().println("=> " + result.getResult()); - - existingLocals = result.getFrame(); - } catch (KillException e) { - return; - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - public ShellResult evalShell(String code, MaterializedFrame existingLocals) { - final Source source = sourceManager.get("(shell)", code); - return (ShellResult) execute(this, source, RubyParser.ParserContext.SHELL, coreLibrary.getMainObject(), existingLocals); - } - - public Object execute(RubyContext context, Source source, RubyParser.ParserContext parserContext, Object self, MaterializedFrame parentFrame) { - try { - final RubyParserResult parseResult = parser.parse(context, source, parserContext, parentFrame); - final RubyArguments arguments = new RubyArguments(parentFrame, self, null); - final CallTarget callTarget = Truffle.getRuntime().createCallTarget(parseResult.getRootNode()); - - return callTarget.call(null, arguments); - } catch (RaiseException e) { - throw e; - } catch (ThrowException e) { - throw new RaiseException(context.getCoreLibrary().argumentErrorUncaughtThrow(e.getTag())); - } catch (KillException | QuitException e) { - throw e; - } catch (Throwable e) { - throw new RaiseException(ExceptionTranslator.translateException(this, e)); - } - } - - public long getNextObjectID() { - // TODO(CS): We can theoretically run out of long values - - final long id = nextObjectID.getAndIncrement(); - - if (id < 0) { - nextObjectID.set(Long.MIN_VALUE); - throw new RuntimeException("Object IDs exhausted"); - } - - return id; - } - - public void shutdown() { - atExitManager.run(); - - threadManager.leaveGlobalLock(); - - objectSpaceManager.shutdown(); - - if (fiberManager != null) { - fiberManager.shutdown(); - } - } - - public RubyString makeString(String string) { - return new RubyString(coreLibrary.getStringClass(), string); - } - - public RubyString makeString(char string) { - return makeString(Character.toString(string)); - } - - public Configuration getConfiguration() { - return configuration; - } - - public CoreLibrary getCoreLibrary() { - return coreLibrary; - } - - public FeatureManager getFeatureManager() { - return featureManager; - } - - public ObjectSpaceManager getObjectSpaceManager() { - return objectSpaceManager; - } - - public TraceManager getTraceManager() { - return traceManager; - } - - public FiberManager getFiberManager() { - return fiberManager; - } - - public ThreadManager getThreadManager() { - return threadManager; - } - - public RubyParser getParser() { - return parser; - } - - /** - * Utility method to check if an object should be visible in a Ruby program. Used in assertions - * at method boundaries to check that only values we want to be visible to the programmer become - * so. - */ - public static boolean shouldObjectBeVisible(Object object) { - // TODO(cs): RubyMethod should never be visible - - return object instanceof UndefinedPlaceholder || // - object instanceof Boolean || // - object instanceof Integer || // - object instanceof BigInteger || // - object instanceof Double || // - object instanceof RubyBasicObject || // - object instanceof RubyMethod || // - object instanceof NilPlaceholder || // - object instanceof RubyMethod; - } - - public static boolean shouldObjectsBeVisible(Object... objects) { - for (Object object : objects) { - if (!shouldObjectBeVisible(object)) { - return false; - } - } - - return true; - } - - public void setCurrentDirectory(String currentDirectory) { - this.currentDirectory = currentDirectory; - } - - public String getCurrentDirectory() { - return currentDirectory; - } - - public POSIX getPOSIX() { - return posix; - } - - public AtExitManager getAtExitManager() { - return atExitManager; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParser.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParser.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; - -/** - * Interface to a Ruby parser. - */ -public interface RubyParser { - - public static enum ParserContext { - TOP_LEVEL, SHELL, MODULE - } - - RubyParserResult parse(RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParserResult.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParserResult.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import com.oracle.truffle.api.nodes.*; - -/** - * The result of parsing Ruby code is a root node and a frame descriptor for the method in that - * root. The root node will always be a {@code RubyRootNode}, but this package is below the nodes - * package so currently cannot refer to it. - */ -public class RubyParserResult { - - private final RootNode rootNode; - - public RubyParserResult(RootNode rootNode) { - assert rootNode != null; - this.rootNode = rootNode; - } - - public RootNode getRootNode() { - return rootNode; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/ShellResult.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/ShellResult.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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; - -import com.oracle.truffle.api.frame.*; - -/** - * The result of executing a line in a shell is a result value and the final frame containing any - * local variables set. - */ -public class ShellResult { - - private final Object result; - private final MaterializedFrame frame; - - public ShellResult(Object result, MaterializedFrame frame) { - assert RubyContext.shouldObjectBeVisible(result); - assert frame != null; - - this.result = result; - this.frame = frame; - } - - public Object getResult() { - return result; - } - - public MaterializedFrame getFrame() { - return frame; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/UndefinedPlaceholder.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/UndefinedPlaceholder.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013 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; - -/** - * The {@link UndefinedPlaceholder} is a value that represents an undefined value in Ruby. This is - * used to differentiate between nil and the true absence of a value, such as an argument that has - * not been passed. - */ -public final class UndefinedPlaceholder { - - public static final UndefinedPlaceholder INSTANCE = new UndefinedPlaceholder(); - - private UndefinedPlaceholder() { - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/Configuration.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/Configuration.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2013 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.configuration; - -import java.io.*; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * Configurable, immutable global parameters for Ruby. - */ -public class Configuration { - - private final String standardLibrary; - - private final boolean verbose; - private final int warningLevel; - private final int taintCheckLevel; - - private final String defaultExternalEncoding; - private final String defaultInternalEncoding; - - private final boolean debug; - private final boolean trace; - private final boolean fullObjectSpace; - - private final boolean printParseTree; - private final boolean printUninitializedCalls; - private final boolean printJavaExceptions; - - private final PrintStream standardOut; - private final InputReader inputReader; - - public Configuration(ConfigurationBuilder builder) { - assert builder != null; - - standardLibrary = builder.getStandardLibrary(); - - verbose = builder.getVerbose(); - warningLevel = builder.getWarningLevel(); - taintCheckLevel = builder.getTaintCheckLevel(); - - defaultExternalEncoding = builder.getDefaultExternalEncoding(); - defaultInternalEncoding = builder.getDefaultInternalEncoding(); - - debug = builder.getDebug(); - trace = builder.getTrace(); - fullObjectSpace = builder.getFullObjectSpace(); - - printParseTree = builder.getPrintParseTree(); - printUninitializedCalls = builder.getPrintUninitializedCalls(); - printJavaExceptions = builder.getPrintJavaExceptions(); - - standardOut = builder.getStandardOut(); - inputReader = builder.getInputReader(); - } - - public String getStandardLibrary() { - return standardLibrary; - } - - public boolean getDebug() { - return debug; - } - - public boolean getVerbose() { - return verbose; - } - - public int getWarningLevel() { - return warningLevel; - } - - public int getTaintCheckLevel() { - return taintCheckLevel; - } - - public String getDefaultExternalEncoding() { - return defaultExternalEncoding; - } - - public String getDefaultInternalEncoding() { - return defaultInternalEncoding; - } - - public boolean getTrace() { - return trace; - } - - public boolean getFullObjectSpace() { - return fullObjectSpace; - } - - public boolean getPrintParseTree() { - return printParseTree; - } - - public boolean getPrintUninitializedCalls() { - return printUninitializedCalls; - } - - public boolean getPrintJavaExceptions() { - return printJavaExceptions; - } - - public PrintStream getStandardOut() { - return standardOut; - } - - public InputReader getInputReader() { - return inputReader; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/ConfigurationBuilder.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/ConfigurationBuilder.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2013 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.configuration; - -import java.io.*; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * The mutable counterpart to {@link Configuration}. - */ -public class ConfigurationBuilder { - - /** - * The path of the JRuby packaging of the Ruby standard library within our source tree. - */ - public static final String JRUBY_STDLIB_JAR = "lib/jruby-stdlib-1.7.4.jar"; - - private String standardLibrary = JRUBY_STDLIB_JAR; - - private boolean debug = false; - private boolean verbose = false; - private int warningLevel = 0; - private int taintCheckLevel = 0; - - private String defaultExternalEncoding = null; - private String defaultInternalEncoding = null; - - private boolean trace = false; - private boolean fullObjectSpace = false; - - private boolean printParseTree = false; - private boolean printUninitializedCalls = false; - private boolean printJavaExceptions = false; - - private PrintStream standardOut = System.out; - - private InputReader inputReader = new InputReader() { - - private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); - - @Override - public String readLine(String prompt) throws IOException { - System.err.print(prompt); - return reader.readLine(); - } - - }; - - public ConfigurationBuilder() { - } - - public ConfigurationBuilder(Configuration configuration) { - assert configuration != null; - - standardLibrary = configuration.getStandardLibrary(); - - debug = configuration.getDebug(); - verbose = configuration.getVerbose(); - warningLevel = configuration.getWarningLevel(); - taintCheckLevel = configuration.getTaintCheckLevel(); - - defaultExternalEncoding = configuration.getDefaultExternalEncoding(); - defaultInternalEncoding = configuration.getDefaultInternalEncoding(); - - trace = configuration.getTrace(); - fullObjectSpace = configuration.getFullObjectSpace(); - - printParseTree = configuration.getPrintParseTree(); - printUninitializedCalls = configuration.getPrintUninitializedCalls(); - printJavaExceptions = configuration.getPrintJavaExceptions(); - - standardOut = configuration.getStandardOut(); - } - - public String getStandardLibrary() { - return standardLibrary; - } - - public void setStandardLibrary(String standardLibrary) { - assert standardLibrary != null; - this.standardLibrary = standardLibrary; - } - - public boolean getDebug() { - return debug; - } - - public void setDebug(boolean debug) { - this.debug = debug; - } - - public boolean getVerbose() { - return verbose; - } - - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - public int getWarningLevel() { - return warningLevel; - } - - public void setWarningLevel(int warningLevel) { - this.warningLevel = warningLevel; - } - - public int getTaintCheckLevel() { - return taintCheckLevel; - } - - public void setTaintCheckLevel(int taintCheckLevel) { - this.taintCheckLevel = taintCheckLevel; - } - - public String getDefaultExternalEncoding() { - return defaultExternalEncoding; - } - - public void setDefaultExternalEncoding(String defaultExternalEncoding) { - assert defaultExternalEncoding != null; - this.defaultExternalEncoding = defaultExternalEncoding; - } - - public String getDefaultInternalEncoding() { - return defaultInternalEncoding; - } - - public void setDefaultInternalEncoding(String defaultInternalEncoding) { - assert defaultInternalEncoding != null; - this.defaultInternalEncoding = defaultInternalEncoding; - } - - public boolean getTrace() { - return trace; - } - - public void setTrace(boolean trace) { - this.trace = trace; - } - - public boolean getFullObjectSpace() { - return fullObjectSpace; - } - - public void setFullObjectSpace(boolean fullObjectSpace) { - this.fullObjectSpace = fullObjectSpace; - } - - public boolean getPrintParseTree() { - return printParseTree; - } - - public void setPrintParseTree(boolean printParseTree) { - this.printParseTree = printParseTree; - } - - public boolean getPrintUninitializedCalls() { - return printUninitializedCalls; - } - - public void setPrintUninitializedCalls(boolean printUninitializedCalls) { - this.printUninitializedCalls = printUninitializedCalls; - } - - public boolean getPrintJavaExceptions() { - return printJavaExceptions; - } - - public void setPrintJavaExceptions(boolean printJavaExceptions) { - this.printJavaExceptions = printJavaExceptions; - } - - public PrintStream getStandardOut() { - return standardOut; - } - - public void setStandardOut(PrintStream standardOut) { - assert standardOut != null; - this.standardOut = standardOut; - } - - public InputReader getInputReader() { - return inputReader; - } - - public void setInputReader(InputReader lineReader) { - assert lineReader != null; - this.inputReader = lineReader; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.control; - -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Controls a break from a control structure or method. - */ -public final class BreakException extends ControlFlowException { - - public static final BreakException NIL = new BreakException(NilPlaceholder.INSTANCE); - - private final Object result; - - public BreakException(Object result) { - assert RubyContext.shouldObjectBeVisible(result); - - this.result = result; - } - - public Object getResult() { - return result; - } - - private static final long serialVersionUID = -8650123232850256133L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ContinuationReturnException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ContinuationReturnException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Controls return from a continuation. - */ -public final class ContinuationReturnException extends ControlFlowException { - - private final RubyContinuation continuation; - private final Object value; - - public ContinuationReturnException(RubyContinuation continuation, Object value) { - assert continuation != null; - assert RubyContext.shouldObjectBeVisible(value); - - this.continuation = continuation; - this.value = value; - } - - /** - * Get the continuation that caused this. - */ - public RubyContinuation getContinuation() { - return continuation; - } - - /** - * Get the value that has been returned. - */ - public Object getValue() { - return value; - } - - private static final long serialVersionUID = 6215834704293311504L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ExceptionTranslator.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ExceptionTranslator.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -public final class ExceptionTranslator { - - /** - * Translate a Java exception into a Ruby exception. - */ - public static RubyBasicObject translateException(RubyContext context, Throwable exception) { - assert context != null; - assert exception != null; - - CompilerAsserts.neverPartOfCompilation(); - - // RaiseException already includes the Ruby exception - - if (exception instanceof RaiseException) { - return ((RaiseException) exception).getRubyException(); - } - - // Translate divide by zero into ZeroDivisionError - - if (exception instanceof ArithmeticException && (exception.getMessage().endsWith("divide by zero") || exception.getMessage().endsWith("/ by zero"))) { - return new RubyException(context.getCoreLibrary().getZeroDivisionErrorClass(), "divided by 0"); - } - - /* - * If we can't translate the exception into a Ruby exception, then the error is ours and we - * report it as as RubyTruffleError. If a programmer sees this then it's a bug in our - * implementation. - */ - - if (context.getConfiguration().getPrintJavaExceptions()) { - exception.printStackTrace(); - } - - String message; - - if (exception.getMessage() == null) { - message = exception.getClass().getSimpleName(); - } else { - message = exception.getMessage(); - } - - return new RubyException(context.getCoreLibrary().getRubyTruffleErrorClass(), message); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.control; - -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Controls moving to the next iteration in a control structure or method. - */ -public final class NextException extends ControlFlowException { - - public static final NextException NIL = new NextException(NilPlaceholder.INSTANCE); - - private final Object result; - - public NextException(Object result) { - assert RubyContext.shouldObjectBeVisible(result); - - this.result = result; - } - - public Object getResult() { - return result; - } - - private static final long serialVersionUID = -302759969186731457L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RaiseException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RaiseException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Ruby exceptions are just Ruby objects, so they cannot also be exceptions unless we made all Ruby - * objects exceptions. A simpler approach is to wrap Ruby exceptions in Java exceptions when we want - * to throw them. The error messages match MRI. Note that throwing is different to raising in Ruby, - * which is the reason we have both {@link ThrowException} and {@link RaiseException}. - */ -public class RaiseException extends RuntimeException { - - private final RubyBasicObject rubyException; - - public RaiseException(RubyBasicObject rubyException) { - this.rubyException = rubyException; - } - - @Override - public String toString() { - return rubyException.toString(); - } - - @Override - public String getMessage() { - return rubyException.toString(); - } - - public RubyBasicObject getRubyException() { - return rubyException; - } - - private static final long serialVersionUID = 7501185855599094740L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RedoException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RedoException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.nodes.*; - -/** - * Controls re-doing an iteration in a control structure or method. - */ -public final class RedoException extends ControlFlowException { - - private static final long serialVersionUID = -4717868827111714052L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RetryException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RetryException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.nodes.*; - -/** - * Controls re-trying an iteration in a control structure or method. - */ -public final class RetryException extends ControlFlowException { - - private static final long serialVersionUID = -1675586631300635765L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ReturnException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ReturnException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Controls an explicit return from a method. - */ -public final class ReturnException extends ControlFlowException { - - private final long returnID; - private final Object value; - - public ReturnException(long returnID, Object value) { - assert RubyContext.shouldObjectBeVisible(value); - - this.returnID = returnID; - this.value = value; - } - - /** - * Return the return ID of this return that identifies where it intends to return to. - */ - public long getReturnID() { - return returnID; - } - - /** - * Get the value that has been returned. - */ - public Object getValue() { - return value; - } - - private static final long serialVersionUID = -9177536212065610691L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ThrowException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ThrowException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 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.control; - -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * Controls throwing a value. Note that throwing is different to raising in Ruby, which is the - * reason we have both {@link ThrowException} and {@link RaiseException}. - */ -public class ThrowException extends ControlFlowException { - - private final Object tag; - private final Object value; - - public ThrowException(Object tag, Object value) { - assert tag != null; - assert RubyContext.shouldObjectBeVisible(value); - - this.tag = tag; - this.value = value; - } - - public Object getTag() { - return tag; - } - - public Object getValue() { - return value; - } - - private static final long serialVersionUID = 8693305627979840677L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/CoreLibrary.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/CoreLibrary.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,651 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.io.*; -import java.math.*; -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -public class CoreLibrary { - - public static final String RUBY_VERSION = "2.1.0"; - - private final RubyContext context; - - private RubyClass argumentErrorClass; - private RubyClass arrayClass; - private RubyClass basicObjectClass; - private RubyClass bignumClass; - private RubyClass bindingClass; - private RubyClass classClass; - private RubyClass continuationClass; - private RubyClass dirClass; - private RubyClass exceptionClass; - private RubyClass falseClass; - private RubyClass fiberClass; - private RubyClass fileClass; - private RubyClass fixnumClass; - private RubyClass floatClass; - private RubyClass hashClass; - private RubyClass integerClass; - private RubyClass ioClass; - private RubyClass loadErrorClass; - private RubyClass localJumpErrorClass; - private RubyClass matchDataClass; - private RubyClass moduleClass; - private RubyClass nameErrorClass; - private RubyClass nilClass; - private RubyClass noMethodErrorClass; - private RubyClass numericClass; - private RubyClass objectClass; - private RubyClass procClass; - private RubyClass processClass; - private RubyClass rangeClass; - private RubyClass rangeErrorClass; - private RubyClass regexpClass; - private RubyClass rubyTruffleErrorClass; - private RubyClass runtimeErrorClass; - private RubyClass standardErrorClass; - private RubyClass stringClass; - private RubyClass structClass; - private RubyClass symbolClass; - private RubyClass syntaxErrorClass; - private RubyClass systemCallErrorClass; - private RubyClass systemExitClass; - private RubyClass threadClass; - private RubyClass timeClass; - private RubyClass trueClass; - private RubyClass typeErrorClass; - private RubyClass zeroDivisionErrorClass; - - private RubyModule comparableModule; - private RubyModule configModule; - private RubyModule errnoModule; - private RubyModule kernelModule; - private RubyModule mathModule; - private RubyModule objectSpaceModule; - private RubyModule signalModule; - - private RubyModule debugModule; - private RubyArray argv; - private RubyBasicObject globalVariablesObject; - private RubyBasicObject mainObject; - private RubyFalseClass falseObject; - private RubyNilClass nilObject; - private RubyTrueClass trueObject; - - public CoreLibrary(RubyContext context) { - this.context = context; - } - - public void initialize() { - // Create the cyclic classes and modules - - classClass = new RubyClass.RubyClassClass(context); - basicObjectClass = new RubyClass(context, classClass, null, null, "BasicObject"); - objectClass = new RubyClass(null, basicObjectClass, "Object"); - moduleClass = new RubyModule.RubyModuleClass(context); - - // Close the cycles - - moduleClass.unsafeSetRubyClass(classClass); - classClass.unsafeSetSuperclass(moduleClass); - moduleClass.unsafeSetSuperclass(objectClass); - classClass.unsafeSetRubyClass(classClass); - - // Create all other classes and modules - - numericClass = new RubyClass(null, objectClass, "Numeric"); - integerClass = new RubyClass(null, numericClass, "Integer"); - - exceptionClass = new RubyException.RubyExceptionClass(objectClass, "Exception"); - standardErrorClass = new RubyException.RubyExceptionClass(exceptionClass, "StandardError"); - - ioClass = new RubyClass(null, objectClass, "IO"); - - argumentErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "ArgumentError"); - arrayClass = new RubyArray.RubyArrayClass(objectClass); - bignumClass = new RubyClass(null, integerClass, "Bignum"); - bindingClass = new RubyClass(null, objectClass, "Binding"); - continuationClass = new RubyClass(null, objectClass, "Continuation"); - comparableModule = new RubyModule(moduleClass, null, "Comparable"); - configModule = new RubyModule(moduleClass, null, "Config"); - debugModule = new RubyModule(moduleClass, null, "Debug"); - dirClass = new RubyClass(null, objectClass, "Dir"); - errnoModule = new RubyModule(moduleClass, null, "Errno"); - falseClass = new RubyClass(null, objectClass, "FalseClass"); - fiberClass = new RubyFiber.RubyFiberClass(objectClass); - fileClass = new RubyClass(null, ioClass, "File"); - fixnumClass = new RubyClass(null, integerClass, "Fixnum"); - floatClass = new RubyClass(null, objectClass, "Float"); - hashClass = new RubyHash.RubyHashClass(objectClass); - kernelModule = new RubyModule(moduleClass, null, "Kernel"); - loadErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "LoadError"); - localJumpErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "LocalJumpError"); - matchDataClass = new RubyClass(null, objectClass, "MatchData"); - mathModule = new RubyModule(moduleClass, null, "Math"); - nameErrorClass = new RubyClass(null, standardErrorClass, "NameError"); - nilClass = new RubyClass(null, objectClass, "NilClass"); - noMethodErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "NoMethodError"); - objectSpaceModule = new RubyModule(moduleClass, null, "ObjectSpace"); - procClass = new RubyProc.RubyProcClass(objectClass); - processClass = new RubyClass(null, objectClass, "Process"); - rangeClass = new RubyClass(null, objectClass, "Range"); - rangeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RangeError"); - regexpClass = new RubyRegexp.RubyRegexpClass(objectClass); - rubyTruffleErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RubyTruffleError"); - runtimeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RuntimeError"); - stringClass = new RubyString.RubyStringClass(objectClass); - structClass = new RubyClass(null, ioClass, "Struct"); - signalModule = new RubyModule(moduleClass, null, "Signal"); - symbolClass = new RubyClass(null, objectClass, "Symbol"); - syntaxErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "SyntaxError"); - systemCallErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "SystemCallError"); - systemExitClass = new RubyException.RubyExceptionClass(exceptionClass, "SystemExit"); - threadClass = new RubyThread.RubyThreadClass(objectClass); - timeClass = new RubyTime.RubyTimeClass(objectClass); - trueClass = new RubyClass(null, objectClass, "TrueClass"); - typeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "TypeError"); - zeroDivisionErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "ZeroDivisionError"); - - // Includes - - objectClass.include(kernelModule); - - // Set constants - - objectClass.setConstant("RUBY_VERSION", new RubyString(stringClass, RUBY_VERSION)); - objectClass.setConstant("RUBY_PATCHLEVEL", 0); - objectClass.setConstant("RUBY_ENGINE", new RubyString(stringClass, "rubytruffle")); - objectClass.setConstant("RUBY_PLATFORM", new RubyString(stringClass, "jvm")); - - argv = new RubyArray(arrayClass, new ObjectArrayStore()); - objectClass.setConstant("ARGV", argv); - objectClass.setConstant("ENV", getEnv()); - - final RubyHash configHash = new RubyHash(hashClass); - configHash.put(new RubyString(stringClass, "ruby_install_name"), new RubyString(stringClass, "rubytruffle")); - configHash.put(new RubyString(stringClass, "RUBY_INSTALL_NAME"), new RubyString(stringClass, "rubytruffle")); - configHash.put(new RubyString(stringClass, "host_os"), new RubyString(stringClass, "unknown")); - configHash.put(new RubyString(stringClass, "exeext"), new RubyString(stringClass, "")); - configHash.put(new RubyString(stringClass, "EXEEXT"), new RubyString(stringClass, "rubytruffle")); - configModule.setConstant("CONFIG", configHash); - objectClass.setConstant("RbConfig", configModule); - - mathModule.setConstant("PI", Math.PI); - - fileClass.setConstant("SEPARATOR", new RubyString(stringClass, File.separator)); - fileClass.setConstant("Separator", new RubyString(stringClass, File.separator)); - fileClass.setConstant("ALT_SEPARATOR", NilPlaceholder.INSTANCE); - fileClass.setConstant("PATH_SEPARATOR", new RubyString(stringClass, File.pathSeparator)); - fileClass.setConstant("FNM_SYSCASE", 0); - - errnoModule.setConstant("ENOENT", new RubyClass(null, systemCallErrorClass, "ENOENT")); - errnoModule.setConstant("EPERM", new RubyClass(null, systemCallErrorClass, "EPERM")); - errnoModule.setConstant("ENOTEMPTY", new RubyClass(null, systemCallErrorClass, "ENOTEMPTY")); - errnoModule.setConstant("EEXIST", new RubyClass(null, systemCallErrorClass, "EEXIST")); - errnoModule.setConstant("EXDEV", new RubyClass(null, systemCallErrorClass, "EXDEV")); - errnoModule.setConstant("EACCES", new RubyClass(null, systemCallErrorClass, "EACCES")); - - // Add all classes and modules as constants in Object - - final RubyModule[] modules = {argumentErrorClass, // - arrayClass, // - basicObjectClass, // - bignumClass, // - bindingClass, // - classClass, // - continuationClass, // - comparableModule, // - configModule, // - debugModule, // - dirClass, // - errnoModule, // - exceptionClass, // - falseClass, // - fiberClass, // - fileClass, // - fixnumClass, // - floatClass, // - hashClass, // - integerClass, // - ioClass, // - kernelModule, // - loadErrorClass, // - localJumpErrorClass, // - matchDataClass, // - mathModule, // - moduleClass, // - nameErrorClass, // - nilClass, // - noMethodErrorClass, // - numericClass, // - objectClass, // - objectSpaceModule, // - procClass, // - processClass, // - rangeClass, // - rangeErrorClass, // - regexpClass, // - rubyTruffleErrorClass, // - runtimeErrorClass, // - signalModule, // - standardErrorClass, // - stringClass, // - structClass, // - symbolClass, // - syntaxErrorClass, // - systemCallErrorClass, // - systemExitClass, // - threadClass, // - timeClass, // - trueClass, // - typeErrorClass, // - zeroDivisionErrorClass}; - - for (RubyModule module : modules) { - objectClass.setConstant(module.getName(), module); - } - - // Create some key objects - - mainObject = new RubyObject(objectClass); - nilObject = new RubyNilClass(nilClass); - trueObject = new RubyTrueClass(trueClass); - falseObject = new RubyFalseClass(falseClass); - - // Create the globals object - - globalVariablesObject = new RubyBasicObject(objectClass); - globalVariablesObject.switchToPrivateLayout(); - globalVariablesObject.setInstanceVariable("$:", new RubyArray(arrayClass, new ObjectArrayStore())); - } - - public void initializeAfterMethodsAdded() { - bignumClass.getSingletonClass().undefMethod("new"); - falseClass.getSingletonClass().undefMethod("new"); - fixnumClass.getSingletonClass().undefMethod("new"); - floatClass.getSingletonClass().undefMethod("new"); - integerClass.getSingletonClass().undefMethod("new"); - nilClass.getSingletonClass().undefMethod("new"); - numericClass.getSingletonClass().undefMethod("new"); - trueClass.getSingletonClass().undefMethod("new"); - } - - public RubyBasicObject box(Object object) { - assert RubyContext.shouldObjectBeVisible(object); - - // TODO(cs): pool common object instances like small Fixnums? - - if (object instanceof RubyBasicObject) { - return (RubyBasicObject) object; - } - - if (object instanceof Boolean) { - if ((boolean) object) { - return trueObject; - } else { - return falseObject; - } - } - - if (object instanceof Integer) { - return new RubyFixnum(fixnumClass, (int) object); - } - - if (object instanceof BigInteger) { - return new RubyBignum(bignumClass, (BigInteger) object); - } - - if (object instanceof Double) { - return new RubyFloat(floatClass, (double) object); - } - - if (object instanceof NilPlaceholder) { - return nilObject; - } - - CompilerDirectives.transferToInterpreter(); - - throw new UnsupportedOperationException("Don't know how to box " + object.getClass().getName()); - } - - public RubyException runtimeError(String message) { - return new RubyException(runtimeErrorClass, message); - } - - public RubyException frozenError(String className) { - return runtimeError(String.format("can't modify frozen %s", className)); - } - - public RubyException argumentError(String message) { - return new RubyException(argumentErrorClass, message); - } - - public RubyException argumentError(int passed, int required) { - return argumentError(String.format("wrong number of arguments (%d for %d)", passed, required)); - } - - public RubyException argumentErrorUncaughtThrow(Object tag) { - return argumentError(String.format("uncaught throw `%s'", tag)); - } - - public RubyException localJumpError(String message) { - return new RubyException(localJumpErrorClass, message); - } - - public RubyException unexpectedReturn() { - return localJumpError("unexpected return"); - } - - public RubyException typeError(String message) { - return new RubyException(typeErrorClass, message); - } - - public RubyException typeError(String from, String to) { - return typeError(String.format("can't convert %s to %s", from, to)); - } - - public RubyException typeErrorIsNotA(String value, String expectedType) { - return typeError(String.format("%s is not a %s", value, expectedType)); - } - - public RubyException typeErrorNeedsToBe(String name, String expectedType) { - return typeError(String.format("%s needs to be %s", name, expectedType)); - } - - public RubyException rangeError(String message) { - return new RubyException(rangeErrorClass, message); - } - - public RubyException nameError(String message) { - return new RubyException(nameErrorClass, message); - } - - public RubyException nameErrorUninitializedConstant(String name) { - return nameError(String.format("uninitialized constant %s", name)); - } - - public RubyException nameErrorNoMethod(String name, String object) { - return nameError(String.format("undefined local variable or method `%s' for %s", name, object)); - } - - public RubyException nameErrorInstanceNameNotAllowable(String name) { - return nameError(String.format("`%s' is not allowable as an instance variable name", name)); - } - - public RubyException nameErrorUncaughtThrow(Object tag) { - return nameError(String.format("uncaught throw `%s'", tag)); - } - - public RubyException noMethodError(String message) { - return new RubyException(context.getCoreLibrary().getNoMethodErrorClass(), message); - } - - public RubyException noMethodError(String name, String object) { - return noMethodError(String.format("undefined method `%s' for %s", name, object)); - } - - public RubyException loadError(String message) { - return new RubyException(context.getCoreLibrary().getLoadErrorClass(), message); - } - - public RubyException loadErrorCannotLoad(String name) { - return loadError(String.format("cannot load such file -- %s", name)); - } - - public RubyException zeroDivisionError() { - return new RubyException(context.getCoreLibrary().getZeroDivisionErrorClass(), "divided by 0"); - } - - public RubyContext getContext() { - return context; - } - - public RubyClass getArgumentErrorClass() { - return argumentErrorClass; - } - - public RubyClass getArrayClass() { - return arrayClass; - } - - public RubyClass getBasicObjectClass() { - return basicObjectClass; - } - - public RubyClass getBignumClass() { - return bignumClass; - } - - public RubyClass getBindingClass() { - return bindingClass; - } - - public RubyClass getClassClass() { - return classClass; - } - - public RubyModule getComparableClass() { - return comparableModule; - } - - public RubyClass getContinuationClass() { - return continuationClass; - } - - public RubyClass getDirClass() { - return dirClass; - } - - public RubyClass getExceptionClass() { - return exceptionClass; - } - - public RubyClass getFalseClass() { - return falseClass; - } - - public RubyClass getFiberClass() { - return fiberClass; - } - - public RubyClass getFileClass() { - return fileClass; - } - - public RubyClass getFixnumClass() { - return fixnumClass; - } - - public RubyClass getFloatClass() { - return floatClass; - } - - public RubyClass getHashClass() { - return hashClass; - } - - public RubyClass getIntegerClass() { - return integerClass; - } - - public RubyClass getIoClass() { - return ioClass; - } - - public RubyClass getLoadErrorClass() { - return loadErrorClass; - } - - public RubyClass getLocalJumpErrorClass() { - return localJumpErrorClass; - } - - public RubyClass getMatchDataClass() { - return matchDataClass; - } - - public RubyClass getModuleClass() { - return moduleClass; - } - - public RubyClass getNameErrorClass() { - return nameErrorClass; - } - - public RubyClass getNilClass() { - return nilClass; - } - - public RubyClass getNoMethodErrorClass() { - return noMethodErrorClass; - } - - public RubyClass getNumericClass() { - return numericClass; - } - - public RubyClass getObjectClass() { - return objectClass; - } - - public RubyClass getProcClass() { - return procClass; - } - - public RubyClass getProcessClass() { - return processClass; - } - - public RubyClass getRangeClass() { - return rangeClass; - } - - public RubyClass getRangeErrorClass() { - return rangeErrorClass; - } - - public RubyClass getRegexpClass() { - return regexpClass; - } - - public RubyClass getRubyTruffleErrorClass() { - return rubyTruffleErrorClass; - } - - public RubyClass getRuntimeErrorClass() { - return runtimeErrorClass; - } - - public RubyModule getSignalModule() { - return signalModule; - } - - public RubyClass getStandardErrorClass() { - return standardErrorClass; - } - - public RubyClass getStringClass() { - return stringClass; - } - - public RubyClass getStructClass() { - return structClass; - } - - public RubyClass getSymbolClass() { - return symbolClass; - } - - public RubyClass getSyntaxErrorClass() { - return syntaxErrorClass; - } - - public RubyClass getSystemCallErrorClass() { - return systemCallErrorClass; - } - - public RubyClass getThreadClass() { - return threadClass; - } - - public RubyClass getTimeClass() { - return timeClass; - } - - public RubyClass getTrueClass() { - return trueClass; - } - - public RubyClass getTypeErrorClass() { - return typeErrorClass; - } - - public RubyClass getZeroDivisionErrorClass() { - return zeroDivisionErrorClass; - } - - public RubyModule getKernelModule() { - return kernelModule; - } - - public RubyModule getMathModule() { - return mathModule; - } - - public RubyModule getObjectSpaceModule() { - return objectSpaceModule; - } - - public RubyModule getDebugModule() { - return debugModule; - } - - public RubyArray getArgv() { - return argv; - } - - public RubyBasicObject getGlobalVariablesObject() { - return globalVariablesObject; - } - - public RubyBasicObject getMainObject() { - return mainObject; - } - - public RubyFalseClass getFalseObject() { - return falseObject; - } - - public RubyNilClass getNilObject() { - return nilObject; - } - - public RubyTrueClass getTrueObject() { - return trueObject; - } - - public RubyHash getEnv() { - final RubyHash hash = new RubyHash(context.getCoreLibrary().getHashClass()); - - for (Map.Entry variable : System.getenv().entrySet()) { - hash.put(context.makeString(variable.getKey()), context.makeString(variable.getValue())); - } - - return hash; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/GeneralConversions.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/GeneralConversions.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.*; - -public class GeneralConversions { - - /** - * Convert a value to a boolean, without doing any lookup. - */ - public static boolean toBoolean(Object value) { - assert value != null; - - if (value instanceof NilPlaceholder) { - return false; - } - - if (value instanceof Boolean) { - return (boolean) value; - } - - if (value instanceof RubyTrueClass) { - return true; - } - - if (value instanceof RubyFalseClass) { - return false; - } - - return true; - } - - /** - * Convert a value to a {@code Fixnum}, without doing any lookup. - */ - public static int toFixnum(Object value) { - assert value != null; - - if (value instanceof NilPlaceholder || value instanceof RubyNilClass) { - return 0; - } - - if (value instanceof Integer) { - return (int) value; - } - - if (value instanceof RubyFixnum) { - return ((RubyFixnum) value).getValue(); - } - - if (value instanceof BigInteger) { - throw new UnsupportedOperationException(); - } - - if (value instanceof RubyBignum) { - throw new UnsupportedOperationException(); - } - - if (value instanceof Double) { - return (int) (double) value; - } - - if (value instanceof RubyFloat) { - return (int) ((RubyFloat) value).getValue(); - } - - CompilerDirectives.transferToInterpreter(); - - throw new UnsupportedOperationException(value.getClass().toString()); - } - - /** - * Convert a value to a {@code Float}, without doing any lookup. - */ - public static double toFloat(Object value) { - assert value != null; - - if (value instanceof NilPlaceholder || value instanceof RubyNilClass) { - return 0; - } - - if (value instanceof Integer) { - return (int) value; - } - - if (value instanceof RubyFixnum) { - return ((RubyFixnum) value).getValue(); - } - - if (value instanceof BigInteger) { - return ((BigInteger) value).doubleValue(); - } - - if (value instanceof RubyBignum) { - return ((RubyBignum) value).getValue().doubleValue(); - } - - if (value instanceof Double) { - return (double) value; - } - - if (value instanceof RubyFloat) { - return ((RubyFloat) value).getValue(); - } - - CompilerDirectives.transferToInterpreter(); - - throw new UnsupportedOperationException(); - } - - /** - * Given a {@link BigInteger} value, produce either a {@code Fixnum} or {@code Bignum} . - */ - public static Object fixnumOrBignum(BigInteger value) { - assert value != null; - - if (value.compareTo(RubyFixnum.MIN_VALUE_BIG) >= 0 && value.compareTo(RubyFixnum.MAX_VALUE_BIG) <= 0) { - return value.intValue(); - } else { - return value; - } - } - - /** - * Given a {@code long} value, produce either a {@code Fixnum} or {@code Bignum} . - */ - public static Object fixnumOrBignum(long value) { - if (value >= RubyFixnum.MIN_VALUE && value <= RubyFixnum.MAX_VALUE) { - return (int) value; - } else { - return BigInteger.valueOf(value); - } - } - - /** - * Given a reference, produce either {@code nil} or the object. . - */ - public static Object instanceOrNil(Object object) { - if (object == null) { - return NilPlaceholder.INSTANCE; - } else { - return object; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBignum.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBignum.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Bignum} class. - */ -public class RubyBignum extends RubyObject implements Unboxable { - - private final BigInteger value; - - public RubyBignum(RubyClass bignumClass, BigInteger value) { - super(bignumClass); - - assert value != null; - - this.value = value; - } - - public BigInteger getValue() { - return value; - } - - public Object unbox() { - return value; - } - - public static RubyArray divMod(RubyContext context, BigInteger a, BigInteger b) { - final BigInteger[] quotientRemainder = a.divideAndRemainder(b); - - final Object quotient = GeneralConversions.fixnumOrBignum(quotientRemainder[0]); - final Object remainder = GeneralConversions.fixnumOrBignum(quotientRemainder[1]); - - final ObjectImmutablePairArrayStore store = new ObjectImmutablePairArrayStore(quotient, remainder); - return new RubyArray(context.getCoreLibrary().getArrayClass(), store); - } - - @Override - public int hashCode() { - return value.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof RubyBignum)) { - return false; - } - RubyBignum other = (RubyBignum) obj; - if (value == null) { - if (other.value != null) { - return false; - } - } else if (!value.equals(other.value)) { - return false; - } - return true; - } - - @Override - public String toString() { - return value.toString(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBinding.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBinding.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.frame.*; - -/** - * Represents the Ruby {@code Binding} class. - */ -public class RubyBinding extends RubyObject { - - private final Object self; - private final MaterializedFrame frame; - - public RubyBinding(RubyClass bindingClass, Object self, MaterializedFrame frame) { - super(bindingClass); - - assert self != null; - assert frame != null; - - this.self = self; - this.frame = frame; - } - - public Object getSelf() { - return self; - } - - public MaterializedFrame getFrame() { - return frame; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyClass.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyClass.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; - -import com.oracle.truffle.api.CompilerDirectives.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.lookup.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Class} class. Note that most of the functionality you might associate - * with {@code Class} is actually in {@code Module}, implemented by {@link RubyModule}. - */ -public class RubyClass extends RubyModule { - - /** - * The class from which we create the object that is {@code Class}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyClass} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyClassClass extends RubyClass { - - public RubyClassClass(RubyContext context) { - super(context, null, null, null, "Class"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyClass(null, getContext().getCoreLibrary().getObjectClass(), "(unnamed class)"); - } - - } - - @CompilationFinal private RubyClass superclass; - - // We maintain a list of subclasses so we can notify them when they need to update their layout. - private final Set subClasses = Collections.newSetFromMap(new WeakHashMap()); - - /* - * The layout to use for instances of this class - do not confuse with objectLayout, which is - * the layout for this object - the class. - */ - private ObjectLayout objectLayoutForInstances = null; - - public RubyClass(RubyModule parentModule, RubyClass rubySuperclass, String name) { - this(parentModule, rubySuperclass, name, false); - } - - public RubyClass(RubyModule parentModule, RubyClass rubySuperclass, String name, boolean isSingleton) { - this(rubySuperclass.getContext(), rubySuperclass.getContext().getCoreLibrary().getClassClass(), parentModule, rubySuperclass, name); - - if (!isSingleton) { - getSingletonClass(); - } - } - - /** - * This constructor supports initialization and solves boot-order problems and should not - * normally be used from outside this class. - */ - public RubyClass(RubyContext context, RubyClass classClass, RubyModule parentModule, RubyClass superclass, String name) { - super(context, classClass, parentModule, name); - - if (superclass == null) { - objectLayoutForInstances = ObjectLayout.EMPTY; - } else { - unsafeSetSuperclass(superclass); - } - } - - public RubyClass getSuperclass() { - assert superclass != null; - return superclass; - } - - @Override - public RubyClass getSingletonClass() { - if (rubySingletonClass == null) { - RubyClass singletonSuperclass; - - if (superclass == null) { - singletonSuperclass = getRubyClass(); - } else { - singletonSuperclass = superclass.getSingletonClass(); - } - - rubySingletonClass = new RubyClass(getParentModule(), singletonSuperclass, String.format("#", getName()), true); - - lookupNode = new LookupFork(rubySingletonClass, lookupNode); - } - - return rubySingletonClass; - } - - /** - * This method supports initialization and solves boot-order problems and should not normally be - * used. - */ - public void unsafeSetSuperclass(RubyClass newSuperclass) { - assert superclass == null; - - superclass = newSuperclass; - superclass.addDependent(this); - superclass.subClasses.add(this); - - include(superclass); - - objectLayoutForInstances = new ObjectLayout(getName(), superclass.objectLayoutForInstances); - } - - public RubyBasicObject newInstance() { - return new RubyObject(this); - } - - /** - * Is an instance of this class assignable to some location expecting some other class? - */ - public boolean assignableTo(RubyClass otherClass) { - if (this == otherClass) { - return true; - } - - if (superclass == null) { - return false; - } - - return superclass.assignableTo(otherClass); - } - - /** - * Returns the object layout that objects of this class should use. Do not confuse with - * {@link #getObjectLayout}, which for {@link RubyClass} will return the layout of the class - * object itself. - */ - public ObjectLayout getObjectLayoutForInstances() { - return objectLayoutForInstances; - } - - /** - * Change the layout to be used for instances of this object. - */ - public void setObjectLayoutForInstances(ObjectLayout newObjectLayoutForInstances) { - objectLayoutForInstances = newObjectLayoutForInstances; - - for (RubyClass subClass : subClasses) { - subClass.renewObjectLayoutForInstances(); - } - } - - private void renewObjectLayoutForInstances() { - objectLayoutForInstances = objectLayoutForInstances.renew(superclass.objectLayoutForInstances); - - for (RubyClass subClass : subClasses) { - subClass.renewObjectLayoutForInstances(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyContinuation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyContinuation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -/** - * Represents the Ruby {@code Continuation} class. We only support continuations that just move up - * the stack and are one-shot. - */ -public class RubyContinuation extends RubyObject { - - /* - * A continuation is dead if we have already resumed it once. We will not be able to resume it - * again due to the current implementation being an exception thrown to go back up the stack. - */ - private boolean dead = false; - - public RubyContinuation(RubyClass rubyClass) { - super(rubyClass); - } - - /** - * To enter a continuation means to remember the execution state at this point, reify that into - * an object, and then call the passed block. For our implementation, the continuation will be - * dead when this method resumes. - */ - public Object enter(RubyProc block) { - try { - return block.call(null, this); - } catch (ContinuationReturnException e) { - // Thrown in call - - // Check the exception is for this continuation - - if (e.getContinuation() == this) { - return e.getValue(); - } else { - throw e; - } - } finally { - dead = true; - } - } - - /** - * To call a continuation means to go back to the execution state when it was created. For our - * implementation we can only do this once, and only if that means jumping back up the stack. - */ - public void call(Object... args) { - if (dead) { - throw new UnsupportedOperationException("Only continuations that just move up the stack and are one-shot are supported"); - } - - Object returnValue; - - if (args.length == 0) { - returnValue = NilPlaceholder.INSTANCE; - } else if (args.length == 1) { - returnValue = args[0]; - } else { - returnValue = RubyArray.specializedFromObjects(getRubyClass().getContext().getCoreLibrary().getArrayClass(), args); - } - - // Caught in enter - - throw new ContinuationReturnException(this, returnValue); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Exception} class. - */ -public class RubyException extends RubyObject { - - /** - * The class from which we create the object that is {@code Exception}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyException} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyExceptionClass extends RubyClass { - - public RubyExceptionClass(RubyClass superClass, String name) { - super(null, superClass, name); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyException(this); - } - - } - - private RubyString message; - - public RubyException(RubyClass rubyClass) { - super(rubyClass); - message = rubyClass.getContext().makeString("(object uninitialized)"); - } - - public RubyException(RubyClass rubyClass, String message) { - this(rubyClass, rubyClass.getContext().makeString(message)); - } - - public RubyException(RubyClass rubyClass, RubyString message) { - this(rubyClass); - initialize(message); - } - - public void initialize(RubyString setMessage) { - assert setMessage != null; - message = setMessage; - } - - public RubyString getMessage() { - return message; - } - - @Override - public String toString() { - return message.toString(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFalseClass.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFalseClass.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code FalseClass} class. - */ -public class RubyFalseClass extends RubyObject implements Unboxable { - - public RubyFalseClass(RubyClass objectClass) { - super(objectClass); - } - - public Object unbox() { - return false; - } - - @Override - public String toString() { - return "false"; - } - - @Override - public boolean equals(Object other) { - return other instanceof RubyFalseClass || (other instanceof Boolean && !((boolean) other)); - } - - @Override - public int hashCode() { - return Boolean.FALSE.hashCode(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFiber.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFiber.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.concurrent.*; - -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.objects.*; -import com.oracle.truffle.ruby.runtime.subsystems.*; - -/** - * Represents the Ruby {@code Fiber} class. The current implementation uses Java threads and message - * passing. Note that the relationship between Java threads, Ruby threads and Ruby fibers is - * complex. A Java thread might be running a fiber that on difference resumptions is representing - * different Ruby threads. Take note of the lock contracts on {@link #waitForResume} and - * {@link #resume}. - */ -public class RubyFiber extends RubyObject { - - public static class RubyFiberClass extends RubyClass { - - public RubyFiberClass(RubyClass objectClass) { - super(null, objectClass, "Fiber"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyFiber(this, getContext().getFiberManager(), getContext().getThreadManager()); - } - - } - - private interface FiberMessage { - } - - private class FiberResumeMessage implements FiberMessage { - - private final RubyThread thread; - private final RubyFiber sendingFiber; - private final Object arg; - - public FiberResumeMessage(RubyThread thread, RubyFiber sendingFiber, Object arg) { - this.thread = thread; - this.sendingFiber = sendingFiber; - this.arg = arg; - } - - public RubyThread getThread() { - return thread; - } - - public RubyFiber getSendingFiber() { - return sendingFiber; - } - - public Object getArg() { - return arg; - } - - } - - private class FiberExitMessage implements FiberMessage { - } - - public class FiberExitException extends ControlFlowException { - - private static final long serialVersionUID = 1522270454305076317L; - - } - - private final FiberManager fiberManager; - private final ThreadManager threadManager; - - private BlockingQueue messageQueue = new ArrayBlockingQueue<>(1); - public RubyFiber lastResumedByFiber = null; - - public RubyFiber(RubyClass rubyClass, FiberManager fiberManager, ThreadManager threadManager) { - super(rubyClass); - this.fiberManager = fiberManager; - this.threadManager = threadManager; - } - - public void initialize(RubyProc block) { - final RubyFiber finalFiber = this; - final RubyProc finalBlock = block; - - new Thread(new Runnable() { - - @Override - public void run() { - fiberManager.registerFiber(finalFiber); - - try { - try { - final Object arg = finalFiber.waitForResume(); - final Object result = finalBlock.call(null, arg); - finalFiber.lastResumedByFiber.resume(finalFiber, result); - } catch (FiberExitException e) { - // Naturally exit the thread on catching this - } - } finally { - fiberManager.unregisterFiber(finalFiber); - } - } - - }).start(); - } - - /** - * Send the Java thread that represents this fiber to sleep until it recieves a resume or exit - * message. On entry, assumes that the GIL is not held. On exit, holding the GIL. - */ - public Object waitForResume() { - FiberMessage message = null; - - do { - try { - // TODO(cs) what is a suitable timeout? - message = messageQueue.poll(1, TimeUnit.SECONDS); - } catch (InterruptedException e) { - // Poll again - } - } while (message == null); - - if (message instanceof FiberExitMessage) { - throw new FiberExitException(); - } - - final FiberResumeMessage resumeMessage = (FiberResumeMessage) message; - - threadManager.enterGlobalLock(resumeMessage.getThread()); - - fiberManager.setCurrentFiber(this); - - lastResumedByFiber = resumeMessage.getSendingFiber(); - return resumeMessage.getArg(); - } - - /** - * Send a message to a fiber by posting into a message queue. Doesn't explicitly notify the Java - * thread (although the queue implementation may) and doesn't wait for the message to be - * received. On entry, assumes the the GIL is held. On exit, not holding the GIL. - */ - public void resume(RubyFiber sendingFiber, Object... args) { - Object arg; - - if (args.length == 0) { - arg = NilPlaceholder.INSTANCE; - } else if (args.length == 1) { - arg = args[0]; - } else { - arg = RubyArray.specializedFromObjects(getRubyClass().getContext().getCoreLibrary().getArrayClass(), args); - } - - final RubyThread runningThread = threadManager.leaveGlobalLock(); - - messageQueue.add(new FiberResumeMessage(runningThread, sendingFiber, arg)); - } - - public void shutdown() { - messageQueue.add(new FiberExitMessage()); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFile.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFile.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.io.*; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * Represents the Ruby {@code File} class. - */ -public class RubyFile extends RubyObject { - - private final Reader reader; - private final Writer writer; - - public RubyFile(RubyClass rubyClass, Reader reader, Writer writer) { - super(rubyClass); - this.reader = reader; - this.writer = writer; - } - - public void close() { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - public static String expandPath(String fileName) { - // TODO(cs): see the other expandPath - - try { - return new File(fileName).getCanonicalPath(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static String expandPath(String fileName, String dir) { - /* - * TODO(cs): this isn't quite correct - I think we want to collapse .., but we don't want to - * resolve symlinks etc. This might be where we want to start borrowing JRuby's - * implementation, but it looks quite tied to their data structures. - */ - - try { - return new File(dir, fileName).getCanonicalPath(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static RubyFile open(RubyContext context, String fileName, String mode) { - Reader reader; - Writer writer; - - if (mode.equals("rb")) { - try { - reader = new InputStreamReader(new FileInputStream(fileName)); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - - writer = null; - } else if (mode.equals("w")) { - reader = null; - - try { - writer = new OutputStreamWriter(new FileOutputStream(fileName)); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - } else { - throw new UnsupportedOperationException(); - } - - final RubyFile file = new RubyFile(context.getCoreLibrary().getFileClass(), reader, writer); - - return file; - } - - public Reader getReader() { - return reader; - } - - public Writer getWriter() { - return writer; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFixnum.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFixnum.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; - -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Fixnum} class. - */ -public class RubyFixnum extends RubyObject implements Unboxable { - - public static final int MIN_VALUE = Integer.MIN_VALUE; - public static final int MAX_VALUE = Integer.MAX_VALUE; - - public static final BigInteger MIN_VALUE_BIG = BigInteger.valueOf(MIN_VALUE); - public static final BigInteger MAX_VALUE_BIG = BigInteger.valueOf(MAX_VALUE); - - public static final int SIZE = Integer.SIZE; - - private final int value; - - public RubyFixnum(RubyClass fixnumClass, int value) { - super(fixnumClass); - this.value = value; - } - - public int getValue() { - return value; - } - - @Override - public String toString() { - return Integer.toString(value); - } - - @Override - public boolean equals(Object other) { - if (other instanceof Integer) { - return value == (int) other; - } else if (other instanceof RubyFixnum) { - return value == ((RubyFixnum) other).value; - } else if (other instanceof BigInteger) { - return ((BigInteger) other).equals(value); - } else if (other instanceof RubyBignum) { - return ((RubyBignum) other).getValue().equals(value); - } else if (other instanceof Double) { - return value == (double) other; - } else if (other instanceof RubyFloat) { - return value == ((RubyFloat) other).getValue(); - } else { - return super.equals(other); - } - } - - @Override - public int hashCode() { - throw new UnsupportedOperationException(); - } - - public Object unbox() { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFloat.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFloat.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Float} class. - */ -public class RubyFloat extends RubyObject implements Unboxable { - - private final double value; - - public RubyFloat(RubyClass floatClass, double value) { - super(floatClass); - this.value = value; - } - - public double getValue() { - return value; - } - - @Override - public String toString() { - return Double.toString(value); - } - - @Override - public boolean equals(Object other) { - if (other instanceof Integer) { - return value == (int) other; - } else if (other instanceof RubyFixnum) { - return value == ((RubyFixnum) other).getValue(); - } else if (other instanceof Double) { - return value == (double) other; - } else if (other instanceof RubyFloat) { - return value == ((RubyFloat) other).value; - } else { - return super.equals(other); - } - } - - @Override - public int hashCode() { - throw new UnsupportedOperationException(); - } - - public Object unbox() { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyHash.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyHash.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; - -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Hash} class. - */ -public class RubyHash extends RubyObject { - - /** - * The class from which we create the object that is {@code Hash}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyHash} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyHashClass extends RubyClass { - - public RubyHashClass(RubyClass objectClass) { - super(null, objectClass, "Hash"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyHash(this); - } - - } - - public final Map storage = new LinkedHashMap<>(); - @CompilationFinal public RubyProc defaultBlock = null; - - public RubyHash(RubyClass rubyClass, RubyProc defaultBlock) { - super(rubyClass); - initialize(defaultBlock); - } - - public RubyHash(RubyClass rubyClass) { - super(rubyClass); - } - - public void initialize(RubyProc setDefaultBlock) { - defaultBlock = setDefaultBlock; - } - - @Override - public Object dup() { - final RubyHash newHash = new RubyHash(rubyClass); - newHash.setInstanceVariables(getInstanceVariables()); - newHash.storage.putAll(storage); - return newHash; - } - - public void put(Object key, Object value) { - checkFrozen(); - - storage.put(key, value); - } - - public Object get(Object key) { - return storage.get(key); - } - - public Map getMap() { - return storage; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("{"); - - for (Map.Entry entry : storage.entrySet()) { - if (builder.length() > 1) { - builder.append(", "); - } - - builder.append(entry.getKey().toString()); - builder.append("=>"); - builder.append(entry.getValue().toString()); - } - - builder.append("}"); - return builder.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((storage == null) ? 0 : storage.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof RubyHash)) { - return false; - } - RubyHash other = (RubyHash) obj; - if (storage == null) { - if (other.storage != null) { - return false; - } - } else if (!storage.equals(other.storage)) { - return false; - } - return true; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyMatchData.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyMatchData.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -/** - * Represents the Ruby {@code MatchData} class. - */ -public class RubyMatchData extends RubyObject { - - private final Object[] values; - - public RubyMatchData(RubyClass rubyClass, Object[] values) { - super(rubyClass); - this.values = values; - } - - public Object[] valuesAt(int... indices) { - final Object[] result = new Object[indices.length]; - - for (int n = 0; n < indices.length; n++) { - result[n] = values[indices[n]]; - } - - return result; - } - - public Object[] getValues() { - return values; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyModule.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyModule.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.lookup.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Module} class. - */ -public class RubyModule extends RubyObject implements LookupNode { - - /** - * The class from which we create the object that is {@code Module}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyModule} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyModuleClass extends RubyClass { - - public RubyModuleClass(RubyContext context) { - super(context, null, null, null, "Module"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyModule(this, null, "(unnamed module)"); - } - - } - - /** - * The slot within a module definition method frame where we store the implicit state that is - * the current visibility for new methods. - */ - public static final Object VISIBILITY_FRAME_SLOT_ID = new Object(); - - /** - * The slot within a module definition method frame where we store the implicit state that is - * the flag for whether or not new methods will be module methods (functions is the term). - */ - public static final Object MODULE_FUNCTION_FLAG_FRAME_SLOT_ID = new Object(); - - // The context is stored here - objects can obtain it via their class (which is a module) - private final RubyContext context; - - /* - * The module in which this module was defined. By analogy, if superclass is the dynamic scope, - * the parent module is the lexical scope. - */ - private final RubyModule parentModule; - - /* - * The first thing to lookup names in. Not always the class, as we also have singleton classes, - * included modules etc. - */ - private LookupNode lookupParent = LookupTerminal.INSTANCE; - - private final String name; - private final Map methods = new HashMap<>(); - private final Map constants = new HashMap<>(); - private final Map classVariables = new HashMap<>(); - - private final CyclicAssumption unmodifiedAssumption; - - /** - * Keep track of other modules that depend on the configuration of this module in some way. The - * include subclasses and modules that include this module. - */ - private final Set dependents = Collections.newSetFromMap(new WeakHashMap()); - - public RubyModule(RubyClass rubyClass, RubyModule parentModule, String name) { - this(rubyClass.getContext(), rubyClass, parentModule, name); - } - - public RubyModule(RubyContext context, RubyClass rubyClass, RubyModule parentModule, String name) { - super(rubyClass); - - this.context = context; - this.parentModule = parentModule; - this.name = name; - - unmodifiedAssumption = new CyclicAssumption(name + " is unmodified"); - - /* - * Modules always go into the object space manager. Manually allocate an objectID, because - * the lazy mechanism uses the Ruby class of the object, which may not be set yet during - * bootstrap. - */ - - objectID = context.getNextObjectID(); - context.getObjectSpaceManager().add(this); - } - - public RubyModule getParentModule() { - return parentModule; - } - - public void include(RubyModule module) { - checkFrozen(); - - lookupParent = new LookupFork(module, lookupParent); - newVersion(); - module.addDependent(this); - } - - /** - * Set the value of a constant, possibly redefining it. - */ - public void setConstant(String constantName, Object value) { - assert RubyContext.shouldObjectBeVisible(value); - - checkFrozen(); - - getConstants().put(constantName, value); - newVersion(); - // TODO(CS): warn when redefining a constant - } - - public void setClassVariable(String variableName, Object value) { - assert RubyContext.shouldObjectBeVisible(value); - - checkFrozen(); - - if (!setClassVariableIfAlreadySet(variableName, value)) { - classVariables.put(variableName, value); - } - } - - public boolean setClassVariableIfAlreadySet(String variableName, Object value) { - assert RubyContext.shouldObjectBeVisible(value); - - checkFrozen(); - - if (lookupParent.setClassVariableIfAlreadySet(variableName, value)) { - return true; - } - - if (classVariables.containsKey(variableName)) { - classVariables.put(variableName, value); - return true; - } - - return false; - } - - public void removeClassVariable(String variableName) { - checkFrozen(); - - classVariables.remove(variableName); - } - - public void setModuleConstant(String constantName, Object value) { - checkFrozen(); - - setConstant(constantName, value); - getSingletonClass().setConstant(constantName, value); - } - - public void addMethod(RubyMethod method) { - checkFrozen(); - getMethods().put(method.getName(), method); - newVersion(); - } - - /** - * Remove a method from this module. - */ - public void removeMethod(String methodName) { - checkFrozen(); - - getMethods().remove(methodName); - newVersion(); - } - - public void undefMethod(String methodName) { - undefMethod(lookupMethod(methodName)); - } - - public void undefMethod(RubyMethod method) { - addMethod(method.undefined()); - } - - /** - * Alias a method. - */ - public void alias(String newName, String oldName) { - final RubyMethod method = lookupMethod(oldName); - - if (method == null) { - CompilerDirectives.transferToInterpreter(); - throw new RuntimeException("Couldn't alias as coudln't find " + oldName); - } - - addMethod(method.withNewName(newName)); - } - - @Override - public Object lookupConstant(String constantName) { - Object value; - - // Look in this module - - value = getConstants().get(constantName); - - if (value != null) { - return value; - } - - // Look in the parent module - - if (parentModule != null) { - value = parentModule.lookupConstant(constantName); - - if (value != null) { - return value; - } - } - - // Look in the lookup parent - - return lookupParent.lookupConstant(constantName); - } - - @Override - public Object lookupClassVariable(String variableName) { - // Look in this module - - final Object value = classVariables.get(variableName); - - if (value != null) { - return value; - } - - // Look in the parent - - return lookupParent.lookupClassVariable(variableName); - } - - public Set getClassVariables() { - final Set classVariablesSet = new HashSet<>(); - - classVariablesSet.addAll(classVariables.keySet()); - classVariablesSet.addAll(lookupParent.getClassVariables()); - - return classVariablesSet; - } - - @Override - public RubyMethod lookupMethod(String methodName) { - // Look in this module - - final RubyMethod method = getMethods().get(methodName); - - if (method != null) { - return method; - } - - // Look in the parent - - return lookupParent.lookupMethod(methodName); - } - - public void appendFeatures(RubyModule other) { - // TODO(CS): check only run once - - for (Map.Entry constantEntry : getConstants().entrySet()) { - final String constantName = constantEntry.getKey(); - final Object constantValue = constantEntry.getValue(); - other.setModuleConstant(constantName, constantValue); - } - - for (Map.Entry methodEntry : getMethods().entrySet()) { - final String methodName = methodEntry.getKey(); - final RubyMethod method = methodEntry.getValue(); - other.addMethod(method.withNewName(methodName)); - } - } - - public RubyContext getContext() { - return context; - } - - public String getName() { - return name; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public String toString() { - return name; - } - - public void newVersion() { - unmodifiedAssumption.invalidate(); - - // Make dependents new versions - - for (RubyModule dependent : dependents) { - dependent.newVersion(); - } - } - - public void addDependent(RubyModule dependent) { - dependents.add(dependent); - } - - public Assumption getUnmodifiedAssumption() { - return unmodifiedAssumption.getAssumption(); - } - - public void getMethods(Map foundMethods) { - lookupParent.getMethods(foundMethods); - - for (RubyMethod method : methods.values()) { - foundMethods.put(method.getName(), method); - } - } - - public static void setCurrentVisibility(Frame frame, Visibility visibility) { - final FrameSlot slot = frame.getFrameDescriptor().findFrameSlot(VISIBILITY_FRAME_SLOT_ID); - - frame.setObject(slot, visibility); - } - - public void visibilityMethod(PackedFrame frame, Object[] arguments, Visibility visibility) { - if (arguments.length == 0) { - setCurrentVisibility(frame.unpack(), visibility); - } else { - for (Object arg : arguments) { - final RubyMethod method = lookupMethod(arg.toString()); - - if (method == null) { - throw new RuntimeException("Couldn't find method " + arg.toString()); - } - - /* - * If the method was already defined in this class, that's fine {@link addMethod} - * will overwrite it, otherwise we do actually want to add a copy of the method with - * a different visibility to this module. - */ - - addMethod(method.withNewVisibility(visibility)); - } - } - } - - public List getDeclaredMethods() { - return new ArrayList<>(getMethods().values()); - } - - public void moduleEval(String source) { - getRubyClass().getContext().eval(source, this); - } - - public Map getConstants() { - return constants; - } - - public Map getMethods() { - return methods; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyNilClass.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyNilClass.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * Represents the Ruby {@code NilClass} class. - */ -public class RubyNilClass extends RubyObject { - - public RubyNilClass(RubyClass rubyClass) { - super(rubyClass); - } - - @Override - public boolean equals(Object other) { - return other instanceof RubyNilClass || other instanceof NilPlaceholder; - } - - @Override - public int hashCode() { - return 0; - } - - public static boolean isNil(Object block) { - return block instanceof NilPlaceholder || block instanceof RubyNilClass; - } - - @Override - public String toString() { - return ""; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyObject.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyObject.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Object} class. - */ -public class RubyObject extends RubyBasicObject { - - public boolean frozen = false; - - public RubyObject(RubyClass rubyClass) { - super(rubyClass); - } - - public void checkFrozen() { - if (frozen) { - CompilerDirectives.transferToInterpreter(); - throw new RaiseException(getRubyClass().getContext().getCoreLibrary().frozenError(getRubyClass().getName().toLowerCase())); - } - } - - public Object dup() { - final RubyObject newObject = new RubyObject(rubyClass); - newObject.setInstanceVariables(getInstanceVariables()); - return newObject; - } - - public static String checkInstanceVariableName(RubyContext context, String name) { - if (!name.startsWith("@")) { - throw new RaiseException(context.getCoreLibrary().nameErrorInstanceNameNotAllowable(name)); - } - - return name.substring(1); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyProc.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyProc.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Proc} class. - */ -public class RubyProc extends RubyObject { - - /** - * The class from which we create the object that is {@code Proc}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyProc} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyProcClass extends RubyClass { - - public RubyProcClass(RubyClass objectClass) { - super(null, objectClass, "Proc"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyProc(this); - } - - } - - public static enum Type { - PROC, LAMBDA - } - - @CompilationFinal private Type type; - @CompilationFinal private Object self; - @CompilationFinal private RubyProc block; - @CompilationFinal private RubyMethod method; - - public RubyProc(RubyClass procClass) { - super(procClass); - } - - public RubyProc(RubyClass procClass, Type type, Object self, RubyProc block, RubyMethod method) { - super(procClass); - initialize(type, self, block, method); - } - - public void initialize(Type setType, Object setSelf, RubyProc setBlock, RubyMethod setMethod) { - assert setSelf != null; - assert RubyContext.shouldObjectBeVisible(setSelf); - type = setType; - self = setSelf; - block = setBlock; - method = setMethod; - } - - public Object getSelf() { - return self; - } - - @CompilerDirectives.SlowPath - public Object call(PackedFrame caller, Object... args) { - return callWithModifiedSelf(caller, self, args); - } - - public Object callWithModifiedSelf(PackedFrame caller, Object modifiedSelf, Object... args) { - assert modifiedSelf != null; - - try { - return method.call(caller, modifiedSelf, block, args); - } catch (ReturnException e) { - switch (type) { - case PROC: - throw e; - case LAMBDA: - return e.getValue(); - default: - throw new IllegalStateException(); - } - } - } - - public RubyMethod getMethod() { - return method; - } - - public Type getType() { - return type; - } - - public RubyProc getBlock() { - return block; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyRegexp.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyRegexp.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.regex.*; - -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Regexp} class. - */ -public class RubyRegexp extends RubyObject { - - /** - * The class from which we create the object that is {@code Regexp}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyRegexp} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyRegexpClass extends RubyClass { - - public RubyRegexpClass(RubyClass objectClass) { - super(null, objectClass, "Regexp"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyRegexp(getContext().getCoreLibrary().getRegexpClass()); - } - - } - - @CompilationFinal private Pattern pattern; - - public RubyRegexp(RubyClass regexpClass) { - super(regexpClass); - } - - public RubyRegexp(RubyClass regexpClass, String pattern) { - this(regexpClass); - initialize(compile(pattern)); - } - - public RubyRegexp(RubyClass regexpClass, Pattern pattern) { - this(regexpClass); - initialize(pattern); - } - - public void initialize(String setPattern) { - pattern = compile(setPattern); - } - - public void initialize(Pattern setPattern) { - pattern = setPattern; - } - - public Object matchOperator(Frame frame, String string) { - final RubyContext context = getRubyClass().getContext(); - - final Matcher matcher = pattern.matcher(string); - - if (matcher.find()) { - for (int n = 1; n < matcher.groupCount() + 1; n++) { - final FrameSlot slot = frame.getFrameDescriptor().findFrameSlot("$" + n); - - if (slot != null) { - frame.setObject(slot, context.makeString(matcher.group(n))); - } - } - - return matcher.start(); - } else { - return NilPlaceholder.INSTANCE; - } - } - - public Pattern getPattern() { - return pattern; - } - - public Object match(String string) { - final RubyContext context = getRubyClass().getContext(); - - final Matcher matcher = pattern.matcher(string); - - if (!matcher.find()) { - return NilPlaceholder.INSTANCE; - } - - final Object[] values = new Object[matcher.groupCount() + 1]; - - for (int n = 0; n < matcher.groupCount() + 1; n++) { - final String group = matcher.group(n); - - if (group == null) { - values[n] = NilPlaceholder.INSTANCE; - } else { - values[n] = context.makeString(group); - } - } - - return new RubyMatchData(context.getCoreLibrary().getMatchDataClass(), values); - } - - @Override - public int hashCode() { - return pattern.pattern().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof RubyRegexp)) { - return false; - } - RubyRegexp other = (RubyRegexp) obj; - if (pattern == null) { - if (other.pattern != null) { - return false; - } - } else if (!pattern.pattern().equals(other.pattern.pattern())) { - return false; - } - return true; - } - - public static Pattern compile(String pattern) { - return Pattern.compile(pattern, Pattern.MULTILINE | Pattern.UNIX_LINES); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyString.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyString.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.math.*; -import java.nio.*; -import java.nio.charset.*; -import java.util.*; -import java.util.regex.*; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.array.*; -import com.oracle.truffle.ruby.runtime.core.range.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code String} class. - */ -public class RubyString extends RubyObject { - - /** - * The class from which we create the object that is {@code String}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyString} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyStringClass extends RubyClass { - - public RubyStringClass(RubyClass objectClass) { - super(null, objectClass, "String"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyString(getContext().getCoreLibrary().getStringClass(), ""); - } - - } - - private boolean fromJavaString; - - private Charset encoding; - private byte[] bytes; - - private String cachedStringValue; - - /** - * Construct a string from a Java {@link String}, lazily converting to bytes as needed. - */ - public RubyString(RubyClass stringClass, String value) { - super(stringClass); - fromJavaString = true; - encoding = null; - bytes = null; - cachedStringValue = value; - } - - /** - * Construct a string from bytes representing characters in an encoding, lazily converting to a - * Java {@link String} as needed. - */ - public RubyString(RubyClass stringClass, Charset encoding, byte[] bytes) { - super(stringClass); - fromJavaString = false; - this.encoding = encoding; - this.bytes = bytes; - cachedStringValue = null; - } - - public RubyString(RubyString copyOf) { - super(copyOf.getRubyClass().getContext().getCoreLibrary().getStringClass()); - fromJavaString = copyOf.fromJavaString; - encoding = copyOf.encoding; - - if (copyOf.bytes != null) { - bytes = Arrays.copyOf(copyOf.bytes, copyOf.bytes.length); - } else { - bytes = null; - } - - cachedStringValue = copyOf.cachedStringValue; - } - - public boolean isFromJavaString() { - return fromJavaString; - } - - public byte[] getBytes() { - return bytes; - } - - public void replace(String value) { - fromJavaString = true; - encoding = null; - bytes = null; - cachedStringValue = value; - } - - @Override - public String toString() { - if (cachedStringValue == null) { - cachedStringValue = encoding.decode(ByteBuffer.wrap(bytes)).toString(); - } - - return cachedStringValue; - } - - @Override - public boolean equals(Object other) { - if (other == null) { - return false; - } - - // If the other value is a Java string, use our Java string representation to compare - - if (other instanceof String) { - return toString().equals(other); - } - - if (other instanceof RubyString) { - final RubyString otherString = (RubyString) other; - - // If we both came from Java strings, use them to compare - - if (fromJavaString && otherString.fromJavaString) { - return toString().equals(other.toString()); - } - - // If we both have the same encoding, compare bytes - - if (encoding == otherString.encoding) { - return Arrays.equals(bytes, otherString.bytes); - } - - // If we don't have the same encoding, we need some more advanced logic - - throw new UnsupportedOperationException("Can't compare strings in different encodings yet"); - } - - return false; - } - - @Override - public int hashCode() { - return toString().hashCode(); - } - - public static Object getIndex(RubyContext context, String string, Object[] args) { - if (args.length == 1) { - final Object index = args[0]; - - if (index instanceof Integer) { - final int stringLength = string.length(); - final int normalisedIndex = ArrayUtilities.normaliseIndex(stringLength, (int) index); - - return context.makeString(string.charAt(normalisedIndex)); - } else if (index instanceof FixnumRange) { - final FixnumRange range = (FixnumRange) index; - - final int stringLength = string.length(); - - if (range.doesExcludeEnd()) { - final int begin = ArrayUtilities.normaliseIndex(stringLength, range.getBegin()); - final int exclusiveEnd = ArrayUtilities.normaliseExclusiveIndex(stringLength, range.getExclusiveEnd()); - return context.makeString(string.substring(begin, exclusiveEnd)); - } else { - final int begin = ArrayUtilities.normaliseIndex(stringLength, range.getBegin()); - final int inclusiveEnd = ArrayUtilities.normaliseIndex(stringLength, range.getInclusiveEnd()); - return context.makeString(string.substring(begin, inclusiveEnd + 1)); - } - } else { - throw new UnsupportedOperationException("Don't know how to index a string with " + index.getClass()); - } - } else { - final int rangeStart = (int) args[0]; - int rangeLength = (int) args[1]; - - if (rangeLength > string.length() - rangeStart) { - rangeLength = string.length() - rangeStart; - } - - if (rangeStart > string.length()) { - return NilPlaceholder.INSTANCE; - } - - return context.makeString(string.substring(rangeStart, rangeStart + rangeLength)); - } - } - - @Override - public Object dup() { - return new RubyString(this); - } - - public void concat(RubyString other) { - if (fromJavaString && other.fromJavaString) { - cachedStringValue += other.cachedStringValue; - encoding = null; - bytes = null; - } else { - throw new UnsupportedOperationException("Don't know how to append strings with encodings"); - } - } - - public static String ljust(String string, int length, String padding) { - final StringBuilder builder = new StringBuilder(); - - builder.append(string); - - int n = 0; - - while (builder.length() < length) { - builder.append(padding.charAt(n)); - - n++; - - if (n == padding.length()) { - n = 0; - } - } - - return builder.toString(); - } - - public static String rjust(String string, int length, String padding) { - final StringBuilder builder = new StringBuilder(); - - int n = 0; - - while (builder.length() + string.length() < length) { - builder.append(padding.charAt(n)); - - n++; - - if (n == padding.length()) { - n = 0; - } - } - - builder.append(string); - - return builder.toString(); - } - - public static RubyArray scan(RubyContext context, String string, Pattern pattern) { - final Matcher matcher = pattern.matcher(string); - - final RubyArray results = new RubyArray(context.getCoreLibrary().getArrayClass()); - - while (matcher.find()) { - if (matcher.groupCount() == 0) { - results.push(context.makeString(matcher.group(0))); - } else { - final RubyArray subResults = new RubyArray(context.getCoreLibrary().getArrayClass()); - - for (int n = 1; n < matcher.groupCount() + 1; n++) { - subResults.push(context.makeString(matcher.group(n))); - } - - results.push(subResults); - } - } - - return results; - } - - public Object toInteger() { - if (toString().length() == 0) { - return 0; - } - - try { - final int value = Integer.parseInt(toString()); - - if (value >= RubyFixnum.MIN_VALUE && value <= RubyFixnum.MAX_VALUE) { - return value; - } else { - return BigInteger.valueOf(value); - } - } catch (NumberFormatException e) { - return new BigInteger(toString()); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubySymbol.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubySymbol.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Symbol} class. - */ -public class RubySymbol extends RubyObject { - - private final String symbol; - - public RubySymbol(RubyClass symbolClass, String symbol) { - super(symbolClass); - this.symbol = symbol.intern(); - } - - public RubyProc toProc() { - final RubyContext context = getRubyClass().getContext(); - - final CallTarget callTarget = new CallTarget() { - - @Override - public Object call(PackedFrame frame, Arguments args) { - final RubyArguments rubyArgs = (RubyArguments) args; - final Object receiver = rubyArgs.getArguments()[0]; - final Object[] sendArgs = Arrays.copyOfRange(rubyArgs.getArguments(), 1, rubyArgs.getArguments().length); - final RubyBasicObject receiverObject = context.getCoreLibrary().box(receiver); - return receiverObject.send(symbol, rubyArgs.getBlock(), sendArgs); - } - - }; - - final CallTargetMethodImplementation methodImplementation = new CallTargetMethodImplementation(callTarget, null); - final RubyMethod method = new RubyMethod(null, null, new UniqueMethodIdentifier(), symbol, null, Visibility.PUBLIC, false, methodImplementation); - - return new RubyProc(context.getCoreLibrary().getProcClass(), RubyProc.Type.PROC, NilPlaceholder.INSTANCE, null, method); - } - - @Override - public String toString() { - return symbol; - } - - @Override - public String inspect() { - return ":" + symbol; - } - - @Override - public int hashCode() { - return symbol.hashCode(); - } - - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } else if (other instanceof RubySymbol) { - return symbol == ((RubySymbol) other).symbol; - } else if (other instanceof RubyString) { - return other.equals(symbol); - } else { - return super.equals(other); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyThread.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyThread.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.truffle.ruby.runtime.objects.*; -import com.oracle.truffle.ruby.runtime.subsystems.*; - -/** - * Represents the Ruby {@code Thread} class. Implemented using Java threads, but note that there is - * not a one-to-one mapping between Ruby threads and Java threads - specifically in combination with - * fibers as they are currently implemented as their own Java threads. - */ -public class RubyThread extends RubyObject { - - /** - * The class from which we create the object that is {@code Thread}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyThread} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyThreadClass extends RubyClass { - - public RubyThreadClass(RubyClass objectClass) { - super(null, objectClass, "Thread"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyThread(this, getContext().getThreadManager()); - } - - } - - private final ThreadManager manager; - - private final CountDownLatch finished = new CountDownLatch(1); - - private final int hashCode = new Random().nextInt(); - - public RubyThread(RubyClass rubyClass, ThreadManager manager) { - super(rubyClass); - this.manager = manager; - } - - public void initialize(RubyProc block) { - final RubyProc finalBlock = block; - - initialize(new Runnable() { - - @Override - public void run() { - finalBlock.call(null); - } - - }); - } - - public void initialize(Runnable runnable) { - final RubyThread finalThread = this; - final Runnable finalRunnable = runnable; - - new Thread(new Runnable() { - - @Override - public void run() { - finalThread.manager.registerThread(finalThread); - finalThread.manager.enterGlobalLock(finalThread); - - try { - finalRunnable.run(); - } finally { - finalThread.manager.leaveGlobalLock(); - finalThread.manager.unregisterThread(finalThread); - finalThread.finished.countDown(); - } - } - - }).start(); - } - - @Override - public int hashCode() { - return hashCode; - } - - public void shutdown() { - } - - public void join() { - final RubyThread runningThread = getRubyClass().getContext().getThreadManager().leaveGlobalLock(); - - try { - while (true) { - try { - finished.await(); - break; - } catch (InterruptedException e) { - // Await again - } - } - } finally { - runningThread.manager.enterGlobalLock(runningThread); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTime.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTime.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.text.*; -import java.util.*; - -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code Time} class. This is a very rough implementation and is only really - * enough to run benchmark harnesses. - */ -public class RubyTime extends RubyObject { - - /** - * The class from which we create the object that is {@code Time}. A subclass of - * {@link RubyClass} so that we can override {@link #newInstance} and allocate a - * {@link RubyTime} rather than a normal {@link RubyBasicObject}. - */ - public static class RubyTimeClass extends RubyClass { - - public RubyTimeClass(RubyClass objectClass) { - super(null, objectClass, "Time"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyTime(this, milisecondsToNanoseconds(System.currentTimeMillis())); - } - - } - - private final long nanoseconds; - - public RubyTime(RubyClass timeClass, long nanoseconds) { - super(timeClass); - this.nanoseconds = nanoseconds; - } - - /** - * Subtract one time from another, producing duration in seconds. - */ - public double subtract(RubyTime other) { - return nanosecondsToSecond(nanoseconds - other.nanoseconds); - } - - @Override - public String toString() { - /* - * I think this is ISO 8601 with a custom time part. Note that Ruby's time formatting syntax - * is different to Java's. - */ - - return new SimpleDateFormat("Y-MM-d H:m:ss Z").format(toDate()); - } - - private Date toDate() { - return new Date(nanosecondsToMiliseconds(nanoseconds)); - } - - public static RubyTime fromDate(RubyClass timeClass, long timeMiliseconds) { - return new RubyTime(timeClass, milisecondsToNanoseconds(timeMiliseconds)); - } - - private static long milisecondsToNanoseconds(long miliseconds) { - return miliseconds * 1000000; - } - - private static long nanosecondsToMiliseconds(long nanoseconds) { - return nanoseconds / 1000000; - } - - private static double nanosecondsToSecond(long nanoseconds) { - return nanoseconds / 1e9; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTrueClass.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTrueClass.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Represents the Ruby {@code TrueClass} class. - */ -public class RubyTrueClass extends RubyObject implements Unboxable { - - public RubyTrueClass(RubyClass objectClass) { - super(objectClass); - } - - public Object unbox() { - return true; - } - - @Override - public String toString() { - return "true"; - } - - @Override - public boolean equals(Object other) { - return other instanceof RubyTrueClass || (other instanceof Boolean && (boolean) other); - } - - @Override - public int hashCode() { - return Boolean.TRUE.hashCode(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/StringFormatter.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/StringFormatter.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2013 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.core; - -import java.io.*; -import java.util.*; - -import com.oracle.truffle.ruby.runtime.core.array.*; - -public class StringFormatter { - - public static String format(String format, List values) { - final ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); - final PrintStream printStream = new PrintStream(byteArray); - - format(printStream, format, values); - - return byteArray.toString(); - } - - public static void format(PrintStream stream, String format, List values) { - /* - * See http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-sprintf. - * - * At the moment we just do the basics that we need. We will need a proper lexer later on. - * Or better than that we could compile to Truffle nodes if the format string is constant! I - * don't think we can easily translate to Java's format syntax, otherwise JRuby would do - * that and they don't. - */ - - // I'm not using a for loop, because Checkstyle won't let me modify the control variable - - int n = 0; - int v = 0; - - while (n < format.length()) { - final char c = format.charAt(n); - n++; - - if (c == '%') { - // %[flags][width][.precision]type - - final String flagChars = "0"; - - boolean zeroPad = false; - - while (n < format.length() && flagChars.indexOf(format.charAt(n)) != -1) { - switch (format.charAt(n)) { - case '0': - zeroPad = true; - break; - } - - n++; - } - - int width; - - if (n < format.length() && Character.isDigit(format.charAt(n))) { - final int widthStart = n; - - while (Character.isDigit(format.charAt(n))) { - n++; - } - - width = Integer.parseInt(format.substring(widthStart, n)); - } else { - width = 0; - } - - int precision; - - if (format.charAt(n) == '.') { - n++; - - final int precisionStart = n; - - while (Character.isDigit(format.charAt(n))) { - n++; - } - - precision = Integer.parseInt(format.substring(precisionStart, n)); - } else { - precision = 5; - } - - final char type = format.charAt(n); - n++; - - final StringBuilder formatBuilder = new StringBuilder(); - - formatBuilder.append("%"); - - if (width > 0) { - if (zeroPad) { - formatBuilder.append("0"); - } - - formatBuilder.append(width); - } - - switch (type) { - case 'd': { - formatBuilder.append("d"); - final int value = GeneralConversions.toFixnum(values.get(v)); - stream.printf(formatBuilder.toString(), value); - break; - } - - case 'f': { - formatBuilder.append("."); - formatBuilder.append(precision); - formatBuilder.append("f"); - final double value = GeneralConversions.toFloat(values.get(v)); - stream.printf(formatBuilder.toString(), value); - break; - } - - default: - throw new RuntimeException("Kernel#sprintf error"); - } - - v++; - } else { - stream.print(c); - } - } - } - - public static void formatPuts(PrintStream stream, List args) { - if (args.size() > 0) { - formatPutsInner(stream, args); - } else { - stream.println(); - } - } - - public static void formatPutsInner(PrintStream stream, List args) { - if (args.size() > 0) { - for (Object arg : args) { - if (arg instanceof RubyArray) { - final RubyArray array = (RubyArray) arg; - formatPutsInner(stream, array.asList()); - } else { - stream.println(arg); - } - } - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayStore.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayStore.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -/** - * Interface to various ways to store values in arrays. - */ -public interface ArrayStore { - - /** - * Get the size of the store. - */ - int size(); - - /** - * Get a value from the array using a normalized index. - */ - Object get(int normalisedIndex); - - /** - * Get a range of values from an array store. - */ - ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd); - - /** - * Set a value at an index, or throw {@link GeneraliseArrayStoreException} if that's not - * possible. - */ - void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException; - - /** - * Set a range to be a single value, or throw {@link GeneraliseArrayStoreException} if that's - * not possible. - */ - void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException; - - /** - * Set a range to be a copied from another array, or throw {@link GeneraliseArrayStoreException} - * if that's not possible. - */ - void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException; - - /** - * Insert a value at an index, or throw {@link GeneraliseArrayStoreException} if that's not - * possible. - */ - void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException; - - /** - * Push a value onto the end, or throw {@link GeneraliseArrayStoreException} if that's not - * possible. - */ - void push(Object value) throws GeneraliseArrayStoreException; - - /** - * Delete a value at an index, returning the value. - */ - Object deleteAt(int normalisedIndex); - - /** - * Does a store contain a value? - */ - boolean contains(Object value); - - /** - * Duplicate the store. - */ - ArrayStore dup(); - - /** - * Duplicate the store, in a format which can store an object. - */ - ArrayStore generalizeFor(Object type); - - /** - * Get the type of value stored. - */ - Object getIndicativeValue(); - - /** - * Get the contents of the store as a new array. - */ - Object[] toObjectArray(); - - /** - * Does one store equal another. - */ - boolean equals(ArrayStore other); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayUtilities.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayUtilities.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.core.array; - -/** - * Simple array utilities, not tied to any particular implementation. - */ -public abstract class ArrayUtilities { - - /** - * Apply Ruby's wrap-around index semantics. - */ - public static int normaliseIndex(int length, int index) { - if (index < 0) { - return length + index; - } else { - return index; - } - } - - /** - * Apply Ruby's wrap-around index semantics. - */ - public static int normaliseExclusiveIndex(int length, int exclusiveIndex) { - if (exclusiveIndex < 0) { - return length + exclusiveIndex + 1; - } else { - return exclusiveIndex; - } - } - - /** - * If an exclusive index is beyond the end of the array, truncate it to be length of the array. - */ - public static int truncateNormalisedExclusiveIndex(int length, int normalisedExclusiveEnd) { - return Math.min(length, normalisedExclusiveEnd); - } - - /** - * What capacity should we allocate for a given requested length? - */ - public static int capacityFor(int length) { - return Math.max(16, length * 2); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/BaseArrayStore.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/BaseArrayStore.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -/** - * Contains implementations of as much of the array stores that we could easily share. Much of the - * rest depends on static types in method signatures, so is lexically almost the same, but isn't the - * same in type, and as the whole point is to avoid boxing, we can't use Java's generics. - */ -public abstract class BaseArrayStore implements ArrayStore { - - protected int capacity; - protected int size; - - @Override - public int size() { - return size; - } - - /** - * Set a range in the array to be another range. You must ensure that the otherValues array is - * of the same type as your values array. - */ - protected void setRangeArrayMatchingTypes(int normalisedBegin, int normalisedExclusiveEnd, Object otherValues, int otherSize) { - // Is the range the whole array? - - if (normalisedBegin == 0 && normalisedExclusiveEnd == size) { - // Do we already have enough space? - - if (otherSize <= capacity) { - // Copy to our existing array. - final Object values = getValuesArrayObject(); - System.arraycopy(otherValues, 0, values, 0, otherSize); - } else { - // Create a new copy of their array. - setCapacityWithNewArray(otherSize); - final Object values = getValuesArrayObject(); - System.arraycopy(otherValues, 0, values, 0, otherSize); - } - - size = otherSize; - } else { - final int rangeLength = normalisedExclusiveEnd - normalisedBegin; - - // Create extra space - might be negative if the new range is shorter, or zero. - - final int extraSpaceNeeded = otherSize - rangeLength; - - if (extraSpaceNeeded > 0) { - createSpace(normalisedBegin, extraSpaceNeeded); - } else if (extraSpaceNeeded < 0) { - deleteSpace(normalisedBegin, -extraSpaceNeeded); - } - - // Copy across the new values. - final Object values = getValuesArrayObject(); - System.arraycopy(otherValues, 0, values, normalisedBegin, otherSize); - } - } - - protected void createSpace(int normalisedBegin, int count) { - /* - * Is this space at the end or in the middle? - */ - - if (normalisedBegin == size) { - createSpaceAtEnd(count); - } else { - /* - * Create space in the middle - is the array already big enough? - */ - - final int elementsToMove = size - normalisedBegin; - - if (size + count > capacity) { - /* - * The array isn't big enough. We don't want to use Arrays.copyOf because that will - * do wasted copying of the elements we are about to move. However - is - * Arrays.copyOf clever enough to see that only one instance of Array is using the - * block and use realloc, potentially avoiding a malloc and winning? - */ - - final Object values = getValuesArrayObject(); - setCapacityWithNewArray(ArrayUtilities.capacityFor(size + count)); - final Object newValues = getValuesArrayObject(); - System.arraycopy(values, 0, newValues, 0, normalisedBegin); - System.arraycopy(values, normalisedBegin, newValues, normalisedBegin + count, elementsToMove); - } else { - /* - * The array is already big enough - we can copy elements already in the array to - * make space. - */ - - final Object values = getValuesArrayObject(); - System.arraycopy(values, normalisedBegin, values, normalisedBegin + count, elementsToMove); - } - - size += count; - } - } - - protected void createSpaceAtEnd(int count) { - /* - * Create space at the end - we can do this by creating a copy of the array if needed. - */ - - if (size + count > capacity) { - setCapacityByCopying(ArrayUtilities.capacityFor(size + count)); - } - - size += count; - } - - protected void deleteSpace(int normalisedBegin, int count) { - final Object values = getValuesArrayObject(); - final int elementsToMove = size - normalisedBegin - count; - - if (elementsToMove > 0) { - System.arraycopy(values, normalisedBegin + count, values, normalisedBegin, elementsToMove); - } - - size -= count; - } - - protected abstract void setCapacityByCopying(int newCapacity); - - protected abstract void setCapacityWithNewArray(int newCapacity); - - protected abstract Object getValuesArrayObject(); - - @Override - public boolean equals(ArrayStore other) { - for (int n = 0; n < size; n++) { - if (!other.get(n).equals(get(n))) { - return false; - } - } - - return true; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/EmptyArrayStore.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/EmptyArrayStore.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * An array store that can only be empty. - */ -public final class EmptyArrayStore implements ArrayStore { - - public static final EmptyArrayStore INSTANCE = new EmptyArrayStore(); - - private EmptyArrayStore() { - } - - @Override - public int size() { - return 0; - } - - @Override - public Object get(int normalisedIndex) { - return NilPlaceholder.INSTANCE; - } - - @Override - public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) { - return null; // Represents Nil - } - - @Override - public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - throw new GeneraliseArrayStoreException(); - } - - @Override - public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException { - throw new GeneraliseArrayStoreException(); - } - - @Override - public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException { - throw new GeneraliseArrayStoreException(); - } - - @Override - public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - throw new GeneraliseArrayStoreException(); - } - - @Override - public void push(Object value) throws GeneraliseArrayStoreException { - throw new GeneraliseArrayStoreException(); - } - - @Override - public Object deleteAt(int normalisedIndex) { - throw new UnsupportedOperationException("Cannot delete from an empty array"); - } - - @Override - public ArrayStore dup() { - return this; - } - - @Override - public boolean contains(Object value) { - return false; - } - - @Override - public ArrayStore generalizeFor(Object type) { - if (type instanceof Integer) { - return new FixnumArrayStore(); - } else { - return new ObjectArrayStore(); - } - } - - @Override - public Object getIndicativeValue() { - return null; - } - - @Override - public Object[] toObjectArray() { - return new Object[]{}; - } - - @Override - public boolean equals(ArrayStore other) { - if (other == null) { - return false; - } else if (other == this) { - return true; - } else { - return other.size() == 0; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumArrayStore.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumArrayStore.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A store for an array of Fixnums. - */ -public final class FixnumArrayStore extends BaseArrayStore { - - private int[] values; - - public FixnumArrayStore() { - this(new int[]{}); - } - - public FixnumArrayStore(int[] values) { - this.values = values; - size = values.length; - capacity = values.length; - } - - @Override - public Object get(int normalisedIndex) { - try { - return getFixnum(normalisedIndex); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - public int getFixnum(int normalisedIndex) throws UnexpectedResultException { - if (normalisedIndex >= size) { - throw new UnexpectedResultException(NilPlaceholder.INSTANCE); - } - - return values[normalisedIndex]; - } - - @Override - public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) { - if (normalisedBegin >= size) { - return null; // Represents Nil - } - - return new FixnumArrayStore(Arrays.copyOfRange(values, normalisedBegin, truncatedNormalisedExclusiveEnd)); - } - - @Override - public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - if (value instanceof Integer) { - setFixnum(normalisedIndex, (int) value); - } else { - throw new GeneraliseArrayStoreException(); - } - } - - public void setFixnum(int normalisedIndex, int value) throws GeneraliseArrayStoreException { - if (normalisedIndex > size) { - throw new GeneraliseArrayStoreException(); - } - - if (normalisedIndex == size) { - push(value); - } else { - values[normalisedIndex] = value; - } - } - - @Override - public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException { - if (value instanceof Integer) { - setRangeSingleFixnum(normalisedBegin, truncatedNormalisedExclusiveEnd, (int) value); - } else { - throw new GeneraliseArrayStoreException(); - } - } - - public void setRangeSingleFixnum(int normalisedBegin, int truncatedNormalisedExclusiveEnd, int value) { - // Is the range the whole array? - - if (normalisedBegin == 0 && truncatedNormalisedExclusiveEnd == size) { - // Reset length and set the value. - size = 1; - values[0] = value; - } else { - // Delete the range, except for the first value. - deleteSpace(normalisedBegin + 1, truncatedNormalisedExclusiveEnd - normalisedBegin - 1); - - // Set the value we left in. - values[normalisedBegin] = value; - } - } - - @Override - public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException { - if (other instanceof FixnumArrayStore) { - setRangeArrayFixnum(normalisedBegin, normalisedExclusiveEnd, (FixnumArrayStore) other); - } else { - throw new GeneraliseArrayStoreException(); - } - } - - public void setRangeArrayFixnum(int normalisedBegin, int normalisedExclusiveEnd, FixnumArrayStore other) { - setRangeArrayMatchingTypes(normalisedBegin, normalisedExclusiveEnd, other.values, other.size); - } - - @Override - public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - if (value instanceof Integer) { - insertFixnum(normalisedIndex, (int) value); - } else { - throw new GeneraliseArrayStoreException(); - } - } - - public void insertFixnum(int normalisedIndex, int value) throws GeneraliseArrayStoreException { - if (normalisedIndex > size) { - throw new GeneraliseArrayStoreException(); - } - - createSpace(normalisedIndex, 1); - values[normalisedIndex] = value; - } - - @Override - public void push(Object value) throws GeneraliseArrayStoreException { - if (value instanceof Integer) { - pushFixnum((int) value); - } else { - throw new GeneraliseArrayStoreException(); - } - } - - public void pushFixnum(int value) { - createSpaceAtEnd(1); - values[size - 1] = value; - } - - @Override - public Object deleteAt(int normalisedIndex) { - try { - return deleteAtFixnum(normalisedIndex); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - public int deleteAtFixnum(int normalisedIndex) throws UnexpectedResultException { - if (normalisedIndex >= size) { - CompilerDirectives.transferToInterpreter(); - throw new UnexpectedResultException(NilPlaceholder.INSTANCE); - } - - final int value = values[normalisedIndex]; - - deleteSpace(normalisedIndex, 1); - - return value; - } - - @Override - public ArrayStore dup() { - return new FixnumArrayStore(Arrays.copyOf(values, size)); - } - - @Override - public boolean contains(Object value) { - if (!(value instanceof Integer)) { - return false; - } - - final int intValue = (int) value; - - for (int n = 0; n < size; n++) { - if (values[n] == intValue) { - return true; - } - } - - return false; - } - - @Override - public ArrayStore generalizeFor(Object type) { - return new ObjectArrayStore(toObjectArray()); - } - - @Override - public Object getIndicativeValue() { - return 0; - } - - @Override - protected void setCapacityByCopying(int newCapacity) { - values = Arrays.copyOf(values, newCapacity); - capacity = values.length; - } - - @Override - protected void setCapacityWithNewArray(int newCapacity) { - values = new int[newCapacity]; - capacity = values.length; - } - - @Override - protected Object getValuesArrayObject() { - return values; - } - - @Override - public Object[] toObjectArray() { - final Object[] objectValues = new Object[size]; - - // System.arraycopy will not box. - - for (int n = 0; n < size; n++) { - objectValues[n] = values[n]; - } - - return objectValues; - } - - @Override - public boolean equals(ArrayStore other) { - if (other instanceof FixnumArrayStore) { - return equals((FixnumArrayStore) other); - } else { - return super.equals(other); - } - } - - public boolean equals(FixnumArrayStore other) { - if (other == null) { - return false; - } else if (other == this) { - return true; - } else if (other.size != size) { - return false; - } else if (other.capacity == capacity) { - return Arrays.equals(other.values, values); - } else { - for (int n = 0; n < size; n++) { - if (other.values[n] != values[n]) { - return false; - } - } - - return true; - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumImmutablePairArrayStore.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumImmutablePairArrayStore.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A store for a pair of Fixnums. - */ -public final class FixnumImmutablePairArrayStore extends BaseArrayStore { - - private final int first; - private final int second; - - public FixnumImmutablePairArrayStore(int first, int second) { - size = 2; - capacity = 2; - this.first = first; - this.second = second; - } - - @Override - public int size() { - return 2; - } - - @Override - public Object get(int normalisedIndex) { - switch (normalisedIndex) { - case 0: - return first; - case 1: - return second; - default: - return NilPlaceholder.INSTANCE; - } - } - - public int getFixnum(int normalisedIndex) throws UnexpectedResultException { - switch (normalisedIndex) { - case 0: - return first; - case 1: - return second; - default: - CompilerDirectives.transferToInterpreter(); - throw new UnexpectedResultException(NilPlaceholder.INSTANCE); - } - } - - @Override - public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) { - if (normalisedBegin >= size) { - return null; // Represents Nil - } - - return new FixnumArrayStore(Arrays.copyOfRange(new int[]{first, second}, normalisedBegin, truncatedNormalisedExclusiveEnd)); - } - - @Override - public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void push(Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public Object deleteAt(int normalisedIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public ArrayStore dup() { - return this; - } - - @Override - public boolean contains(Object value) { - if (value instanceof Integer) { - final int intValue = (int) value; - return first == intValue || second == intValue; - } else { - return false; - } - } - - @Override - public ArrayStore generalizeFor(Object type) { - return new ObjectArrayStore(toObjectArray()); - } - - @Override - public Object getIndicativeValue() { - return 0; - } - - @Override - protected void setCapacityByCopying(int newCapacity) { - throw new UnsupportedOperationException(); - } - - @Override - protected void setCapacityWithNewArray(int newCapacity) { - throw new UnsupportedOperationException(); - } - - @Override - protected Object getValuesArrayObject() { - return new int[]{first, second}; - } - - @Override - public Object[] toObjectArray() { - return new Object[]{first, second}; - } - - @Override - public boolean equals(ArrayStore other) { - if (other instanceof FixnumImmutablePairArrayStore) { - return equals((FixnumImmutablePairArrayStore) other); - } else { - return super.equals(other); - } - } - - public boolean equals(FixnumImmutablePairArrayStore other) { - if (other == null) { - return false; - } else if (other == this) { - return true; - } else { - return other.first == first && other.second == second; - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/GeneraliseArrayStoreException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/GeneraliseArrayStoreException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -import com.oracle.truffle.api.nodes.*; - -/** - * An exception that signals that an ArrayStore cannot store a given object because of its type, and - * that the store must be generalized to accommodate it. - */ -public class GeneraliseArrayStoreException extends SlowPathException { - - private static final long serialVersionUID = -7648655548414168177L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectArrayStore.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectArrayStore.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -import java.util.*; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * A store for an array of any objects. - */ -public final class ObjectArrayStore extends BaseArrayStore { - - private Object[] values; - - public ObjectArrayStore() { - this(new Object[]{}); - } - - public ObjectArrayStore(Object[] values) { - this.values = values; - size = values.length; - capacity = values.length; - } - - @Override - public Object get(int normalisedIndex) { - if (normalisedIndex >= size) { - return NilPlaceholder.INSTANCE; - } - - return values[normalisedIndex]; - } - - @Override - public ArrayStore getRange(int normalisedBegin, int normalisedExclusiveEnd) { - if (normalisedBegin >= size) { - return null; // Represents Nil - } - - return new ObjectArrayStore(Arrays.copyOfRange(values, normalisedBegin, normalisedExclusiveEnd)); - } - - @Override - public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - if (normalisedIndex > size) { - final int originalLength = size; - createSpace(size, normalisedIndex - size + 1); - Arrays.fill(values, originalLength, normalisedIndex, NilPlaceholder.INSTANCE); - values[normalisedIndex] = value; - } else if (normalisedIndex == size) { - push(value); - } else { - values[normalisedIndex] = value; - } - } - - @Override - public void setRangeSingle(int normalisedBegin, int normalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException { - // Is the range the whole array? - - if (normalisedBegin == 0 && normalisedExclusiveEnd == size) { - // Reset length and set the value. - size = 1; - values[0] = value; - } else { - // Delete the range, except for the first value. - deleteSpace(normalisedBegin + 1, normalisedExclusiveEnd - normalisedBegin - 1); - - // Set the value we left in. - System.err.println(normalisedBegin + " in " + size + " with " + values.length); - values[normalisedBegin] = value; - } - } - - @Override - public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException { - setRangeArray(normalisedBegin, normalisedExclusiveEnd, (ObjectArrayStore) other.generalizeFor(null)); - } - - public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ObjectArrayStore other) { - setRangeArrayMatchingTypes(normalisedBegin, normalisedExclusiveEnd, other.values, other.size); - } - - @Override - public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - if (normalisedIndex > size) { - final int originalLength = size; - createSpaceAtEnd(normalisedIndex - size + 1); - Arrays.fill(values, originalLength, normalisedIndex, NilPlaceholder.INSTANCE); - values[normalisedIndex] = value; - } else { - createSpace(normalisedIndex, 1); - values[normalisedIndex] = value; - } - } - - @Override - public void push(Object value) throws GeneraliseArrayStoreException { - createSpaceAtEnd(1); - values[size - 1] = value; - } - - @Override - public Object deleteAt(int normalisedIndex) { - if (normalisedIndex >= size) { - return NilPlaceholder.INSTANCE; - } - - final Object value = values[normalisedIndex]; - - deleteSpace(normalisedIndex, 1); - - return value; - } - - @Override - public ArrayStore dup() { - return new ObjectArrayStore(Arrays.copyOf(values, size)); - } - - @Override - public boolean contains(Object value) { - for (int n = 0; n < size; n++) { - if (values[n].equals(value)) { - return true; - } - } - - return false; - } - - @Override - public ObjectArrayStore generalizeFor(Object type) { - return this; - } - - @Override - public Object getIndicativeValue() { - return null; - } - - @Override - protected void setCapacityByCopying(int newCapacity) { - values = Arrays.copyOf(values, newCapacity); - capacity = values.length; - } - - @Override - protected void setCapacityWithNewArray(int newCapacity) { - values = new Object[newCapacity]; - capacity = values.length; - } - - @Override - protected Object getValuesArrayObject() { - return values; - } - - public Object[] getValues() { - return values; - } - - @Override - public Object[] toObjectArray() { - if (values.length == size) { - return values; - } else { - return Arrays.copyOf(values, size); - } - } - - @Override - public boolean equals(ArrayStore other) { - if (other instanceof ObjectArrayStore) { - return equals((ObjectArrayStore) other); - } else { - return super.equals(other); - } - } - - public boolean equals(ObjectArrayStore other) { - if (other == null) { - return false; - } else if (other == this) { - return true; - } else if (other.size != size) { - return false; - } else if (other.capacity == capacity) { - return Arrays.equals(other.values, values); - } else { - for (int n = 0; n < size; n++) { - if (!other.values[n].equals(values[n])) { - return false; - } - } - - return true; - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectImmutablePairArrayStore.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectImmutablePairArrayStore.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A store for a pair of objects. - */ -public final class ObjectImmutablePairArrayStore extends BaseArrayStore { - - private final Object first; - private final Object second; - - public ObjectImmutablePairArrayStore(Object first, Object second) { - size = 2; - capacity = 2; - this.first = first; - this.second = second; - } - - @Override - public int size() { - return 2; - } - - @Override - public Object get(int normalisedIndex) { - switch (normalisedIndex) { - case 0: - return first; - case 1: - return second; - default: - return NilPlaceholder.INSTANCE; - } - } - - @Override - public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) { - if (normalisedBegin >= size) { - return null; // Represents Nil - } - - return new ObjectArrayStore(Arrays.copyOfRange(new Object[]{first, second}, normalisedBegin, truncatedNormalisedExclusiveEnd)); - } - - @Override - public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public void push(Object value) throws GeneraliseArrayStoreException { - CompilerDirectives.transferToInterpreter(); - throw new GeneraliseArrayStoreException(); - } - - @Override - public Object deleteAt(int normalisedIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public ArrayStore dup() { - return this; - } - - @Override - public boolean contains(Object value) { - return first.equals(value) || second.equals(value); - } - - @Override - public ArrayStore generalizeFor(Object type) { - return new ObjectArrayStore(toObjectArray()); - } - - @Override - public Object getIndicativeValue() { - return 0; - } - - @Override - protected void setCapacityByCopying(int newCapacity) { - throw new UnsupportedOperationException(); - } - - @Override - protected void setCapacityWithNewArray(int newCapacity) { - throw new UnsupportedOperationException(); - } - - @Override - protected Object getValuesArrayObject() { - return new Object[]{first, second}; - } - - @Override - public Object[] toObjectArray() { - return new Object[]{first, second}; - } - - @Override - public boolean equals(ArrayStore other) { - if (other instanceof ObjectImmutablePairArrayStore) { - return equals((ObjectImmutablePairArrayStore) other); - } else { - return super.equals(other); - } - } - - public boolean equals(ObjectImmutablePairArrayStore other) { - if (other == null) { - return false; - } else if (other == this) { - return true; - } else { - return other.first == first && other.second == second; - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/RubyArray.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/RubyArray.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,428 +0,0 @@ -/* - * Copyright (c) 2013 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.core.array; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.CompilerDirectives.SlowPath; -import com.oracle.truffle.api.frame.*; -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.methods.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Implements the Ruby {@code Array} class. - */ -@SuppressWarnings("unused") -public final class RubyArray extends RubyObject { - - public static class RubyArrayClass extends RubyClass { - - public RubyArrayClass(RubyClass objectClass) { - super(null, objectClass, "Array"); - } - - @Override - public RubyBasicObject newInstance() { - return new RubyArray(this); - } - - } - - @CompilationFinal private ArrayStore store; - - public RubyArray(RubyClass arrayClass) { - this(arrayClass, EmptyArrayStore.INSTANCE); - } - - public RubyArray(RubyClass arrayClass, ArrayStore store) { - super(arrayClass); - this.store = store; - } - - private static RubyArray selfAsArray(Object self) { - if (self instanceof RubyArray) { - return (RubyArray) self; - } else { - throw new IllegalStateException(); - } - } - - @CompilerDirectives.SlowPath - public static RubyArray specializedFromObject(RubyClass arrayClass, Object object) { - ArrayStore store; - - if (object instanceof Integer || object instanceof RubyFixnum) { - store = new FixnumArrayStore(new int[]{GeneralConversions.toFixnum(object)}); - } else { - store = new ObjectArrayStore(new Object[]{object}); - } - - return new RubyArray(arrayClass, store); - } - - /** - * Create a Ruby array from a Java array of objects, choosing the best store. - */ - @CompilerDirectives.SlowPath - public static RubyArray specializedFromObjects(RubyClass arrayClass, Object... objects) { - if (objects.length == 0) { - return new RubyArray(arrayClass); - } - - boolean canUseFixnum = true; - - for (Object object : objects) { - if (!(object instanceof Integer || object instanceof RubyFixnum)) { - canUseFixnum = false; - } - } - - ArrayStore store; - - if (canUseFixnum) { - final int[] values = new int[objects.length]; - - for (int n = 0; n < objects.length; n++) { - values[n] = GeneralConversions.toFixnum(objects[n]); - } - - store = new FixnumArrayStore(values); - } else { - store = new ObjectArrayStore(objects); - } - - return new RubyArray(arrayClass, store); - } - - public Object get(int index) { - return store.get(ArrayUtilities.normaliseIndex(store.size(), index)); - } - - public Object getRangeInclusive(int begin, int inclusiveEnd) { - final int l = store.size(); - final int normalisedInclusiveEnd = ArrayUtilities.normaliseIndex(l, inclusiveEnd); - return getRangeExclusive(begin, normalisedInclusiveEnd + 1); - } - - public Object getRangeExclusive(int begin, int exclusiveEnd) { - final int l = store.size(); - final int normalisedBegin = ArrayUtilities.normaliseIndex(l, begin); - final int truncatedNormalisedExclusiveEnd = ArrayUtilities.truncateNormalisedExclusiveIndex(l, ArrayUtilities.normaliseExclusiveIndex(l, exclusiveEnd)); - - final Object range = store.getRange(normalisedBegin, truncatedNormalisedExclusiveEnd); - - if (range == null) { - return new RubyArray(getRubyClass()); - } else { - return new RubyArray(getRubyClass(), (ArrayStore) range); - } - } - - public void set(int index, Object value) { - checkFrozen(); - - final int l = store.size(); - final int normalisedIndex = ArrayUtilities.normaliseIndex(l, index); - - try { - store.set(normalisedIndex, value); - } catch (GeneraliseArrayStoreException e) { - store = store.generalizeFor(value); - - try { - store.set(normalisedIndex, value); - } catch (GeneraliseArrayStoreException ex) { - throwSecondGeneraliseException(); - } - } - } - - public void setRangeSingleInclusive(int begin, int inclusiveEnd, Object value) { - final int l = store.size(); - final int normalisedInclusiveEnd = ArrayUtilities.normaliseIndex(l, inclusiveEnd); - setRangeSingleExclusive(begin, normalisedInclusiveEnd + 1, value); - } - - public void setRangeSingleExclusive(int begin, int exclusiveEnd, Object value) { - checkFrozen(); - - final int l = store.size(); - final int normalisedBegin = ArrayUtilities.normaliseIndex(l, begin); - final int truncatedNormalisedExclusiveEnd = ArrayUtilities.truncateNormalisedExclusiveIndex(l, ArrayUtilities.normaliseExclusiveIndex(l, exclusiveEnd)); - - try { - store.setRangeSingle(normalisedBegin, truncatedNormalisedExclusiveEnd, value); - } catch (GeneraliseArrayStoreException e) { - store = store.generalizeFor(value); - - try { - store.setRangeSingle(normalisedBegin, truncatedNormalisedExclusiveEnd, value); - } catch (GeneraliseArrayStoreException ex) { - throwSecondGeneraliseException(); - } - } - } - - public void setRangeArrayInclusive(int begin, int inclusiveEnd, RubyArray other) { - final int l = store.size(); - final int normalisedInclusiveEnd = ArrayUtilities.normaliseIndex(l, inclusiveEnd); - setRangeArrayExclusive(begin, normalisedInclusiveEnd + 1, other); - } - - public void setRangeArrayExclusive(int begin, int exclusiveEnd, RubyArray other) { - checkFrozen(); - - final int l = store.size(); - final int normalisedBegin = ArrayUtilities.normaliseIndex(l, begin); - final int normalisedExclusiveEnd = ArrayUtilities.normaliseExclusiveIndex(l, exclusiveEnd); - - try { - store.setRangeArray(normalisedBegin, normalisedExclusiveEnd, other.store); - } catch (GeneraliseArrayStoreException e) { - store = store.generalizeFor(other.store.getIndicativeValue()); - - try { - store.setRangeArray(normalisedBegin, normalisedExclusiveEnd, other.store); - } catch (GeneraliseArrayStoreException ex) { - throwSecondGeneraliseException(); - } - } - } - - public void insert(int index, Object value) { - checkFrozen(); - - final int l = store.size(); - final int normalisedIndex = ArrayUtilities.normaliseIndex(l, index); - - try { - store.insert(normalisedIndex, value); - } catch (GeneraliseArrayStoreException e) { - store = store.generalizeFor(value); - - try { - store.insert(normalisedIndex, value); - } catch (GeneraliseArrayStoreException ex) { - throwSecondGeneraliseException(); - } - } - } - - public void push(Object value) { - checkFrozen(); - - if (store instanceof EmptyArrayStore) { - /* - * Normally we want to transfer to interpreter to generalize an array store, but the - * special case of an empty array is common, will never cause rewrites and has a simple - * implementation, so treat it as a special case. - */ - store = ((EmptyArrayStore) store).generalizeFor(value); - } - - try { - store.push(value); - } catch (GeneraliseArrayStoreException e) { - store = store.generalizeFor(value); - - try { - store.push(value); - } catch (GeneraliseArrayStoreException ex) { - throw new IllegalStateException("Generalised to support a specific value, but value still rejected by store"); - } - } - } - - public void unshift(Object value) { - insert(0, value); - } - - public Object deleteAt(int index) { - checkFrozen(); - - final int l = store.size(); - final int normalisedIndex = ArrayUtilities.normaliseIndex(l, index); - - return store.deleteAt(normalisedIndex); - } - - @Override - @CompilerDirectives.SlowPath - public Object dup() { - return new RubyArray(getRubyClass(), store.dup()); - } - - public ArrayStore getArrayStore() { - return store; - } - - public List asList() { - final RubyArray array = this; - - return new AbstractList() { - - @Override - public Object get(int n) { - return array.get(n); - } - - @Override - public int size() { - return array.size(); - } - - }; - } - - public Object[] toObjectArray() { - return store.toObjectArray(); - } - - private static void throwSecondGeneraliseException() { - CompilerAsserts.neverPartOfCompilation(); - throw new RuntimeException("Generalised based on a value, but the new store also rejected that value."); - } - - public int size() { - return store.size(); - } - - public boolean contains(Object value) { - return store.contains(value); - } - - /** - * Recursive Cartesian product. - *

- * The Array#product method is supposed to be able to take a block, to which it yields tuples as - * they are produced, so it might be worth abstracting this method into sending tuples to some - * interface, which either adds them to an array, or yields them to the block. - */ - @SlowPath - public static RubyArray product(RubyClass arrayClass, RubyArray[] arrays, int l) { - if (arrays.length - l == 1) { - final RubyArray firstArray = arrays[0]; - - final RubyArray tuples = new RubyArray(arrayClass); - - for (int i = 0; i < firstArray.size(); i++) { - final RubyArray tuple = new RubyArray(arrayClass); - tuple.push(firstArray.get(i)); - tuples.push(tuple); - } - - return tuples; - } else { - final RubyArray intermediateTuples = product(arrayClass, arrays, l - 1); - final RubyArray lastArray = arrays[l - 1]; - - final RubyArray tuples = new RubyArray(arrayClass); - - for (int n = 0; n < intermediateTuples.size(); n++) { - for (int i = 0; i < lastArray.size(); i++) { - final RubyArray tuple = (RubyArray) ((RubyArray) intermediateTuples.get(n)).dup(); - tuple.push(lastArray.get(i)); - tuples.push(tuple); - } - } - - return tuples; - } - } - - public boolean equals(RubyArray other) { - if (other == null) { - return false; - } else if (other == this) { - return true; - } else { - return store.equals(other.store); - } - } - - @Override - public boolean equals(Object other) { - if (other instanceof RubyArray) { - return equals((RubyArray) other); - } else { - return false; - } - } - - @Override - public int hashCode() { - getRubyClass().getContext().implementationMessage("Array#hash returns nonsense"); - return 0; - } - - public RubyArray relativeComplement(RubyArray other) { - // TODO(cs): specialize for different stores - - final RubyArray result = new RubyArray(getRubyClass().getContext().getCoreLibrary().getArrayClass()); - - for (Object value : asList()) { - if (!other.contains(value)) { - result.push(value); - } - } - - return result; - } - - public String join(String separator) { - final StringBuilder builder = new StringBuilder(); - - for (int n = 0; n < size(); n++) { - if (n > 0) { - builder.append(separator); - } - - builder.append(get(n).toString()); - } - - return builder.toString(); - } - - public static String join(Object[] parts, String separator) { - final StringBuilder builder = new StringBuilder(); - - for (int n = 0; n < parts.length; n++) { - if (n > 0) { - builder.append(separator); - } - - builder.append(parts[n].toString()); - } - - return builder.toString(); - } - - public void flattenTo(RubyArray result) { - for (int n = 0; n < size(); n++) { - final Object value = get(n); - - if (value instanceof RubyArray) { - ((RubyArray) value).flattenTo(result); - } else { - result.push(value); - } - } - } - - public boolean isEmpty() { - return store.size() == 0; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/FixnumRange.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/FixnumRange.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2013 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.core.range; - -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -/** - * A range that has {@code Fixnum} begin and end. - */ -public class FixnumRange extends RubyRange { - - private final int begin; - private final int end; - private final boolean excludeEnd; - - public FixnumRange(RubyClass rangeClass, int begin, int end, boolean excludeEnd) { - super(rangeClass); - this.begin = begin; - this.end = end; - this.excludeEnd = excludeEnd; - } - - @Override - public String toString() { - if (excludeEnd) { - return begin + "..." + end; - } else { - return begin + ".." + end; - } - } - - @Override - public RubyArray toArray() { - final int length = getLength(); - - if (length < 0) { - return new RubyArray(getRubyClass().getContext().getCoreLibrary().getArrayClass()); - } else { - final int[] values = new int[length]; - - for (int n = 0; n < length; n++) { - values[n] = begin + n; - } - - return new RubyArray(getRubyClass().getContext().getCoreLibrary().getArrayClass(), new FixnumArrayStore(values)); - } - } - - private int getLength() { - if (excludeEnd) { - return end - begin; - } else { - return end - begin + 1; - } - } - - public final int getBegin() { - return begin; - } - - public final int getEnd() { - return end; - } - - public final int getInclusiveEnd() { - if (excludeEnd) { - return end - 1; - } else { - return end; - } - } - - public final int getExclusiveEnd() { - if (excludeEnd) { - return end; - } else { - return end + 1; - } - } - - @Override - public boolean doesExcludeEnd() { - return excludeEnd; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + begin; - result = prime * result + end; - result = prime * result + (excludeEnd ? 1231 : 1237); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof FixnumRange)) { - return false; - } - FixnumRange other = (FixnumRange) obj; - if (begin != other.begin) { - return false; - } - if (end != other.end) { - return false; - } - if (excludeEnd != other.excludeEnd) { - return false; - } - return true; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/ObjectRange.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/ObjectRange.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2013 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.core.range; - -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -public class ObjectRange extends RubyRange { - - private final Object begin; - private final Object end; - private final boolean excludeEnd; - - public ObjectRange(RubyClass rangeClass, Object begin, Object end, boolean excludeEnd) { - super(rangeClass); - this.begin = begin; - this.end = end; - this.excludeEnd = excludeEnd; - } - - @Override - public RubyArray toArray() { - throw new UnsupportedOperationException(); - } - - public Object getBegin() { - return begin; - } - - public Object getEnd() { - return end; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((begin == null) ? 0 : begin.hashCode()); - result = prime * result + ((end == null) ? 0 : end.hashCode()); - result = prime * result + (excludeEnd ? 1231 : 1237); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof ObjectRange)) { - return false; - } - ObjectRange other = (ObjectRange) obj; - if (begin == null) { - if (other.begin != null) { - return false; - } - } else if (!begin.equals(other.begin)) { - return false; - } - if (end == null) { - if (other.end != null) { - return false; - } - } else if (!end.equals(other.end)) { - return false; - } - if (excludeEnd != other.excludeEnd) { - return false; - } - return true; - } - - @Override - public boolean doesExcludeEnd() { - // TODO Auto-generated method stub - return false; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/RubyRange.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/RubyRange.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2013 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.core.range; - -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -public abstract class RubyRange extends RubyObject { - - public RubyRange(RubyClass rangeClass) { - super(rangeClass); - } - - public abstract RubyArray toArray(); - - public abstract boolean doesExcludeEnd(); - -} diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /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 d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ /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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupFork.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupFork.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2013 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.lookup; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * A fork in the lookup graph. Look at first and then look at second. - */ -public class LookupFork implements LookupNode { - - private LookupNode first; - private LookupNode second; - - public LookupFork(LookupNode first, LookupNode second) { - this.first = first; - this.second = second; - } - - public boolean setClassVariableIfAlreadySet(String variableName, Object value) { - if (first.setClassVariableIfAlreadySet(variableName, value)) { - return true; - } - - return second.setClassVariableIfAlreadySet(variableName, value); - } - - @Override - public Object lookupConstant(String constantName) { - final Object firstResult = first.lookupConstant(constantName); - - if (firstResult != null) { - return firstResult; - } - - return second.lookupConstant(constantName); - } - - @Override - public Object lookupClassVariable(String classVariable) { - final Object firstResult = first.lookupClassVariable(classVariable); - - if (firstResult != null) { - return firstResult; - } - - return second.lookupClassVariable(classVariable); - } - - @Override - public RubyMethod lookupMethod(String methodName) { - final RubyMethod firstResult = first.lookupMethod(methodName); - - if (firstResult != null) { - return firstResult; - } - - return second.lookupMethod(methodName); - } - - @Override - public Assumption getUnmodifiedAssumption() { - return new UnionAssumption(first.getUnmodifiedAssumption(), second.getUnmodifiedAssumption()); - } - - public LookupNode getFirst() { - return first; - } - - public LookupNode getSecond() { - return second; - } - - public Set getClassVariables() { - final Set classVariables = new HashSet<>(); - classVariables.addAll(first.getClassVariables()); - classVariables.addAll(second.getClassVariables()); - return classVariables; - } - - public void getMethods(Map methods) { - second.getMethods(methods); - first.getMethods(methods); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupNode.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.lookup; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * A node in the lookup graph. We abstract from modules and classes because with includes and - * singletons and so on there are more nodes in the graph than there are classes and modules. - */ -public interface LookupNode { - - boolean setClassVariableIfAlreadySet(String variableName, Object value); - - Object lookupConstant(String constantName); - - Object lookupClassVariable(String variableName); - - RubyMethod lookupMethod(String methodName); - - Assumption getUnmodifiedAssumption(); - - Set getClassVariables(); - - void getMethods(Map methods); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupTerminal.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupTerminal.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.lookup; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * A terminal in the lookup graph. - */ -public class LookupTerminal implements LookupNode { - - public static final LookupTerminal INSTANCE = new LookupTerminal(); - - public boolean setClassVariableIfAlreadySet(String variableName, Object value) { - return false; - } - - @Override - public Object lookupConstant(String constantName) { - return null; - } - - @Override - public Object lookupClassVariable(String constantName) { - return null; - } - - @Override - public RubyMethod lookupMethod(String methodName) { - return null; - } - - @Override - public Assumption getUnmodifiedAssumption() { - return AlwaysValidAssumption.INSTANCE; - } - - public Set getClassVariables() { - return Collections.emptySet(); - } - - public void getMethods(Map methods) { - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Arity.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Arity.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; - -/** - * Represents the arity, or parameter contract, of a method. - */ -public class Arity { - - private final int minimum; - public static final int NO_MINIMUM = 0; - - private final int maximum; - public static final int NO_MAXIMUM = Integer.MAX_VALUE; - - public static final Arity NO_ARGS = new Arity(0, 0); - public static final Arity ONE_ARG = new Arity(1, 1); - - public Arity(int minimum, int maximum) { - this.minimum = minimum; - this.maximum = maximum; - } - - public void checkArguments(RubyContext context, Object[] arguments) { - if (arguments.length < minimum || arguments.length > maximum) { - CompilerDirectives.transferToInterpreter(); - throw new RaiseException(context.getCoreLibrary().argumentError(arguments.length, minimum)); - } - } - - public int getMinimum() { - return minimum; - } - - public int getMaximum() { - return maximum; - } - - @Override - public String toString() { - return String.format("Arity(%d, %d)", minimum, maximum); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/CallTargetMethodImplementation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/CallTargetMethodImplementation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -public class CallTargetMethodImplementation implements MethodImplementation { - - private final CallTarget callTarget; - private final MaterializedFrame declarationFrame; - - public CallTargetMethodImplementation(CallTarget callTarget, MaterializedFrame declarationFrame) { - assert callTarget != null; - - this.callTarget = callTarget; - this.declarationFrame = declarationFrame; - } - - public Object call(PackedFrame caller, Object self, RubyProc block, Object... args) { - assert RubyContext.shouldObjectBeVisible(self); - assert RubyContext.shouldObjectsBeVisible(args); - - RubyArguments arguments = new RubyArguments(declarationFrame, self, block, args); - - final Object result = callTarget.call(caller, arguments); - - assert RubyContext.shouldObjectBeVisible(result); - - return result; - } - - public MaterializedFrame getDeclarationFrame() { - return declarationFrame; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/MethodImplementation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/MethodImplementation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.core.*; - -public interface MethodImplementation { - - Object call(PackedFrame caller, Object self, RubyProc block, Object... args); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/RubyMethod.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/RubyMethod.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Any kind of Ruby method - so normal methods in classes and modules, but also blocks, procs, - * lambdas and native methods written in Java. - */ -public class RubyMethod { - - private final SourceSection sourceSection; - private final RubyModule declaringModule; - private final UniqueMethodIdentifier uniqueIdentifier; - private final String intrinsicName; - private final String name; - private final Visibility visibility; - private final boolean undefined; - - private final MethodImplementation implementation; - - public RubyMethod(SourceSection sourceSection, RubyModule declaringModule, UniqueMethodIdentifier uniqueIdentifier, String intrinsicName, String name, Visibility visibility, boolean undefined, - MethodImplementation implementation) { - this.sourceSection = sourceSection; - this.declaringModule = declaringModule; - this.uniqueIdentifier = uniqueIdentifier; - this.intrinsicName = intrinsicName; - this.name = name; - this.visibility = visibility; - this.undefined = undefined; - this.implementation = implementation; - } - - public Object call(PackedFrame caller, Object self, RubyProc block, Object... args) { - assert RubyContext.shouldObjectBeVisible(self); - assert RubyContext.shouldObjectsBeVisible(args); - - final Object result = implementation.call(caller, self, block, args); - - assert RubyContext.shouldObjectBeVisible(result); - - return result; - } - - public SourceSection getSourceSection() { - return sourceSection; - } - - public UniqueMethodIdentifier getUniqueIdentifier() { - return uniqueIdentifier; - } - - public String getIntrinsicName() { - return intrinsicName; - } - - public String getName() { - return name; - } - - public Visibility getVisibility() { - return visibility; - } - - public boolean isUndefined() { - return undefined; - } - - public MethodImplementation getImplementation() { - return implementation; - } - - public RubyMethod withNewName(String newName) { - if (newName.equals(name)) { - return this; - } - - return new RubyMethod(sourceSection, declaringModule, uniqueIdentifier, intrinsicName, newName, visibility, undefined, implementation); - } - - public RubyMethod withNewVisibility(Visibility newVisibility) { - if (newVisibility == visibility) { - return this; - } - - return new RubyMethod(sourceSection, declaringModule, uniqueIdentifier, intrinsicName, name, newVisibility, undefined, implementation); - } - - public RubyMethod withDeclaringModule(RubyModule newDeclaringModule) { - if (newDeclaringModule == declaringModule) { - return this; - } - - return new RubyMethod(sourceSection, newDeclaringModule, uniqueIdentifier, intrinsicName, name, visibility, undefined, implementation); - } - - public RubyMethod undefined() { - if (undefined) { - return this; - } - - return new RubyMethod(sourceSection, declaringModule, uniqueIdentifier, intrinsicName, name, visibility, true, implementation); - } - - public boolean isVisibleTo(RubyBasicObject caller) { - if (caller instanceof RubyModule) { - if (isVisibleTo((RubyModule) caller)) { - return true; - } - } - - if (isVisibleTo(caller.getRubyClass())) { - return true; - } - - if (isVisibleTo(caller.getSingletonClass())) { - return true; - } - - return false; - } - - private boolean isVisibleTo(RubyModule module) { - switch (visibility) { - case PUBLIC: - return true; - - case PROTECTED: - return true; - - case PRIVATE: - if (module == declaringModule) { - return true; - } - - if (module.getSingletonClass() == declaringModule) { - return true; - } - - if (module.getParentModule() != null && isVisibleTo(module.getParentModule())) { - return true; - } - - return false; - - default: - return false; - } - } - - @Override - public String toString() { - return implementation.toString(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/UniqueMethodIdentifier.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/UniqueMethodIdentifier.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -/** - * An object that uniquely identifies a method as it appears in the source code, and that follows - * the method as a normal method, when it becomes a proc, when it changes access or is aliased etc. - */ -public class UniqueMethodIdentifier { - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Visibility.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Visibility.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2013 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.methods; - -/** - * Represents the visibility of a method. - */ -public enum Visibility { - PUBLIC, PROTECTED, PRIVATE -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FixnumStorageLocation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FixnumStorageLocation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A storage location for Fixnums. - */ -public class FixnumStorageLocation extends PrimitiveStorageLocation { - - public FixnumStorageLocation(ObjectLayout objectLayout, long offset, int mask) { - super(objectLayout, offset, mask); - } - - @Override - public Object read(RubyBasicObject object, boolean condition) { - try { - return readFixnum(object, condition); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - public int readFixnum(RubyBasicObject object, boolean condition) throws UnexpectedResultException { - if (isSet(object)) { - return CompilerDirectives.unsafeGetInt(object, offset, condition, this); - } else { - throw new UnexpectedResultException(NilPlaceholder.INSTANCE); - } - } - - @Override - public void write(RubyBasicObject object, Object value) throws GeneralizeStorageLocationException { - if (value instanceof Integer) { - writeFixnum(object, (int) value); - } else if (value instanceof NilPlaceholder) { - markAsUnset(object); - } else { - throw new GeneralizeStorageLocationException(); - } - } - - public void writeFixnum(RubyBasicObject object, int value) { - CompilerDirectives.unsafePutInt(object, offset, value, null); - markAsSet(object); - } - - @Override - public Class getStoredClass() { - return Integer.class; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FloatStorageLocation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FloatStorageLocation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A storage location for Floats. - */ -public class FloatStorageLocation extends PrimitiveStorageLocation { - - public FloatStorageLocation(ObjectLayout objectLayout, long offset, int mask) { - super(objectLayout, offset, mask); - } - - @Override - public Object read(RubyBasicObject object, boolean condition) { - try { - return readFloat(object, condition); - } catch (UnexpectedResultException e) { - return e.getResult(); - } - } - - public double readFloat(RubyBasicObject object, boolean condition) throws UnexpectedResultException { - if (isSet(object)) { - return CompilerDirectives.unsafeGetDouble(object, offset, condition, this); - } else { - throw new UnexpectedResultException(NilPlaceholder.INSTANCE); - } - } - - @Override - public void write(RubyBasicObject object, Object value) throws GeneralizeStorageLocationException { - if (value instanceof Double) { - writeFloat(object, (double) value); - } else if (value instanceof NilPlaceholder) { - markAsUnset(object); - } else { - throw new GeneralizeStorageLocationException(); - } - } - - public void writeFloat(RubyBasicObject object, Double value) { - CompilerDirectives.unsafePutDouble(object, offset, value, null); - markAsSet(object); - } - - @Override - public Class getStoredClass() { - return Double.class; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/GeneralizeStorageLocationException.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/GeneralizeStorageLocationException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -/** - * Indicates that a storage location cannot store the type of value that you asked it to. - */ -public class GeneralizeStorageLocationException extends Exception { - - private static final long serialVersionUID = -5136358171098229961L; - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectLayout.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectLayout.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import java.lang.reflect.*; -import java.util.*; -import java.util.Map.Entry; - -import sun.misc.*; - -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeUtil.*; - -/** - * Maps names of instance variables to storage locations, which are either the offset of a primitive - * field in {@code RubyBasicObject}, or an index into an object array in {@code RubyBasicObject}. - * Object layouts are chained, with each having zero or one parents. - *

- * Object layouts are immutable, with the methods for adding new instance variables of generalizing - * the type of existing instance variables returning new object layouts. - */ -public class ObjectLayout { - - public static final ObjectLayout EMPTY = new ObjectLayout("(empty)"); - - private final String originHint; - - private final ObjectLayout parent; - - private final Map storageLocations = new HashMap<>(); - - private final int primitiveStorageLocationsUsed; - private final int objectStorageLocationsUsed; - - public static final long FIRST_OFFSET = getFirstOffset(); - - private ObjectLayout(String originHint) { - this.originHint = originHint; - this.parent = null; - primitiveStorageLocationsUsed = 0; - objectStorageLocationsUsed = 0; - } - - public ObjectLayout(String originHint, ObjectLayout parent) { - this(originHint, parent, new HashMap()); - } - - public ObjectLayout(String originHint, ObjectLayout parent, Map storageTypes) { - this.originHint = originHint; - this.parent = parent; - - // Start our offsets from where the parent ends - - int primitiveStorageLocationIndex; - int objectStorageLocationIndex; - - if (parent == null) { - primitiveStorageLocationIndex = 0; - objectStorageLocationIndex = 0; - } else { - primitiveStorageLocationIndex = parent.primitiveStorageLocationsUsed; - objectStorageLocationIndex = parent.objectStorageLocationsUsed; - } - - // Go through the variables we've been asked to store - - for (Entry entry : storageTypes.entrySet()) { - // TODO(cs): what if parent has it, but we need a more general type? - - final String name = entry.getKey(); - final Class type = entry.getValue(); - - if (parent == null || parent.findStorageLocation(name) == null) { - boolean canStoreInPrimitive = false; - int primitivesNeeded = 0; - - if (type == Integer.class) { - canStoreInPrimitive = true; - primitivesNeeded = 1; - } else if (type == Double.class) { - canStoreInPrimitive = true; - primitivesNeeded = 2; - } - - if (canStoreInPrimitive && primitiveStorageLocationIndex + primitivesNeeded <= RubyBasicObject.PRIMITIVE_STORAGE_LOCATIONS_COUNT) { - final long offset = FIRST_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * primitiveStorageLocationIndex; - final int mask = 1 << primitiveStorageLocationIndex; - - StorageLocation newStorageLocation = null; - - if (type == Integer.class) { - newStorageLocation = new FixnumStorageLocation(this, offset, mask); - } else if (type == Double.class) { - newStorageLocation = new FloatStorageLocation(this, offset, mask); - } - - storageLocations.put(entry.getKey(), newStorageLocation); - primitiveStorageLocationIndex += primitivesNeeded; - } else { - final ObjectStorageLocation newStorageLocation = new ObjectStorageLocation(this, objectStorageLocationIndex); - storageLocations.put(entry.getKey(), newStorageLocation); - objectStorageLocationIndex++; - } - } - } - - primitiveStorageLocationsUsed = primitiveStorageLocationIndex; - objectStorageLocationsUsed = objectStorageLocationIndex; - } - - /** - * Create a new version of this layout, but with a different parent. The new parent probably - * comes from the same Ruby class as it did, but it's a new layout because layouts are - * immutable, so modifications to the superclass yields a new layout. - */ - public ObjectLayout renew(ObjectLayout newParent) { - return new ObjectLayout(originHint + ".renewed", newParent, getStorageTypes()); - } - - /** - * Create a new version of this layout but with a new variable. - */ - public ObjectLayout withNewVariable(String name, Class type) { - final Map storageTypes = getStorageTypes(); - storageTypes.put(name, type); - return new ObjectLayout(originHint + ".withnew", parent, storageTypes); - } - - /** - * Create a new version of this layout but with an existing variable generalized to support any - * type. - */ - public ObjectLayout withGeneralisedVariable(String name) { - return withNewVariable(name, Object.class); - } - - /** - * Get a map of instance variable names to the type that they store. - */ - public Map getStorageTypes() { - Map storageTypes = new HashMap<>(); - - for (Entry entry : storageLocations.entrySet()) { - final String name = entry.getKey(); - final StorageLocation storageLocation = entry.getValue(); - - if (storageLocation.getStoredClass() != null) { - storageTypes.put(name, storageLocation.getStoredClass()); - } - } - - return storageTypes; - } - - /** - * Get a map of instance variable names to the type that they store, but including both this - * layout and all parent layouts. - */ - public Map getAllStorageLocations() { - final Map allStorageLocations = new HashMap<>(); - - allStorageLocations.putAll(storageLocations); - - if (parent != null) { - allStorageLocations.putAll(parent.getAllStorageLocations()); - } - - return allStorageLocations; - } - - /** - * Find a storage location from a name, including in parents. - */ - public StorageLocation findStorageLocation(String name) { - final StorageLocation storageLocation = storageLocations.get(name); - - if (storageLocation != null) { - return storageLocation; - } - - if (parent == null) { - return null; - } - - return parent.findStorageLocation(name); - } - - public int getObjectStorageLocationsUsed() { - return objectStorageLocationsUsed; - } - - /** - * Does this layout include another layout? That is, is that other layout somewhere in the chain - * of parents? We say 'include' because all of the variables in a parent layout are available in - * your layout as well. - */ - public boolean contains(ObjectLayout other) { - ObjectLayout layout = this; - - do { - if (other == layout) { - return true; - } - - layout = layout.parent; - } while (layout != null); - - return false; - } - - public String getOriginHint() { - return originHint; - } - - private static long getFirstOffset() { - try { - final Field fieldOffsetProviderField = NodeUtil.class.getDeclaredField("unsafeFieldOffsetProvider"); - fieldOffsetProviderField.setAccessible(true); - final FieldOffsetProvider fieldOffsetProvider = (FieldOffsetProvider) fieldOffsetProviderField.get(null); - - final Field firstPrimitiveField = RubyBasicObject.class.getDeclaredField("primitiveStorageLocation01"); - return fieldOffsetProvider.objectFieldOffset(firstPrimitiveField); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectStorageLocation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectStorageLocation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * A storage location for any object. - */ -public class ObjectStorageLocation extends StorageLocation { - - private final int index; - - public ObjectStorageLocation(ObjectLayout objectLayout, int index) { - super(objectLayout); - this.index = index; - } - - @Override - public boolean isSet(RubyBasicObject object) { - return object.objectStorageLocations[index] != null; - } - - @Override - public Object read(RubyBasicObject object, boolean condition) { - final Object result = object.objectStorageLocations[index]; - - if (result == null) { - return NilPlaceholder.INSTANCE; - } else { - return result; - } - } - - @Override - public void write(RubyBasicObject object, Object value) { - object.objectStorageLocations[index] = value; - } - - @Override - public Class getStoredClass() { - return Object.class; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/PrimitiveStorageLocation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/PrimitiveStorageLocation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -/** - * A storage location that uses one of the primitive fields in {@code RubyBasObject}. - */ -public abstract class PrimitiveStorageLocation extends StorageLocation { - - protected final long offset; - protected final int mask; - - protected PrimitiveStorageLocation(ObjectLayout objectLayout, long offset, int mask) { - super(objectLayout); - this.offset = offset; - this.mask = mask; - } - - @Override - public boolean isSet(RubyBasicObject object) { - return (object.primitiveSetMap & mask) != 0; - } - - protected void markAsSet(RubyBasicObject object) { - object.primitiveSetMap |= mask; - } - - protected void markAsUnset(RubyBasicObject object) { - object.primitiveSetMap &= ~mask; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/RubyBasicObject.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/RubyBasicObject.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,360 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -import java.util.*; -import java.util.Map.Entry; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -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.lookup.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * Represents the Ruby {@code BasicObject} class - the root of the Ruby class hierarchy. - */ -public class RubyBasicObject { - - @CompilationFinal protected RubyClass rubyClass; - protected RubyClass rubySingletonClass; - - protected LookupNode lookupNode; - - protected long objectID = -1; - - public boolean hasPrivateLayout = false; - private ObjectLayout objectLayout; - - public static final int PRIMITIVE_STORAGE_LOCATIONS_COUNT = 14; - protected int primitiveStorageLocation01; - protected int primitiveStorageLocation02; - protected int primitiveStorageLocation03; - protected int primitiveStorageLocation04; - protected int primitiveStorageLocation05; - protected int primitiveStorageLocation06; - protected int primitiveStorageLocation07; - protected int primitiveStorageLocation08; - protected int primitiveStorageLocation09; - protected int primitiveStorageLocation10; - protected int primitiveStorageLocation11; - protected int primitiveStorageLocation12; - protected int primitiveStorageLocation13; - protected int primitiveStorageLocation14; - - // A bit map to indicate which primitives are set, so that they can be Nil - protected int primitiveSetMap; - - protected Object[] objectStorageLocations; - - public RubyBasicObject(RubyClass rubyClass) { - if (rubyClass != null) { - unsafeSetRubyClass(rubyClass); - - if (rubyClass.getContext().getConfiguration().getFullObjectSpace()) { - rubyClass.getContext().getObjectSpaceManager().add(this); - } - } - } - - public void initialize() { - } - - public LookupNode getLookupNode() { - return lookupNode; - } - - public RubyClass getRubyClass() { - assert rubyClass != null; - return rubyClass; - } - - public boolean hasPrivateLayout() { - return hasPrivateLayout; - } - - public ObjectLayout getObjectLayout() { - return objectLayout; - } - - public ObjectLayout getUpdatedObjectLayout() { - updateLayout(); - return objectLayout; - } - - /** - * Does this object have an instance variable defined? - */ - public boolean isInstanceVariableDefined(String name) { - if (!hasPrivateLayout && objectLayout != rubyClass.getObjectLayoutForInstances()) { - updateLayout(); - } - - return objectLayout.findStorageLocation(name) != null; - } - - /** - * Set an instance variable to be a value. Slow path. - */ - public void setInstanceVariable(String name, Object value) { - CompilerAsserts.neverPartOfCompilation(); - - // If the object's layout doesn't match the class, update - - if (!hasPrivateLayout && objectLayout != rubyClass.getObjectLayoutForInstances()) { - updateLayout(); - } - - // Find the storage location - - StorageLocation storageLocation = objectLayout.findStorageLocation(name); - - if (storageLocation == null) { - /* - * It doesn't exist, so create a new layout for the class that includes it and update - * the layout of this object. - */ - - rubyClass.setObjectLayoutForInstances(rubyClass.getObjectLayoutForInstances().withNewVariable(name, value.getClass())); - updateLayout(); - - storageLocation = objectLayout.findStorageLocation(name); - } - - // Try to write to that storage location - - try { - storageLocation.write(this, value); - } catch (GeneralizeStorageLocationException e) { - /* - * It might not be able to store the type that we passed, if not generalize the class's - * layout and update the layout of this object. - */ - - rubyClass.setObjectLayoutForInstances(rubyClass.getObjectLayoutForInstances().withGeneralisedVariable(name)); - updateLayout(); - - storageLocation = objectLayout.findStorageLocation(name); - - // Try to write to the generalized storage location - - try { - storageLocation.write(this, value); - } catch (GeneralizeStorageLocationException e1) { - // We know that we just generalized it, so this should not happen - throw new RuntimeException("Generalised an instance variable, but it still rejected the value"); - } - } - } - - /** - * Get the value of an instance variable, or Nil if it isn't defined. Slow path. - */ - public Object getInstanceVariable(String name) { - CompilerAsserts.neverPartOfCompilation(); - - // If the object's layout doesn't match the class, update - - if (!hasPrivateLayout && objectLayout != rubyClass.getObjectLayoutForInstances()) { - updateLayout(); - } - - // Find the storage location - - final StorageLocation storageLocation = objectLayout.findStorageLocation(name); - - // Get the value - - if (storageLocation == null) { - return NilPlaceholder.INSTANCE; - } - - return storageLocation.read(this, true); - } - - public String[] getInstanceVariableNames() { - final Set instanceVariableNames = getInstanceVariables().keySet(); - return instanceVariableNames.toArray(new String[instanceVariableNames.size()]); - } - - public RubyClass getSingletonClass() { - if (rubySingletonClass == null) { - /* - * The object a of class A has a singleton class a' of class Class, with name - * #>, and with superclass that is A. - * - * irb(main):001:0> class A; end - * - * => nil - * - * irb(main):002:0> a = A.new - * - * => # - * - * irb(main):003:0> a.singleton_class - * - * => #> - * - * irb(main):004:0> a.singleton_class.class - * - * => Class - * - * irb(main):005:0> a.singleton_class.superclass - * - * => A - */ - - rubySingletonClass = new RubyClass(rubyClass.getParentModule(), rubyClass, String.format("#>", rubyClass.getName(), getObjectID()), true); - - lookupNode = new LookupFork(rubySingletonClass, rubyClass); - } - - return rubySingletonClass; - } - - public long getObjectID() { - if (objectID == -1) { - objectID = rubyClass.getContext().getNextObjectID(); - } - - return objectID; - } - - public String inspect() { - return toString(); - } - - /** - * Get a map of all instance variables. - */ - protected Map getInstanceVariables() { - if (objectLayout == null) { - return Collections.emptyMap(); - } - - final Map instanceVariableMap = new HashMap<>(); - - for (Entry entry : objectLayout.getAllStorageLocations().entrySet()) { - final String name = entry.getKey(); - final StorageLocation storageLocation = entry.getValue(); - - if (storageLocation.isSet(this)) { - instanceVariableMap.put(name, storageLocation.read(this, true)); - } - } - - return instanceVariableMap; - } - - /** - * Set instance variables from a map. - */ - protected void setInstanceVariables(Map instanceVariables) { - assert instanceVariables != null; - - if (objectLayout == null) { - updateLayout(); - } - - for (Entry entry : instanceVariables.entrySet()) { - final StorageLocation storageLocation = objectLayout.findStorageLocation(entry.getKey()); - assert storageLocation != null; - - try { - storageLocation.write(this, entry.getValue()); - } catch (GeneralizeStorageLocationException e) { - throw new RuntimeException("Should not have to be generalising when setting instance variables - " + entry.getValue().getClass().getName() + ", " + - storageLocation.getStoredClass().getName()); - } - } - } - - /** - * Update the layout of this object to match that of its class. - */ - @CompilerDirectives.SlowPath - public void updateLayout() { - // Get the current values of instance variables - - final Map instanceVariableMap = getInstanceVariables(); - - // Use the layout of the class - - objectLayout = rubyClass.getObjectLayoutForInstances(); - - // Make all primitives as unset - - primitiveSetMap = 0; - - // Create a new array for objects - - allocateObjectStorageLocations(); - - // Restore values - - setInstanceVariables(instanceVariableMap); - } - - private void allocateObjectStorageLocations() { - final int objectStorageLocationsUsed = objectLayout.getObjectStorageLocationsUsed(); - - if (objectStorageLocationsUsed == 0) { - objectStorageLocations = null; - } else { - objectStorageLocations = new Object[objectStorageLocationsUsed]; - } - } - - public void switchToPrivateLayout() { - final Map instanceVariables = getInstanceVariables(); - - hasPrivateLayout = true; - objectLayout = ObjectLayout.EMPTY; - - for (Entry entry : instanceVariables.entrySet()) { - objectLayout = objectLayout.withNewVariable(entry.getKey(), entry.getValue().getClass()); - } - - setInstanceVariables(instanceVariables); - } - - public void extend(RubyModule module) { - getSingletonClass().include(module); - } - - @Override - public String toString() { - return "#<" + rubyClass.getName() + ":0x" + Long.toHexString(getObjectID()) + ">"; - } - - public boolean hasSingletonClass() { - return rubySingletonClass != null; - } - - public Object send(String name, RubyProc block, Object... args) { - final RubyMethod method = getLookupNode().lookupMethod(name); - - if (method == null || method.isUndefined()) { - throw new RaiseException(getRubyClass().getContext().getCoreLibrary().noMethodError(name, toString())); - } - - return method.call(null, this, block, args); - } - - public void unsafeSetRubyClass(RubyClass newRubyClass) { - assert rubyClass == null; - - rubyClass = newRubyClass; - lookupNode = rubyClass; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/StorageLocation.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/StorageLocation.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -/** - * A storage location that abstracts the method for reading and writing values. - */ -public abstract class StorageLocation { - - private ObjectLayout objectLayout; - - protected StorageLocation(ObjectLayout objectLayout) { - this.objectLayout = objectLayout; - } - - public abstract boolean isSet(RubyBasicObject object); - - public abstract Object read(RubyBasicObject object, boolean condition); - - public abstract void write(RubyBasicObject object, Object value) throws GeneralizeStorageLocationException; - - public abstract Class getStoredClass(); - - public ObjectLayout getObjectLayout() { - return objectLayout; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/Unboxable.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/Unboxable.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2013 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.objects; - -/** - * An object that can be losslessly unboxed back to a more primitive value. - */ -public interface Unboxable { - - Object unbox(); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/AtExitManager.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/AtExitManager.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2013 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.subsystems; - -import java.util.*; - -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Manages at_exit callbacks. - */ -public class AtExitManager { - - private final List blocks = new ArrayList<>(); - - public void add(RubyProc block) { - blocks.add(block); - } - - public void run() { - final ListIterator iterator = blocks.listIterator(blocks.size()); - - while (iterator.hasPrevious()) { - iterator.previous().call(null); - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FeatureManager.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FeatureManager.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2013 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.subsystems; - -import java.io.*; -import java.net.*; -import java.util.*; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -/** - * Manages the features loaded into Ruby. This basically means which library files are loaded, but - * Ruby often talks about requiring features, not files. - * - */ -public class FeatureManager { - - private RubyContext context; - - private final Set requiredFiles = new HashSet<>(); - - public FeatureManager(RubyContext context) { - this.context = context; - } - - public boolean require(String feature) throws IOException { - // Some features are handled specially - - if (feature.equals("stringio")) { - context.implementationMessage("stringio not yet implemented"); - return true; - } - - if (feature.equals("rbconfig")) { - // Kernel#rbconfig is always there - return true; - } - - if (feature.equals("pp")) { - // Kernel#pretty_inspect is always there - return true; - } - - // Get the load path - - final Object loadPathObject = context.getCoreLibrary().getGlobalVariablesObject().getInstanceVariable("$:"); - - if (!(loadPathObject instanceof RubyArray)) { - throw new RuntimeException("$: is not an array"); - } - - final List loadPath = ((RubyArray) loadPathObject).asList(); - - // Try as a full path - - if (requireInPath("", feature)) { - return true; - } - - // Try each load path in turn - - for (Object pathObject : loadPath) { - final String path = pathObject.toString(); - - if (requireInPath(path, feature)) { - return true; - } - } - - // Didn't find the feature - - throw new RaiseException(context.getCoreLibrary().loadErrorCannotLoad(feature)); - } - - public boolean requireInPath(String path, String feature) throws IOException { - if (requireFile(feature)) { - return true; - } - - if (requireFile(feature + ".rb")) { - return true; - } - - if (requireFile(path + File.separator + feature)) { - return true; - } - - if (requireFile(path + File.separator + feature + ".rb")) { - return true; - } - - return false; - } - - private boolean requireFile(String fileName) throws IOException { - if (requiredFiles.contains(fileName)) { - return true; - } - - /* - * There is unfortunately no way to check if a string is a file path, or a URL. file:foo.txt - * is a valid file name, as well as a valid URL. We try as a file path first. - */ - - if (new File(fileName).isFile()) { - context.loadFile(fileName); - requiredFiles.add(fileName); - return true; - } else { - URL url; - - try { - url = new URL(fileName); - } catch (MalformedURLException e) { - return false; - } - - InputStream inputStream; - - try { - inputStream = url.openConnection().getInputStream(); - } catch (IOException e) { - return false; - } - - context.load(context.getSourceManager().get(url.toString(), inputStream)); - requiredFiles.add(fileName); - return true; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FiberManager.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FiberManager.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013 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.subsystems; - -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Manages Ruby {@code Fiber} objects. - */ -public class FiberManager { - - private final RubyFiber rootFiber; - private RubyFiber currentFiber; - - private final Set runningFibers = Collections.newSetFromMap(new ConcurrentHashMap()); - - public FiberManager(RubyContext context) { - rootFiber = new RubyFiber(context.getCoreLibrary().getFiberClass(), this, context.getThreadManager()); - currentFiber = rootFiber; - } - - public RubyFiber getCurrentFiber() { - return currentFiber; - } - - public void setCurrentFiber(RubyFiber fiber) { - currentFiber = fiber; - } - - public void registerFiber(RubyFiber fiber) { - runningFibers.add(fiber); - } - - public void unregisterFiber(RubyFiber fiber) { - runningFibers.remove(fiber); - } - - public void shutdown() { - for (RubyFiber fiber : runningFibers) { - fiber.shutdown(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ObjectSpaceManager.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ObjectSpaceManager.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2013 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.subsystems; - -import java.lang.ref.*; -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -/** - * Supports the Ruby {@code ObjectSpace} module. Object IDs are lazily allocated {@code long} - * values, mapped to objects with a weak hash map. Finalizers are implemented with weak references - * and reference queues, and are run in a dedicated Ruby thread (but not a dedicated Java thread). - */ -public class ObjectSpaceManager { - - private class FinalizerReference extends WeakReference { - - public List finalizers = new LinkedList<>(); - - public FinalizerReference(RubyBasicObject object, ReferenceQueue queue) { - super(object, queue); - } - - public void addFinalizer(RubyProc proc) { - finalizers.add(proc); - } - - public List getFinalizers() { - return finalizers; - } - - public void clearFinalizers() { - finalizers = new LinkedList<>(); - } - - } - - private final RubyContext context; - - // TODO(cs): this is wrong - WeakHashMap is not weak in the value - private final WeakHashMap objects = new WeakHashMap<>(); - - private final Map finalizerReferences = new WeakHashMap<>(); - private final ReferenceQueue finalizerQueue = new ReferenceQueue<>(); - private RubyThread finalizerThread; - private Thread finalizerJavaThread; - private boolean stop; - private CountDownLatch finished = new CountDownLatch(1); - - public ObjectSpaceManager(RubyContext context) { - this.context = context; - } - - public void add(RubyBasicObject object) { - objects.put(object.getObjectID(), object); - } - - public RubyBasicObject lookupId(long id) { - return objects.get(id); - } - - public void defineFinalizer(RubyBasicObject object, RubyProc proc) { - // Record the finalizer against the object - - FinalizerReference finalizerReference = finalizerReferences.get(object); - - if (finalizerReference == null) { - finalizerReference = new FinalizerReference(object, finalizerQueue); - finalizerReferences.put(object, finalizerReference); - } - - finalizerReference.addFinalizer(proc); - - // If there is no finalizer thread, start one - - if (finalizerThread == null) { - finalizerThread = new RubyThread(context.getCoreLibrary().getThreadClass(), context.getThreadManager()); - - finalizerThread.initialize(new Runnable() { - - @Override - public void run() { - runFinalizers(); - } - - }); - } - } - - public void undefineFinalizer(RubyBasicObject object) { - final FinalizerReference finalizerReference = finalizerReferences.get(object); - - if (finalizerReference != null) { - finalizerReference.clearFinalizers(); - } - } - - private void runFinalizers() { - // Run in a loop - - while (true) { - // Is there a finalizer ready to immediately run? - - FinalizerReference finalizerReference = (FinalizerReference) finalizerQueue.poll(); - - if (finalizerReference != null) { - runFinalizers(finalizerReference); - continue; - } - - // Check if we've been asked to stop - - if (stop) { - break; - } - - // Leave the global lock and wait on the finalizer queue - - final RubyThread runningThread = context.getThreadManager().leaveGlobalLock(); - finalizerJavaThread = Thread.currentThread(); - - try { - finalizerReference = (FinalizerReference) finalizerQueue.remove(); - } catch (InterruptedException e) { - continue; - } finally { - context.getThreadManager().enterGlobalLock(runningThread); - } - - runFinalizers(finalizerReference); - } - - finished.countDown(); - } - - private static void runFinalizers(FinalizerReference finalizerReference) { - try { - for (RubyProc proc : finalizerReference.getFinalizers()) { - proc.call(null); - } - } catch (Exception e) { - // MRI seems to silently ignore exceptions in finalizers - } - } - - public void shutdown() { - context.getThreadManager().enterGlobalLock(finalizerThread); - - try { - // Tell the finalizer thread to stop and wait for it to do so - - if (finalizerThread != null) { - stop = true; - - if (finalizerJavaThread != null) { - finalizerJavaThread.interrupt(); - } - - context.getThreadManager().leaveGlobalLock(); - - try { - finished.await(); - } catch (InterruptedException e) { - } finally { - context.getThreadManager().enterGlobalLock(finalizerThread); - } - } - - // Run any finalizers for objects that are still live - - for (FinalizerReference finalizerReference : finalizerReferences.values()) { - runFinalizers(finalizerReference); - } - } finally { - context.getThreadManager().leaveGlobalLock(); - } - } - - public Collection getObjects() { - return objects.values(); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ThreadManager.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ThreadManager.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013 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.subsystems; - -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.locks.*; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Manages Ruby {@code Thread} objects. - */ -public class ThreadManager { - - private final ReentrantLock globalLock = new ReentrantLock(); - - private final RubyThread rootThread; - private RubyThread currentThread; - - private final Set runningThreads = Collections.newSetFromMap(new ConcurrentHashMap()); - - public ThreadManager(RubyContext context) { - rootThread = new RubyThread(context.getCoreLibrary().getFiberClass(), this); - runningThreads.add(rootThread); - enterGlobalLock(rootThread); - } - - /** - * Enters the global lock. Reentrant, but be aware that Ruby threads are not one-to-one with - * Java threads. Needs to be told which Ruby thread is becoming active as it can't work this out - * from the current Java thread. Remember to call {@link #leaveGlobalLock} again before - * blocking. - */ - public void enterGlobalLock(RubyThread thread) { - globalLock.lock(); - currentThread = thread; - } - - /** - * Leaves the global lock, returning the Ruby thread which has just stopped being the current - * thread. Remember to call {@link #enterGlobalLock} again with that returned thread before - * executing any Ruby code. You probably want to use this with a {@code finally} statement to - * make sure that happens - */ - public RubyThread leaveGlobalLock() { - if (!globalLock.isHeldByCurrentThread()) { - throw new RuntimeException("You don't own this lock!"); - } - - final RubyThread result = currentThread; - globalLock.unlock(); - return result; - } - - public RubyThread getCurrentThread() { - return currentThread; - } - - public void registerThread(RubyThread thread) { - runningThreads.add(thread); - } - - public void unregisterThread(RubyThread thread) { - runningThreads.remove(thread); - } - - public void shutdown() { - for (RubyThread thread : runningThreads) { - thread.shutdown(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/TraceManager.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/TraceManager.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2013 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.subsystems; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * Manages trace events and calls the user's trace method if one is set. - *

- * Once tracing has been enabled via {@link #setTraceProc(RubyProc)}, the underlying instrumentation - * remains in effect, along with performance impact. - */ -public final class TraceManager { - - private RubyContext context; - - private final AssumedValue traceProc = new AssumedValue<>("trace-proc", null); - private boolean suspended; - - private String lastFile; - private int lastLine; - - private final Assumption notTracingAssumption = Truffle.getRuntime().createAssumption("tracing-disabled"); - - public TraceManager(RubyContext context) { - this.context = context; - } - - /** - * Produce a trace; it is a runtime error if {@link #hasTraceProc()}{@code == false}. - */ - @CompilerDirectives.SlowPath - public void trace(String event, String file, int line, long objectId, RubyBinding binding, String className) { - // If tracing is suspended, stop here - - if (suspended) { - return; - } - - // If the file and line haven't changed since the last trace, stop here - - if (file.equals(lastFile) && line == lastLine) { - return; - } - - final RubyClass stringClass = context.getCoreLibrary().getStringClass(); - - // Suspend tracing while we run the trace proc - - suspended = true; - - try { - // Exceptions from within the proc propagate normally - - traceProc.get().call(null, new RubyString(stringClass, event), // - new RubyString(stringClass, file), // - line, // - GeneralConversions.fixnumOrBignum(objectId), // - GeneralConversions.instanceOrNil(binding), // - GeneralConversions.instanceOrNil(className)); - } finally { - // Resume tracing - - suspended = false; - } - - // Remember the last trace event file and line - - lastFile = file; - lastLine = line; - } - - /** - * Is there a "trace proc" in effect? - */ - public boolean hasTraceProc() { - return traceProc.get() != null; - } - - /** - * Gets the assumption that there has never yet been tracing enabled. Once the assumption is - * invalidated, tracing is presumed permanently enabled even if {@link #hasTraceProc()} returns - * {@code false}. - */ - public Assumption getNotTracingAssumption() { - return notTracingAssumption; - } - - public void setTraceProc(RubyProc newTraceProc) { - if (!context.getConfiguration().getTrace()) { - throw new RuntimeException("You need the --trace option to use tracing"); - } - - traceProc.set(newTraceProc); - lastFile = null; - lastLine = -1; - - notTracingAssumption.invalidate(); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineOptions.java --- a/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineOptions.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2013 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.shell; - -import java.util.*; - -import com.oracle.truffle.ruby.runtime.configuration.*; - -/** - * Options resulting from parsing a command line by {@link CommandLineParser}. - */ -public class CommandLineOptions { - - private final List preRequires; - private final String preChangeDirectory; - - private final List extraLoadPath; - - private final String programFile; - private final List commandLineScripts; - private final List programArgs; - private final List switchArgs; - - private final int recordSeparator; - private final boolean autosplit; - private final String autosplitPattern; - private final boolean checkSyntaxOnly; - private final boolean lineEndingProcessing; - private final boolean inPlaceEdit; - private final String inPlaceBackupExtension; - private final boolean implicitLoop; - private final boolean implicitSedLoop; - private final boolean importFromPath; - private final boolean stripMessage; - private final boolean useJLine; - - private final Configuration configuration; - - public CommandLineOptions(List preRequires, String preChangeDirectory, List extraLoadPath, String programFile, List commandLineScripts, List programArgs, - List switchArgs, int recordSeparator, boolean autosplit, String autosplitPattern, boolean checkSyntaxOnly, boolean lineEndingProcessing, boolean inPlaceEdit, - String inPlaceBackupExtension, boolean implicitLoop, boolean implicitSedLoop, boolean importFromPath, boolean stripMessage, boolean useJLine, Configuration configuration) { - this.preRequires = preRequires; - this.preChangeDirectory = preChangeDirectory; - this.extraLoadPath = extraLoadPath; - this.programFile = programFile; - this.commandLineScripts = commandLineScripts; - this.programArgs = programArgs; - this.switchArgs = switchArgs; - this.recordSeparator = recordSeparator; - this.autosplit = autosplit; - this.autosplitPattern = autosplitPattern; - this.checkSyntaxOnly = checkSyntaxOnly; - this.lineEndingProcessing = lineEndingProcessing; - this.inPlaceEdit = inPlaceEdit; - this.inPlaceBackupExtension = inPlaceBackupExtension; - this.implicitLoop = implicitLoop; - this.implicitSedLoop = implicitSedLoop; - this.importFromPath = importFromPath; - this.stripMessage = stripMessage; - this.useJLine = useJLine; - this.configuration = configuration; - } - - public List getPreRequires() { - return preRequires; - } - - public String getPreChangeDirectory() { - return preChangeDirectory; - } - - public List getExtraLoadPath() { - return extraLoadPath; - } - - public String getProgramFile() { - return programFile; - } - - public List getCommandLineScripts() { - return commandLineScripts; - } - - public List getProgramArgs() { - return programArgs; - } - - public List getSwitchArgs() { - return switchArgs; - } - - public int getRecordSeparator() { - return recordSeparator; - } - - public String getAutosplitPattern() { - return autosplitPattern; - } - - public boolean isAutosplit() { - return autosplit; - } - - public boolean isCheckSyntaxOnly() { - return checkSyntaxOnly; - } - - public boolean isLineEndingProcessing() { - return lineEndingProcessing; - } - - public boolean isInPlaceEdit() { - return inPlaceEdit; - } - - public String getInPlaceBackupExtension() { - return inPlaceBackupExtension; - } - - public boolean isImplicitLoop() { - return implicitLoop; - } - - public boolean isImplicitSedLoop() { - return implicitSedLoop; - } - - public boolean isImportFromPath() { - return importFromPath; - } - - public boolean isStripMessage() { - return stripMessage; - } - - public boolean useJLine() { - return useJLine; - } - - public Configuration getConfiguration() { - return configuration; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineParser.java --- a/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineParser.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,355 +0,0 @@ -/* - * Copyright (c) 2013 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.shell; - -import java.io.*; -import java.util.*; - -import com.oracle.truffle.ruby.runtime.configuration.*; - -/** - * MRI-compatible command line parser, producing {@link CommandLineOptions}. - */ -public abstract class CommandLineParser { - - /** - * Parse an MRI-compatible command line. - */ - public static CommandLineOptions parse(String[] args) { - assert args != null; - - final List preRequires = new ArrayList<>(); - String preChangeDirectory = null; - - final List extraLoadPath = new ArrayList<>(); - - String programFile = null; - final List commandLineScripts = new ArrayList<>(); - final List programArgs = new ArrayList<>(); - final List switchArgs = new ArrayList<>(); - - int recordSeparator = -1; - boolean autosplit = false; - String autosplitPattern = null; - boolean checkSyntaxOnly = false; - boolean lineEndingProcessing = false; - boolean inPlaceEdit = false; - String inPlaceBackupExtension = null; - boolean implicitLoop = false; - boolean implicitSedLoop = false; - boolean importFromPath = false; - boolean messageStrip = false; - boolean useJLine = true; - - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - - final List normalizedArgs = normalizeArgs(args); - - boolean stillRubyArgs = true; - boolean collectingSwitchArgs = false; - int n = 0; - - while (n < normalizedArgs.size()) { - final String arg = normalizedArgs.get(n); - - if (stillRubyArgs && arg.startsWith("-")) { - if (collectingSwitchArgs) { - switchArgs.add(arg); - } else if (arg.startsWith("-0")) { - if (arg.length() == 2) { - recordSeparator = 0; - } else { - recordSeparator = Integer.parseInt(arg.substring(2), 8); - } - } else if (arg.startsWith("-i")) { - inPlaceEdit = true; - - if (arg.length() > 2) { - inPlaceBackupExtension = arg.substring(2); - } - } else if (arg.startsWith("-W")) { - if (arg.length() == 2) { - configurationBuilder.setWarningLevel(2); - } else if (arg.startsWith("-Wlevel=")) { - configurationBuilder.setWarningLevel(Integer.parseInt(arg.substring("-Wlevel=".length()))); - } else { - throw new IllegalArgumentException("bad flag " + arg); - } - } else if (arg.startsWith("-T")) { - if (arg.length() == 2) { - configurationBuilder.setTaintCheckLevel(1); - } else if (arg.startsWith("-Tlevel=")) { - configurationBuilder.setTaintCheckLevel(Integer.parseInt(arg.substring("-Tlevel=".length()))); - } else { - throw new IllegalArgumentException("bad flag " + arg); - } - } else if (arg.startsWith("-x")) { - messageStrip = true; - - if (arg.length() > 2) { - preChangeDirectory = arg.substring(2); - } - } else { - switch (arg) { - case "-C": - case "-e": - case "-E": - case "-F": - case "-I": - case "-r": - case "--home": - if (n + 1 >= normalizedArgs.size()) { - throw new RuntimeException("Expecting value after " + arg); - } - } - - switch (arg) { - case "--": - stillRubyArgs = false; - break; - case "-a": - autosplit = true; - break; - case "-c": - checkSyntaxOnly = true; - break; - case "-C": - if (n + 1 >= normalizedArgs.size()) { - throw new RuntimeException("Need a directory path after -C"); - } - preChangeDirectory = normalizedArgs.get(n + 1); - n++; - break; - case "-d": - case "--debug": - configurationBuilder.setDebug(true); - break; - case "--no-debug": - configurationBuilder.setDebug(false); - break; - case "--trace": - configurationBuilder.setTrace(true); - break; - case "--no-trace": - configurationBuilder.setTrace(false); - break; - case "-e": - commandLineScripts.add(normalizedArgs.get(n + 1)); - n++; - break; - case "-E": - final String[] encodings = normalizedArgs.get(n + 1).split(":"); - configurationBuilder.setDefaultExternalEncoding(encodings[0]); - - if (encodings.length == 2) { - configurationBuilder.setDefaultInternalEncoding(encodings[1]); - } else { - throw new IllegalArgumentException("bad flag " + arg); - } - - n++; - break; - case "-F": - autosplitPattern = normalizedArgs.get(n + 1); - n++; - break; - case "-I": - extraLoadPath.add(normalizedArgs.get(n + 1)); - n++; - break; - case "-l": - lineEndingProcessing = true; - break; - case "-n": - implicitLoop = true; - break; - case "-r": - preRequires.add(normalizedArgs.get(n + 1)); - n++; - break; - case "-s": - collectingSwitchArgs = true; - break; - case "-p": - implicitSedLoop = true; - break; - case "-S": - importFromPath = true; - break; - case "-w": - configurationBuilder.setWarningLevel(1); - break; - case "-h": - case "--help": - help(System.out); - return null; - case "-v": - version(System.out); - configurationBuilder.setVerbose(true); - break; - case "--version": - version(System.out); - return null; - case "--copyright": - copyright(System.out); - return null; - case "--home": - configurationBuilder.setStandardLibrary(normalizedArgs.get(n + 1) + "/" + ConfigurationBuilder.JRUBY_STDLIB_JAR); - n++; - break; - case "--stdlib": - configurationBuilder.setStandardLibrary(normalizedArgs.get(n + 1)); - n++; - break; - case "--full-object-space": - configurationBuilder.setFullObjectSpace(true); - break; - case "--no-jline": - useJLine = false; - break; - case "--print-parse-tree": - configurationBuilder.setPrintParseTree(true); - break; - case "--print-uninitialized-calls": - configurationBuilder.setPrintUninitializedCalls(true); - break; - case "--print-java-exceptions": - configurationBuilder.setPrintJavaExceptions(true); - break; - default: - throw new IllegalArgumentException("unknown flag " + arg); - } - } - } else if (programFile == null) { - programFile = arg; - stillRubyArgs = false; - } else { - programArgs.add(arg); - } - - n++; - } - - return new CommandLineOptions(preRequires, preChangeDirectory, extraLoadPath, programFile, commandLineScripts, programArgs, switchArgs, recordSeparator, autosplit, autosplitPattern, - checkSyntaxOnly, lineEndingProcessing, inPlaceEdit, inPlaceBackupExtension, implicitLoop, implicitSedLoop, importFromPath, messageStrip, useJLine, new Configuration( - configurationBuilder)); - } - - /** - * Produce a canonical set of arguments that includes {@code $RUBYOPT} and has contractions such - * as a {@code -rdir} replaced with separate arguments {@code -r} and {@code dir} for simpler - * processing. - */ - private static List normalizeArgs(String[] args) { - assert args != null; - - // Arguments come from the main method arguments parameter and $RUBYOPT - - final List inputArgs = new ArrayList<>(); - - final String rubyoptVar = System.getenv("RUBYOPT"); - - if (rubyoptVar != null) { - /* - * TODO(cs): what we've got here is a string that we are supposed to treat as if it was - * an extra part of the command line, including more Ruby options. However, we just get - * the string and have to split it into arguments ourselves. Normally the shell does - * that, including lots of fancy quoting styles. Are we supposed to re-implement all of - * that? Otherwise arguments in RUBYOPT will be parsed differently to if they were - * actually on the command line. JRuby just splits like we do. I also think that's what - * MRI does, but is this correct? - */ - - inputArgs.addAll(Arrays.asList(rubyoptVar.split("\\s+"))); - } - - inputArgs.addAll(Arrays.asList(args)); - - // Replace some contractions such as -rdir with -r dir - - final List outputArgs = new ArrayList<>(); - - for (String arg : inputArgs) { - if (arg.startsWith("-C") || arg.startsWith("-E") || arg.startsWith("-F") || arg.startsWith("-I") || arg.startsWith("-r")) { - outputArgs.add(arg.substring(0, 2)); - outputArgs.add(arg.substring(2)); - } else { - outputArgs.add(arg); - } - } - - return outputArgs; - } - - /** - * Print help information. - */ - private static void help(PrintStream out) { - out.println("Usage: ruby [switches] [--] [programfile] [arguments]"); - out.println(" -0[octal] specify record separator (\0, if no argument)"); - out.println(" -a autosplit mode with -n or -p (splits $_ into $F)"); - out.println(" -c check syntax only"); - out.println(" -Cdirectory cd to directory, before executing your script"); - out.println(" -d, --debug set debugging flags (set $DEBUG to true) and enable Debug module"); - out.println(" -e 'command' one line of script. Several -e's allowed. Omit [programfile]"); - out.println(" -Eex[:in] specify the default external and internal character encodings"); - out.println(" -Fpattern split() pattern for autosplit (-a)"); - out.println(" -i[extension] edit ARGV files in place (make backup if extension supplied)"); - out.println(" -Idirectory specify $LOAD_PATH directory (may be used more than once)"); - out.println(" -l enable line ending processing"); - out.println(" -n assume 'while gets(); ... end' loop around your script"); - out.println(" -p assume loop like -n but print line also like sed"); - out.println(" -rlibrary require the library, before executing your script"); - out.println(" -s enable some switch parsing for switches after script name"); - out.println(" -S look for the script using PATH environment variable"); - out.println(" -T[level=1] turn on tainting checks"); - out.println(" -v print version number, then turn on verbose mode"); - out.println(" -w turn warnings on for your script"); - out.println(" -W[level=2] set warning level; 0=silence, 1=medium, 2=verbose"); - out.println(" -x[directory] strip off text before #!ruby line and perhaps cd to directory"); - out.println(" --copyright print the copyright"); - out.println(" --version print the version"); - out.println("Extra rubytruffle switches:"); - out.println(" --home dir set the location of the Ruby Truffle installation (default . or $RUBY_TRUFFLE_HOME)"); - out.println(" --stdlib dir use a directory for the Ruby standard library"); - out.println(" --full-object-space enable full ObjectSpace#each_object and similar"); - out.println(" --no-debug disable debugging"); - out.println(" --no-trace disable tracing"); - out.println("Debugging rubytruffle switches:"); - out.println(" --no-cache-constant-lookup don't cache constant lookups"); - out.println(" --no-cache-method-calls don't cache method lookups"); - out.println(" --no-intrinsic-method-calls don't turn method calls into intrinsic nodes"); - out.println(" --no-jline don't use JLine"); - out.println(" --print-parse-tree print the result of parsing"); - out.println(" --print-uninitialized-calls print each time a method call is uninitialized"); - out.println(" --print-java-exceptions print Java exception back traces at the point of translating them to Ruby exceptions"); - out.println("Relevant environment variables:"); - out.println(" RUBYHOME location of the Ruby Truffle installation"); - out.println(" RUBYOPT extra command line arguments"); - out.println(" RUBYLIB list of colon separated paths to add to $LOAD_PATH"); - out.println(" PATH as RUBYLIB, if -S is used"); - } - - /** - * Print version information. - */ - private static void version(PrintStream out) { - out.printf("ruby (rubytruffle) dev [JVM %s]\n", System.getProperty("java.version")); - } - - /** - * Print copyright information. - */ - private static void copyright(PrintStream out) { - out.println("Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved."); - out.println("ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms."); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/Shell.java --- a/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/Shell.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +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.shell; - -import java.io.*; - -import jline.console.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.ruby.nodes.core.*; -import com.oracle.truffle.ruby.parser.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.configuration.*; -import com.oracle.truffle.ruby.runtime.core.array.*; - -/** - * The entry point class for RubyTruffle. Implements the MRI command line interface. - */ -public class Shell { - - /** - * Entry point method for Ruby both in batch and interactive mode. - */ - public static void main(String[] args) throws IOException { - // Parse the command line - - final CommandLineOptions options = CommandLineParser.parse(args); - - if (options == null) { - return; - } - - // Setup JLine - - ConsoleReader console = null; - - if (options.useJLine()) { - System.setProperty("jline.shutdownhook", "true"); - console = new ConsoleReader(); - console.setExpandEvents(false); - } - - // Override the home directory if RUBYHOME is set - - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(options.getConfiguration()); - - if (System.getenv("RUBYHOME") != null) { - configurationBuilder.setStandardLibrary(System.getenv("RUBYHOME") + "/" + ConfigurationBuilder.JRUBY_STDLIB_JAR); - } - - // Use JLine for console input - - final ConsoleReader finalConsole = console; - - if (options.useJLine()) { - configurationBuilder.setInputReader(new InputReader() { - - @Override - public String readLine(String prompt) throws IOException { - return finalConsole.readLine(prompt); - } - - }); - } - - // Set up a context - - final RubyContext context = new RubyContext(new Configuration(configurationBuilder), new JRubyParser()); - - // Ruby should always have a debug context. - context.setDebugContext(new MinimalRubyDebugContext(context)); - - // Bring in core method nodes - - CoreMethodNodeManager.addMethods(context.getCoreLibrary().getObjectClass()); - - // Give the core library manager a chance to tweak some of those methods - - context.getCoreLibrary().initializeAfterMethodsAdded(); - - // Set program arguments - - for (String arg : options.getProgramArgs()) { - context.getCoreLibrary().getArgv().push(context.makeString(arg)); - } - - if (!options.getSwitchArgs().isEmpty()) { - context.implementationMessage("can't set -s switch arguments yet"); - } - - // Set the load path - - final RubyArray loadPath = (RubyArray) context.getCoreLibrary().getGlobalVariablesObject().getInstanceVariable("$:"); - - final String pathVar = System.getenv("PATH"); - - if (options.isImportFromPath() && pathVar != null) { - for (String path : pathVar.split(File.pathSeparator)) { - loadPath.push(context.makeString(path)); - } - } - - for (String path : options.getExtraLoadPath()) { - loadPath.push(context.makeString(path)); - } - - final String rubylibVar = System.getenv("RUBYLIB"); - - if (rubylibVar != null) { - for (String path : rubylibVar.split(File.pathSeparator)) { - loadPath.push(context.makeString(path)); - } - } - - if (context.getConfiguration().getStandardLibrary().endsWith(".jar")) { - /* - * Use the 1.9 library, even though we're emulating 2.1, as there are some bugs running - * the 2.1 library at the moment. - */ - loadPath.push(context.makeString("jar:file:" + context.getConfiguration().getStandardLibrary() + "!/META-INF/jruby.home/lib/ruby/1.9")); - } else { - loadPath.push(context.makeString(context.getConfiguration().getStandardLibrary())); - } - - // Pre-required modules - - for (String feature : options.getPreRequires()) { - context.getFeatureManager().require(feature); - } - - // Check for other options that are not implemented yet - - if (options.getRecordSeparator() != -1) { - context.implementationMessage("record separator not implemented"); - } - - if (options.isAutosplit()) { - context.implementationMessage("autosplit not implemented"); - } - - if (options.getPreChangeDirectory() != null) { - context.implementationMessage("not able to change directory"); - } - - if (options.isLineEndingProcessing()) { - context.implementationMessage("line end processing not implemented"); - } - - if (options.isInPlaceEdit()) { - context.implementationMessage("in place editing not implemented"); - } - - if (options.isImplicitLoop() || options.isImplicitSedLoop()) { - context.implementationMessage("implicit loops not implemented"); - } - - if (options.isStripMessage()) { - context.implementationMessage("strip message -x option not implemented"); - } - - // Run the scripts, program file, or run the temporary version of IRB - - try { - if (!options.getCommandLineScripts().isEmpty()) { - final StringBuilder combinedScript = new StringBuilder(); - - for (String script : options.getCommandLineScripts()) { - combinedScript.append(script); - combinedScript.append("\n"); - } - - try { - final Source source = context.getSourceManager().get("-e", combinedScript.toString()); - if (options.isCheckSyntaxOnly()) { - context.getParser().parse(context, source, RubyParser.ParserContext.TOP_LEVEL, null); - System.out.println("Syntax OK"); - } else { - context.execute(context, source, RubyParser.ParserContext.TOP_LEVEL, context.getCoreLibrary().getMainObject(), null); - } - } catch (Exception e) { - e.printStackTrace(); - } - } else if (options.getProgramFile() != null) { - try { - if (options.isCheckSyntaxOnly()) { - final Source source = context.getSourceManager().get(options.getProgramFile()); - context.getParser().parse(context, source, RubyParser.ParserContext.TOP_LEVEL, null); - System.out.println("Syntax OK"); - } else { - context.loadFile(options.getProgramFile()); - } - } catch (Exception e) { - e.printStackTrace(); - } - } else { - if (options.isCheckSyntaxOnly()) { - System.err.println("Can't check syntax in IRB mode"); - return; - } - - context.runShell(null, null); - } - } finally { - context.shutdown(); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/README --- a/graal/com.oracle.truffle.ruby.test/specs/README Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -This is a configuration of the RubySpec set of specifications - -http://rubyspec.org. RubySpec is the specifications, and MSpec is the tool to -run them. - -Thanks to Brian Shirai and others who have worked on RubySpec. - -At the moment we have only configured the version 1.9 specs, and we only run -language and command line specs. - -In the `specs` directory (everything we do here will be in the `specs` -directory), you need to clone the MSpec and RubySpec Git repositories: - - $ git clone https://github.com/rubyspec/mspec.git - $ git --git-dir=mspec/.git --work-tree=mspec checkout 1343524a06466b7aa0c90798b7894454c8abce0f - $ git clone https://github.com/rubyspec/rubyspec.git - $ git --git-dir=rubyspec/.git --work-tree=rubyspec checkout 926e356b268fe32c67bec43a21565d727360a89b - -Then you can run MSpec to run RubySpec. We can run all of the harness in our -implementation, not just as an executable under test. - - $ ./rubytruffle mspec/bin/mspec run -t ./rubytruffle --config rubytruffle.mspec --excl-tag fails diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/rubytruffle --- a/graal/com.oracle.truffle.ruby.test/specs/rubytruffle Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -#!/bin/bash - -# The command this file executes is what mx would execute, just taken out of -# the mx wrapper because it appears to interfere with MSpec, and we need a -# 'executable' (a shell script will do) to run. -# -# If this file isn't working for you try generating one for your setup. You -# will need to do this for example if your Java isn't 1.7.0u45. You can use -# the command below - the -v flag gives you the Java command, then just append -# "$@". -# -# $TRUFFLE_DIR/mxtool/mx -v --vm server-nograal ruby -ea -- --home $TRUFFLE_DIR "$@" - -TRUFFLE_DIR=../../.. - -$TRUFFLE_DIR/jdk1.7.0_45/product/bin/java \ - -server-nograal -d64 -ea \ - -cp $TRUFFLE_DIR/lib/jline-2.10.jar:$TRUFFLE_DIR/lib/jrubyparser-0.5.0.jar:$TRUFFLE_DIR/lib/jruby-stdlib-1.7.4.jar:$TRUFFLE_DIR/lib/jnr-posix-3.0.0.jar:$TRUFFLE_DIR/lib/jnr-constants-0.8.4.jar:$TRUFFLE_DIR/lib/jnr-ffi-1.0.4.jar:$TRUFFLE_DIR/lib/jffi-1.2.1.jar:$TRUFFLE_DIR/lib/jffi-1.2.1-native.jar:$TRUFFLE_DIR/lib/jnr-x86asm-1.0.2.jar:$TRUFFLE_DIR/lib/asm-4.0.jar:$TRUFFLE_DIR/lib/asm-analysis-4.0.jar:$TRUFFLE_DIR/lib/asm-commons-4.0.jar:$TRUFFLE_DIR/lib/asm-tree-4.0.jar:$TRUFFLE_DIR/lib/asm-util-4.0.jar:$TRUFFLE_DIR/graal/com.oracle.truffle.api/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.runtime/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.api.dsl/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.nodes/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.parser/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.shell/bin \ - com.oracle.truffle.ruby.shell.Shell \ - --home $TRUFFLE_DIR "$@" diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/rubytruffle.mspec --- a/graal/com.oracle.truffle.ruby.test/specs/rubytruffle.mspec Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -class MSpecScript - - Rubyspec = "rubyspec" - - set :command_line, [ - "rubyspec/command_line" - ] - - set :language, [ - "rubyspec/language" - ] - - set :tags_patterns, [ - [/rubyspec/, "tags"], - [/_spec.rb$/, "_tags.txt"] - ] - - MSpec.enable_feature :encoding - MSpec.enable_feature :continuation - MSpec.enable_feature :fiber - MSpec.enable_feature :fork - MSpec.enable_feature :generator - - set :files, get(:command_line) + get(:language) - -end diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_a_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_a_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:The -a command line option runs the code in loop conditional on Kernel.gets() -fails:The -a command line option sets $-a diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_d_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_d_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -fails:The -d command line option sets $DEBUG to true -fails:The -d command line option sets $VERBOSE to true -fails:The -d command line option sets $-d to true diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_e_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_e_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:The -e command line option with -n and a Fixnum range mimics an awk conditional by comparing an inclusive-end range with $. -fails:The -e command line option with -n and a Fixnum range mimics a sed conditional by comparing an exclusive-end range with $. diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_n_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_n_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -fails:The -n command line option runs the code in loop conditional on Kernel.gets() -fails:The -n command line option only evaluates BEGIN blocks once -fails:The -n command line option only evaluates END blocks once -fails:The -n command line option allows summing over a whole file diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_p_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_p_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:The -p command line option runs the code in loop conditional on Kernel.gets() and prints $_ -fails:The -p command line option sets $-p diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_r_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_r_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:The -r command line option requires the specified file diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_s_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_s_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -fails:The -s command line option when using -- to stop parsing sets the value to true without an explicit value -fails:The -s command line option when using -- to stop parsing parses single letter args into globals -fails:The -s command line option when using -- to stop parsing parses long args into globals -fails:The -s command line option when using -- to stop parsing converts extra dashes into underscores -fails:The -s command line option when running a script sets the value to true without an explicit value -fails:The -s command line option when running a script parses single letter args into globals -fails:The -s command line option when running a script parses long args into globals -fails:The -s command line option when running a script converts extra dashes into underscores diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_e_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_e_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:ruby -E raises a RuntimeError if used with -U diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_f_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_f_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:the -F command line option specifies the field separator pattern for -a diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_i_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_i_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:The -I command line option adds the path to the load path ($:) diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_u_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_u_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -fails:ruby -U sets Encoding.default_internal to UTF-8 -fails:ruby -U does nothing different if specified multiple times -fails:ruby -U is overruled by Encoding.default_internal= -fails:ruby -U does not affect the default external encoding -fails:ruby -U does not affect the source encoding -fails:ruby -U raises a RuntimeError if used with -Eext:int -fails:ruby -U raises a RuntimeError if used with -E:int diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_w_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_w_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -fails:The -W command line option with 0 sets $VERBOSE to nil -fails:The -W command line option with 1 sets $VERBOSE to false -fails:The -W command line option with 2 sets $VERBOSE to true diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_v_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_v_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:The -v command line option sets $VERBOSE to true diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_w_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_w_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:The -w command line option sets $VERBOSE to true diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_x_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_x_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:The -x command line option runs code after the first /#!.*ruby.*/-ish line in target file -fails:The -x command line option needs to be reviewed for spec completeness diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/command_line/error_message_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/error_message_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:The error message caused by an exception is not printed to stdout diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/BEGIN_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/BEGIN_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -fails:The BEGIN keyword runs first in a given code unit -fails:The BEGIN keyword runs multiple begins in FIFO order -fails:The BEGIN keyword runs in a shared scope -fails:The BEGIN keyword accesses variables outside the eval scope diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/alias_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/alias_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -fails:The alias keyword creates a new name for an existing method -fails:The alias keyword adds the new method to the list of methods -fails:The alias keyword adds the new method to the list of public methods -fails:The alias keyword overwrites an existing method with the target name -fails:The alias keyword is reversible -fails:The alias keyword operates on the object's metaclass when used in instance_eval -fails:The alias keyword operates on methods with splat arguments -fails:The alias keyword operates on methods with splat arguments on eigenclasses -fails:The alias keyword operates on methods with splat arguments defined in a superclass -fails:The alias keyword operates on methods with splat arguments defined in a superclass using text block for class eval -fails:The alias keyword is not allowed against Fixnum or String instances diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/array_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/array_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -fails:The unpacking splat operator (*) returns a new array containing the same values when applied to an array inside an empty array -fails:The unpacking splat operator (*) unpacks the start and count arguments in an array slice assignment -fails:Array literals [] treats splatted nil as no element -fails:The unpacking splat operator (*) when applied to a non-Array value attempts to coerce it to Array if the object respond_to?(:to_a) diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/block_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/block_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -fails:A block allows to define a block variable with the same name as the enclosing block -fails:A block taking |a| arguments assigns nil to the argument when no values are yielded -fails:A block taking |a| arguments does not call #to_ary to convert a single yielded object to an Array -fails:A block taking |a| arguments assigns the first value yielded to the argument -fails:A block taking |a, b| arguments assgins nil to the arguments when no values are yielded -fails:A block taking |a, b| arguments assigns one value yielded to the first argument -fails:A block taking |a, b| arguments destructures a splatted Array -fails:A block taking |a, b| arguments calls #to_ary to convert a single yielded object to an Array -fails:A block taking |a, b| arguments does not call #to_ary if the single yielded object is an Array -fails:A block taking |a, b| arguments does not call #to_ary if the object does not respond to #to_ary -fails:A block taking |a, b| arguments raises an TypeError if #to_ary does not return an Array -fails:A block taking |a, *b| arguments assigns 'nil' and '[]' to the arguments when no values are yielded -fails:A block taking |a, *b| arguments assigns all yielded values after the first to the rest argument -fails:A block taking |a, *b| arguments assigns 'nil' and '[]' to the arguments when a single, empty Array is yielded -fails:A block taking |a, *b| arguments assigns the element of a single element Array to the first argument -fails:A block taking |a, *b| arguments destructures a splatted Array -fails:A block taking |a, *b| arguments destructures a single Array value assigning the remaining values to the rest argument -fails:A block taking |a, *b| arguments calls #to_ary to convert a single yielded object to an Array -fails:A block taking |a, *b| arguments does not call #to_ary if the single yielded object is an Array -fails:A block taking |a, *b| arguments raises an TypeError if #to_ary does not return an Array -fails:A block taking |*| arguments does not call #to_ary if the single yielded object is an Array -fails:A block taking |*| arguments does not call #to_ary to convert a single yielded object to an Array -fails:A block taking |*a| arguments assigns all the values passed to the argument as an Array -fails:A block taking |*a| arguments assigns '[[]]' to the argument when passed an empty Array -fails:A block taking |*a| arguments assigns a single Array value passed to the argument by wrapping it in an Array -fails:A block taking |*a| arguments does not call #to_ary if the single yielded object is an Array -fails:A block taking |*a| arguments does not call #to_ary to convert a single yielded object to an Array -fails:A block taking |a, | arguments assigns nil to the argument when no values are yielded -fails:A block taking |a, | arguments assigns the argument the first value yielded -fails:A block taking |a, | arguments assigns the argument the first of several values yielded when it is an Array -fails:A block taking |a, | arguments assigns nil to the argument when passed an empty Array -fails:A block taking |a, | arguments assigns the argument the first element of the Array when passed a single Array -fails:A block taking |a, | arguments calls #to_ary to convert a single yielded object to an Array -fails:A block taking |a, | arguments does not call #to_ary if the single yielded object is an Array -fails:A block taking |a, | arguments raises an TypeError if #to_ary does not return an Array -fails:A block taking |(a, b)| arguments assigns nil to the arguments when yielded no values -fails:A block taking |(a, b)| arguments calls #to_ary to convert a single yielded object to an Array -fails:A block taking |(a, b)| arguments does not call #to_ary if the single yielded object is an Array -fails:A block taking |(a, b)| arguments does not call #to_ary if the object does not respond to #to_ary -fails:A block taking |(a, b)| arguments raises an TypeError if #to_ary does not return an Array -fails:A block taking |(a, b), c| arguments assigns nil to the arguments when yielded no values -fails:A block taking |(a, b), c| arguments destructures a single one-level Array value yielded -fails:A block taking |(a, b), c| arguments destructures a single multi-level Array value yielded -fails:A block taking |(a, b), c| arguments calls #to_ary to convert a single yielded object to an Array -fails:A block taking |(a, b), c| arguments does not call #to_ary if the single yielded object is an Array -fails:A block taking |(a, b), c| arguments does not call #to_ary if the object does not respond to #to_ary -fails:A block taking |(a, b), c| arguments raises an TypeError if #to_ary does not return an Array -fails:A block taking nested |a, (b, (c, d))| destructures a single multi-level Array value yielded -fails:A block taking nested |a, (b, (c, d))| destructures a single multi-level Array value yielded -fails:A block taking nested |a, ((b, c), d)| destructures a single multi-level Array value yielded -fails:A block taking nested |a, ((b, c), d)| destructures a single multi-level Array value yielded -fails:A block arguments with _ extracts arguments with _ -fails:Block-local variables override shadowed variables from the outer scope -fails:Post-args appear after a splat -fails:Post-args are required -fails:Post-args with required args gathers remaining args in the splat -fails:Post-args with required args has an empty splat when there are no remaining args -fails:Post-args with optional args gathers remaining args in the splat -fails:Post-args with optional args overrides the optional arg before gathering in the splat -fails:Post-args with optional args uses the required arg before the optional and the splat -fails:Post-args with optional args overrides the optional args from left to right before gathering the splat -fails:A block taking |(a, b)| arguments destructures a single Array value yielded -fails:A block taking |(a, b)| arguments destructures a single Array value yielded when shadowing an outer variable -fails:A block taking nested |a, (b, (c, d))| assigns nil to the arguments when yielded no values -fails:A block taking nested |a, (b, (c, d))| destructures separate yielded values -fails:A block taking nested |a, ((b, c), d)| assigns nil to the arguments when yielded no values -fails:A block taking nested |a, ((b, c), d)| destructures separate yielded values diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/break_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/break_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -fails:The break statement in a lambda created at the toplevel returns a value when invoking from the toplevel -fails:The break statement in a lambda created at the toplevel returns a value when invoking from a method -fails:The break statement in a lambda created at the toplevel returns a value when invoking from a block diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/case_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/case_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -fails:The 'case'-construct evaluates the body of the when clause matching the case target expression -fails:The 'case'-construct evaluates the body of the when clause whose array expression includes the case target expression -fails:The 'case'-construct evaluates the body of the when clause in left-to-right order if it's an array expression -fails:The 'case'-construct evaluates the body of the when clause whose range expression includes the case target expression -fails:The 'case'-construct expands arrays to lists of values -fails:The 'case'-construct concats arrays before expanding them -fails:The 'case'-construct never matches when clauses with no values -fails:The 'case'-construct works even if there's only one when statement -fails:The 'case'-construct with no target expression evaluates true as only 'true' when true is the first clause -fails:The 'case'-construct with no target expression evaluates false as only 'false' when false is the first clause -fails:The 'case'-construct with no target expression treats a literal array as its own when argument, rather than a list of arguments -fails:The 'case'-construct takes multiple expanded arrays diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/class_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/class_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -fails:A class definition has no class variables -fails:A class definition raises TypeError if the constant qualifying the class is nil -fails:A class definition raises TypeError if any constant qualifying the class is not a Module -fails:A class definition allows using self as the superclass if self is a class -fails:A class definition raises a TypeError if inheriting from a metaclass -fails:A class definition allows the declaration of class variables in the body -fails:A class definition stores instance variables defined in the class body in the class object -fails:A class definition allows the declaration of class variables in a class method -fails:A class definition allows the definition of class-level instance variables in a class method -fails:A class definition allows the declaration of class variables in an instance method -fails:A class definition returns the value of the last statement in the body -fails:An outer class definition contains the inner classes -fails:A class definition extending an object (sclass) raises a TypeError when trying to extend numbers -fails:A class definition extending an object (sclass) allows accessing the block of the original scope -fails:A class definition extending an object (sclass) can use return to cause the enclosing method to return -fails:Reopening a class raises a TypeError when superclasses mismatch -fails:Reopening a class adds new methods to subclasses -fails:class provides hooks calls inherited when a class is created diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/class_variable_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/class_variable_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -fails:A class variable can be accessed from a subclass -fails:A class variable is set in the superclass -fails:A class variable defined in a module can be accessed from classes that extend the module -fails:A class variable defined in a module is not defined in these classes -fails:A class variable defined in a module is only updated in the module a method defined in the module is used -fails:A class variable defined in a module is updated in the class when a Method defined in the class is used -fails:A class variable defined in a module can be accessed from modules that extend the module -fails:A class variable defined in a module is defined in the extended module -fails:A class variable defined in a module is not defined in the extending module -fails:A class variable defined in a module can be accessed inside the class using the module methods diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/constants_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/constants_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -fails:Literal (A::X) constant resolution sends #const_missing to the original class or module scope -fails:Literal (A::X) constant resolution raises a TypeError if a non-class or non-module qualifier is given -fails:Literal (A::X) constant resolution with statically assigned constants does not search the singleton class of the class or module -fails:Literal (A::X) constant resolution with dynamically assigned constants does not search the singleton class of the class or module -fails:Literal (A::X) constant resolution with dynamically assigned constants evaluates the right hand side before evaluating a constant path -fails:Constant resolution within methods sends #const_missing to the original class or module scope -fails:Constant resolution within methods with statically assigned constants searches the lexical scope of the method not the receiver's immediate class -fails:Constant resolution within methods with statically assigned constants searches the lexical scope of a singleton method -fails:Constant resolution within methods with statically assigned constants searches Object as a lexical scope only if Object is explicitly opened -fails:Constant resolution within methods with dynamically assigned constants searches the immediate class or module scope first -fails:Constant resolution within methods with dynamically assigned constants searches the superclass before a module included in the superclass -fails:Constant resolution within methods with dynamically assigned constants searches the lexical scope of the method not the receiver's immediate class -fails:Constant resolution within methods with dynamically assigned constants searches the lexical scope of a singleton method -fails:Constant resolution within methods with dynamically assigned constants does not search the lexical scope of the caller -fails:Constant resolution within methods with dynamically assigned constants searches the lexical scope of a block -fails:Constant resolution within methods with dynamically assigned constants searches Object as a lexical scope only if Object is explicitly opened -fails:Constant resolution within methods with ||= assignes constant if previously undefined -fails:Module#private_constant marked constants remain private even when updated -fails:Module#private_constant marked constants in a module cannot be accessed from outside the module -fails:Module#private_constant marked constants in a module cannot be reopened as a module -fails:Module#private_constant marked constants in a module cannot be reopened as a class -fails:Module#private_constant marked constants in a module is not defined? with A::B form -fails:Module#private_constant marked constants in a module can be accessed from lexical scope -fails:Module#private_constant marked constants in a module is defined? from lexical scope -fails:Module#private_constant marked constants in a class cannot be accessed from outside the class -fails:Module#private_constant marked constants in a class cannot be reopened as a module -fails:Module#private_constant marked constants in a class cannot be reopened as a class -fails:Module#private_constant marked constants in a class is not defined? with A::B form -fails:Module#private_constant marked constants in a class can be accessed from lexical scope -fails:Module#private_constant marked constants in Object cannot be accessed using ::Const form -fails:Module#private_constant marked constants in Object is not defined? using ::Const form -fails:Module#public_constant marked constants in a module can be accessed from outside the module -fails:Module#public_constant marked constants in a module is defined? with A::B form -fails:Module#public_constant marked constants in a class can be accessed from outside the class -fails:Module#public_constant marked constants in a class is defined? with A::B form -fails:Module#public_constant marked constants in Object can be accessed using ::Const form -fails:Module#public_constant marked constants in Object is defined? using ::Const form -fails:Module#private_constant marked constants in a class is defined? from lexical scope -fails:Literal (A::X) constant resolution with statically assigned constants searches a module included in the superclass -fails:Constant resolution within methods with statically assigned constants searches a module included in the superclass -fails:Constant resolution within methods with statically assigned constants searches the superclass chain -fails:Literal (A::X) constant resolution with statically assigned constants searches Object if no class or module qualifier is given -fails:Literal (A::X) constant resolution with statically assigned constants searches Object after searching other scopes -fails:Constant resolution within methods with statically assigned constants searches the superclass chain -fails:Literal (A::X) constant resolution with statically assigned constants searches the superclass chain diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/def_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/def_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -fails:Defining an 'initialize' method sets the method's visibility to private -fails:Defining an 'initialize_copy' method sets the method's visibility to private -fails:An instance method with a default argument assigns an empty Array to an unused splat argument -fails:An instance method with a default argument prefers to assign to a default argument when there are no required arguments -fails:An instance method with a default argument does not evaluate the default when passed a value and a * argument -fails:A singleton method definition raises RuntimeError if frozen -fails:Redefining a singleton method does not inherit a previously set visibility -fails:Redefining a singleton method does not inherit a previously set visibility -fails:A method defined with extreme default arguments may use an fcall as a default -fails:A method defined with extreme default arguments may use preceding arguments as defaults -fails:A method defined with extreme default arguments may use a lambda as a default -fails:A singleton method defined with extreme default arguments may use an fcall as a default -fails:A singleton method defined with extreme default arguments may use preceding arguments as defaults -fails:A singleton method defined with extreme default arguments may use a lambda as a default -fails:A method definition inside a metaclass scope can create a class method -fails:A method definition inside a metaclass scope can create a singleton method -fails:A method definition inside a metaclass scope raises RuntimeError if frozen -fails:A nested method definition creates an instance method when evaluated in an instance method -fails:A nested method definition creates a class method when evaluated in a class method -fails:A nested method definition creates a singleton method when evaluated in the metaclass of an instance -fails:A method definition inside an instance_eval creates a singleton method -fails:A method definition inside an instance_eval creates a singleton method when evaluated inside a metaclass -fails:A method definition inside an instance_eval creates a class method when the receiver is a class -fails:A method definition in an eval creates an instance method -fails:A method definition in an eval creates a class method -fails:A method definition in an eval creates a singleton method -fails:a method definition that sets more than one default parameter all to the same value assigns them all the same object by default -fails:The def keyword within a closure looks outside the closure for the visibility diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/defined_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/defined_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -fails:The defined? keyword when called with a method name having a module as receiver returns nil if the method is private -fails:The defined? keyword when called with a method name having a module as receiver returns nil if the method is protected -fails:The defined? keyword when called with a method name having a local variable as receiver calls #respond_to_missing? -fails:The defined? keyword for an expression returns nil for an expression with !~ and an undefined method -fails:The defined? keyword for an expression returns 'method' for an expression with '!~' -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset class variable -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset class variable -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset global variable -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset instance variable -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset global variable -fails:The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset instance variable -fails:The defined? keyword for variables returns nil for a global variable that has not been read -fails:The defined? keyword for variables returns nil for a global variable that has been read but not assigned to -fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $& -fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $` -fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $' -fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $+ -fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $& -fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $` -fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $' -fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $+ -fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for the capture references -fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $& -fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $` -fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $' -fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $+ -fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $& -fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $` -fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $' -fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $+ -fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for the capture references -fails:The defined? keyword for a scoped constant returns nil when an undefined constant is scoped to a defined constant -fails:The defined? keyword for a top-level scoped constant returns nil when an undefined constant is scoped to a defined constant -fails:The defined? keyword for super returns nil when a superclass undef's the method -fails:The defined? keyword for super for a method taking no arguments returns 'super' from a block when a superclass method exists -fails:The defined? keyword for super for a method taking no arguments returns 'super' from a #define_method when a superclass method exists -fails:The defined? keyword for super for a method taking no arguments returns 'super' from a block in a #define_method when a superclass method exists -fails:The defined? keyword for super for a method taking no arguments returns 'super' when the method exists in a supermodule -fails:The defined? keyword for super for a method taking arguments returns 'super' when a superclass method exists -fails:The defined? keyword for super for a method taking arguments returns 'super' from a block when a superclass method exists -fails:The defined? keyword for super for a method taking arguments returns 'super' from a #define_method when a superclass method exists -fails:The defined? keyword for super for a method taking arguments returns 'super' from a block in a #define_method when a superclass method exists -fails:The defined? keyword for super within an included module's method returns 'super' when a superclass method exists in the including hierarchy -fails:The defined? keyword for instance variables returns nil if not assigned -fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $1-$9 -fails:The defined? keyword for variables when a String matches a Regexp returns nil for non-captures -fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $1-$9 -fails:The defined? keyword for variables when a Regexp matches a String returns nil for non-captures diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/encoding_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/encoding_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -fails:The __ENCODING__ pseudo-variable is an instance of Encoding -fails:The __ENCODING__ pseudo-variable is US-ASCII by default -fails:The __ENCODING__ pseudo-variable is the evaluated strings's one inside an eval -fails:The __ENCODING__ pseudo-variable is the encoding specified by a magic comment inside an eval -fails:The __ENCODING__ pseudo-variable is the encoding specified by a magic comment in the file -fails:The __ENCODING__ pseudo-variable is Encoding::ASCII_8BIT when the interpreter is invoked with -Ka -fails:The __ENCODING__ pseudo-variable is Encoding::ASCII_8BIT when the interpreter is invoked with -KA -fails:The __ENCODING__ pseudo-variable is Encoding::EUC_JP when the interpreter is invoked with -Ke -fails:The __ENCODING__ pseudo-variable is Encoding::EUC_JP when the interpreter is invoked with -KE -fails:The __ENCODING__ pseudo-variable is Encoding::UTF_8 when the interpreter is invoked with -Ku -fails:The __ENCODING__ pseudo-variable is Encoding::UTF_8 when the interpreter is invoked with -KU -fails:The __ENCODING__ pseudo-variable is Encoding::Windows_31J when the interpreter is invoked with -Ks -fails:The __ENCODING__ pseudo-variable is Encoding::Windows_31J when the interpreter is invoked with -KS -fails:The __ENCODING__ pseudo-variable raises a SyntaxError if assigned to diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/ensure_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/ensure_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:An ensure block inside a begin block is executed when an exception is raised in it's corresponding begin block -fails:An ensure block inside a method is executed when an exception is raised in the method diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/execution_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/execution_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:`` returns the output of the executed sub-process -fails:%x is the same as `` diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/file_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/file_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -fails:The __FILE__ pseudo-variable equals (eval) inside an eval -fails:The __FILE__ pseudo-variable equals the absolute path of a file loaded by an absolute path -fails:The __FILE__ pseudo-variable equals the absolute path of a file loaded by a relative path diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/for_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/for_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -fails:The for expression iterates over an Hash passing each key-value pair to the block -fails:The for expression allows a class variable as an iterator name -fails:The for expression yields only as many values as there are arguments -fails:The for expression executes code in containing variable scope -fails:The for expression executes code in containing variable scope with 'do' -fails:The for expression returns expr diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/hash_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/hash_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:Hash literal freezes string keys on initialization diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/line_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/line_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:The __LINE__ pseudo-variable equals the line number of the text in a loaded file diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/literal_lambda_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/literal_lambda_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -fails:->(){} assigns the given block to the parameter prefixed with an ampersand if such a parameter exists -fails:->(){} sets parameters appropriately when a combination of parameter types is given between the parenthesis -fails:->(){} uses lambda's 'rigid' argument handling -fails:->(){} evaluates constants as normal blocks do diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/magic_comment_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/magic_comment_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -fails:Magic comment is optional -fails:Magic comment determines __ENCODING__ -fails:Magic comment is case-insensitive -fails:Magic comment must be at the first line -fails:Magic comment must be the first token of the line -fails:Magic comment can be after the shebang -fails:Magic comment can take Emacs style -fails:Magic comment can take vim style diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/match_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/match_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:The !~ operator evaluates as a call to !~ -fails:The =~ operator calls the =~ method diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/metaclass_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/metaclass_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -fails:self in a metaclass body (class << obj) is TrueClass for true -fails:self in a metaclass body (class << obj) is FalseClass for false -fails:self in a metaclass body (class << obj) is NilClass for nil -fails:self in a metaclass body (class << obj) raises a TypeError for numbers -fails:self in a metaclass body (class << obj) raises a TypeError for symbols -fails:self in a metaclass body (class << obj) is a singleton Class instance -fails:A constant on a metaclass can be accessed via const_get -fails:A constant on a metaclass cannot be accessed via object::CONST -fails:A constant on a metaclass raises a NameError for anonymous_module::CONST -fails:A constant on a metaclass appears in the metaclass constant list -fails:A constant on a metaclass does not appear in the object's class constant list -fails:A constant on a metaclass is not preserved when the object is duped -fails:A constant on a metaclass is preserved when the object is cloned -fails:calling methods on the metaclass calls a method on the instance's metaclass -fails:calling methods on the metaclass calls a method in deeper chains of metaclasses -fails:calling methods on the metaclass calls a method defined on the metaclass of the metaclass diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/module_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/module_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -fails:The module keyword reopens a module included in Object -fails:The module keyword raises a TypeError if the constant is a Class -fails:The module keyword raises a TypeError if the constant is a String -fails:The module keyword raises a TypeError if the constant is a Fixnum -fails:The module keyword raises a TypeError if the constant is nil -fails:The module keyword raises a TypeError if the constant is true -fails:The module keyword raises a TypeError if the constant is false diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/next_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/next_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -fails:The next statement from within the block returns the argument passed -fails:The next statement from within the block returns to the invoking method, with the specified value -fails:The next statement from within the block returns to the currently yielding method in case of chained calls -fails:Assignment via next assigns objects -fails:Assignment via next assigns splatted objects -fails:Assignment via next assigns objects to a splatted reference -fails:Assignment via next assigns splatted objects to a splatted reference via a splatted yield -fails:Assignment via next assigns objects to multiple variables -fails:Assignment via next assigns splatted objects to multiple variables diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/precedence_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/precedence_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:Operators + - have higher precedence than >> << -fails:Operators + - are left-associative diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined/data_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined/data_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -fails:The DATA constant exists when the main script contains __END__ -fails:The DATA constant does not exist when the main script contains no __END__ -fails:The DATA constant does not exist when an included file has a __END__ -fails:The DATA constant does not change when an included files also has a __END__ -fails:The DATA constant is included in an otherwise empty file -fails:The DATA constant succeeds in locking the file DATA came from diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -fails:Predefined global $~ is set to contain the MatchData object of the last match if successful -fails:Predefined global $~ is set to nil if the last match was unsuccessful -fails:Predefined global $~ is set at the method-scoped level rather than block-scoped -fails:Predefined global $~ raises an error if assigned an object not nil or instanceof MatchData -fails:Predefined global $~ changes the value of derived capture globals when assigned -fails:Predefined global $~ changes the value of the derived preceding match global -fails:Predefined global $~ changes the value of the derived following match global -fails:Predefined global $~ changes the value of the derived full match global -fails:Predefined global $& is equivalent to MatchData#[0] on the last match $~ -fails:Predefined global $& sets the encoding to the encoding of the source String -fails:Predefined global $` is equivalent to MatchData#pre_match on the last match $~ -fails:Predefined global $` sets the encoding to the encoding of the source String -fails:Predefined global $` sets an empty result to the encoding of the source String -fails:Predefined global $' is equivalent to MatchData#post_match on the last match $~ -fails:Predefined global $' sets the encoding to the encoding of the source String -fails:Predefined global $' sets an empty result to the encoding of the source String -fails:Predefined global $+ is equivalent to $~.captures.last -fails:Predefined global $+ captures the last non nil capture -fails:Predefined global $+ sets the encoding to the encoding of the source String -fails:Predefined globals $1..N are equivalent to $~[N] -fails:Predefined globals $1..N are nil unless a match group occurs -fails:Predefined globals $1..N sets the encoding to the encoding of the source String -fails:Predefined global $stdout is the same as $DEFAULT_OUTPUT from 'English' library -fails:Predefined global $stdout raises TypeError error if assigned to nil -fails:Predefined global $stdout raises TypeError error if assigned to object that doesn't respond to #write -fails:Predefined global $! remains nil after a failed core class "checked" coercion against a class that defines method_missing -fails:Predefined global $/ changes $-0 -fails:Predefined global $/ does not call #to_str to convert the object to a String -fails:Predefined global $/ raises a TypeError if assigned a Fixnum -fails:Predefined global $/ raises a TypeError if assigned a boolean -fails:Predefined global $-0 changes $/ -fails:Predefined global $-0 does not call #to_str to convert the object to a String -fails:Predefined global $-0 raises a TypeError if assigned a Fixnum -fails:Predefined global $-0 raises a TypeError if assigned a boolean -fails:Predefined global $, raises TypeError if assigned a non-String -fails:Predefined global $_ is set to the last line read by e.g. StringIO#gets -fails:Predefined global $_ is set at the method-scoped level rather than block-scoped -fails:Predefined global $_ is Thread-local -fails:Execution variable $: does not include '.' when the taint check level > 1 -fails:Execution variable $: is the same object as $LOAD_PATH and $-I -fails:Execution variable $: is read-only -fails:Global variable $" is read-only -fails:Global variable $< is read-only -fails:Global variable $FILENAME is read-only -fails:Global variable $? is read-only -fails:Global variable $? is thread-local -fails:Global variable $-a is read-only -fails:Global variable $-l is read-only -fails:Global variable $-p is read-only -fails:Global variable $-d is an alias of $DEBUG -fails:Global variable $-v is an alias of $VERBOSE -fails:Global variable $-w is an alias of $VERBOSE -fails:Global variable $0 raises a TypeError when not given an object that can be coerced to a String -fails:The predefined standard objects includes ARGF -fails:The predefined global constants includes TRUE -fails:The predefined global constants includes FALSE -fails:The predefined global constants includes NIL -fails:The predefined global constants includes STDIN -fails:The predefined global constants includes STDOUT -fails:The predefined global constants includes STDERR -fails:The predefined global constants includes RUBY_RELEASE_DATE -fails:The predefined global constants includes TOPLEVEL_BINDING -fails:Processing RUBYOPT adds the -I path to $LOAD_PATH -fails:Processing RUBYOPT sets $DEBUG to true for '-d' -fails:Processing RUBYOPT prints the version number for '-v' -fails:Processing RUBYOPT sets $VERBOSE to true for '-w' -fails:Processing RUBYOPT sets $VERBOSE to true for '-W' -fails:Processing RUBYOPT sets $VERBOSE to nil for '-W0' -fails:Processing RUBYOPT sets $VERBOSE to false for '-W1' -fails:Processing RUBYOPT sets $VERBOSE to true for '-W2' -fails:Processing RUBYOPT requires the file for '-r' -fails:Processing RUBYOPT raises a RuntimeError for '-a' -fails:Processing RUBYOPT raises a RuntimeError for '-p' -fails:Processing RUBYOPT raises a RuntimeError for '-n' -fails:Processing RUBYOPT raises a RuntimeError for '-y' -fails:Processing RUBYOPT raises a RuntimeError for '-c' -fails:Processing RUBYOPT raises a RuntimeError for '-s' -fails:Processing RUBYOPT raises a RuntimeError for '-h' -fails:Processing RUBYOPT raises a RuntimeError for '--help' -fails:Processing RUBYOPT raises a RuntimeError for '-l' -fails:Processing RUBYOPT raises a RuntimeError for '-S' -fails:Processing RUBYOPT raises a RuntimeError for '-e' -fails:Processing RUBYOPT raises a RuntimeError for '-i' -fails:Processing RUBYOPT raises a RuntimeError for '-x' -fails:Processing RUBYOPT raises a RuntimeError for '-C' -fails:Processing RUBYOPT raises a RuntimeError for '-X' -fails:Processing RUBYOPT raises a RuntimeError for '-F' -fails:Processing RUBYOPT raises a RuntimeError for '-0' -fails:Processing RUBYOPT raises a RuntimeError for '--copyright' -fails:Processing RUBYOPT raises a RuntimeError for '--version' -fails:Processing RUBYOPT raises a RuntimeError for '--yydebug' -fails:The predefined global constant STDERR has nil for the external encoding despite Encoding.default_external being changed -fails:The predefined global constant STDERR has the encodings set by #set_encoding -fails:The predefined global constant ARGV contains Strings encoded in locale Encoding -fails:The predefined global constant STDERR has nil for the internal encoding despite Encoding.default_internal being changed -fails:The predefined global constant STDERR has nil for the internal encoding -fails:The predefined global constant STDERR has nil for the external encoding -fails:The predefined global constant STDOUT has nil for the internal encoding despite Encoding.default_internal being changed -fails:The predefined global constant STDOUT has nil for the internal encoding -fails:The predefined global constant STDOUT has the encodings set by #set_encoding -fails:The predefined global constant STDOUT has nil for the external encoding despite Encoding.default_external being changed -fails:The predefined global constant STDOUT has nil for the external encoding -fails:The predefined global constant STDIN has nil for the internal encoding despite Encoding.default_internal being changed -fails:The predefined global constant STDIN has nil for the internal encoding -fails:The predefined global constant STDIN retains the encoding set by #set_encoding when Encoding.default_external is changed -fails:The predefined global constant STDIN has the encodings set by #set_encoding -fails:The predefined global constant STDIN has the same external encoding as Encoding.default_external when that encoding is changed -fails:The predefined global constant STDIN has the same external encoding as Encoding.default_external diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/private_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/private_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:The private keyword is overridden when a new class is opened diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/proc_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/proc_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -fails:A Proc taking zero arguments raises an ArgumentErro if a value is passed -fails:A Proc taking || arguments raises an ArgumentError if a value is passed -fails:A Proc taking |a| arguments does not call #to_ary to convert a single passed object to an Array -fails:A Proc taking |a| arguments raises an ArgumentError if no value is passed -fails:A Proc taking |a, b| arguments raises an ArgumentError if passed no values -fails:A Proc taking |a, b| arguments raises an ArgumentError if passed one value -fails:A Proc taking |a, b| arguments does not call #to_ary to convert a single passed object to an Array -fails:A Proc taking |a, *b| arguments raises an ArgumentError if passed no values -fails:A Proc taking |a, *b| arguments does not call #to_ary to convert a single passed object to an Array -fails:A Proc taking |*| arguments does not call #to_ary to convert a single passed object to an Array -fails:A Proc taking |*a| arguments does not call #to_ary to convert a single passed object to an Array -fails:A Proc taking |a, | arguments raises an ArgumentError when passed no values -fails:A Proc taking |a, | arguments raises an ArgumentError when passed more than one value -fails:A Proc taking |a, | arguments does not call #to_ary to convert a single passed object to an Array -fails:A Proc taking |(a, b)| arguments raises an ArgumentError when passed no values -fails:A Proc taking |(a, b)| arguments calls #to_ary to convert a single passed object to an Array -fails:A Proc taking |(a, b)| arguments raises an TypeError if #to_ary does not return an Array -fails:A Proc taking |(a, b)| arguments destructures a single Array value yielded diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/redo_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/redo_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -fails:The redo statement restarts block execution if used within block -fails:The redo statement re-executes the closest loop -fails:The redo statement re-executes the last step in enumeration diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/anchors_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/anchors_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:Regexps with anchors supports B (non-word-boundary) diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/back-references_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/back-references_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -fails:Regexps with back-references saves match data in the $~ pseudo-global variable -fails:Regexps with back-references saves captures in numbered $[1-9] variables -fails:Regexps with back-references will not clobber capture variables across threads -fails:Regexps with back-references resets nested backreference before match of outer subexpression diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/character_classes_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/character_classes_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -fails:Regexp with character classes supports [] (character class) -fails:Regexp with character classes supports [[:alpha:][:digit:][:etc:]] (predefined character classes) -fails:Regexp with character classes matches ASCII characters with [[:ascii:]] -fails:Regexp with character classes matches Unicode letter characters with [[:alnum:]] -fails:Regexp with character classes matches Unicode digits with [[:alnum:]] -fails:Regexp with character classes doesn't match Unicode control characters with [[:alnum:]] -fails:Regexp with character classes doesn't match Unicode punctuation characters with [[:alnum:]] -fails:Regexp with character classes matches Unicode letter characters with [[:alpha:]] -fails:Regexp with character classes doesn't match Unicode digits with [[:alpha:]] -fails:Regexp with character classes doesn't match Unicode control characters with [[:alpha:]] -fails:Regexp with character classes doesn't match Unicode punctuation characters with [[:alpha:]] -fails:Regexp with character classes matches Unicode space characters with [[:blank:]] -fails:Regexp with character classes matches Unicode control characters with [[:cntrl:]] -fails:Regexp with character classes matches Unicode digits with [[:digit:]] -fails:Regexp with character classes matches Unicode letter characters with [[:graph:]] -fails:Regexp with character classes matches Unicode digits with [[:graph:]] -fails:Regexp with character classes matches Unicode marks with [[:graph:]] -fails:Regexp with character classes matches Unicode punctuation characters with [[:graph:]] -fails:Regexp with character classes match Unicode format characters with [[:graph:]] -fails:Regexp with character classes match Unicode private-use characters with [[:graph:]] -fails:Regexp with character classes matches Unicode lowercase letter characters with [[:lower:]] -fails:Regexp with character classes matches Unicode lowercase letter characters with [[:print:]] -fails:Regexp with character classes matches Unicode uppercase letter characters with [[:print:]] -fails:Regexp with character classes matches Unicode title-case characters with [[:print:]] -fails:Regexp with character classes matches Unicode digits with [[:print:]] -fails:Regexp with character classes matches Unicode marks with [[:print:]] -fails:Regexp with character classes matches Unicode punctuation characters with [[:print:]] -fails:Regexp with character classes match Unicode format characters with [[:print:]] -fails:Regexp with character classes match Unicode private-use characters with [[:print:]] -fails:Regexp with character classes matches Unicode Pc characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Pd characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Ps characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Pe characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Pi characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Pf characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Pf characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Po characters with [[:punct:]] -fails:Regexp with character classes matches Unicode Zs characters with [[:space:]] -fails:Regexp with character classes matches Unicode Zl characters with [[:space:]] -fails:Regexp with character classes matches Unicode Zp characters with [[:space:]] -fails:Regexp with character classes matches Unicode uppercase characters with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode letter characters [^a-fA-F] with [[:xdigit:]] -fails:Regexp with character classes matches Unicode letter characters [a-fA-F] with [[:xdigit:]] -fails:Regexp with character classes matches Unicode lowercase characters with [[:word:]] -fails:Regexp with character classes matches Unicode uppercase characters with [[:word:]] -fails:Regexp with character classes matches Unicode title-case characters with [[:word:]] -fails:Regexp with character classes matches Unicode decimal digits with [[:word:]] -fails:Regexp with character classes matches Unicode marks with [[:word:]] -fails:Regexp with character classes match Unicode Nl characters with [[:word:]] -fails:Regexps with anchors supports ^ (line start anchor) -fails:Regexp with character classes doesn't matches Unicode marks with [[:alnum:]] -fails:Regexp with character classes doesn't match Unicode lowercase letter characters with [[:punct:]] -fails:Regexp with character classes doesn't match Unicode uppercase letter characters with [[:punct:]] -fails:Regexp with character classes doesn't match Unicode title-case characters with [[:punct:]] -fails:Regexp with character classes doesn't match Unicode digits with [[:punct:]] -fails:Regexp with character classes doesn't match Unicode marks with [[:punct:]] -fails:Regexp with character classes doesn't match Unicode format characters with [[:punct:]] -fails:Regexp with character classes doesn't match Unicode private-use characters with [[:punct:]] -fails:Regexp with character classes doesn't match Unicode lowercase characters with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode title-case characters with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode digits with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode marks with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode punctuation characters with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode control characters with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode format characters with [[:upper:]] -fails:Regexp with character classes doesn't match Unicode private-use characters with [[:upper:]] -fails:Regexps with escape characters support \x (hex characters) -fails:Regexps with escape characters support \c (control characters) diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/encoding_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/encoding_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -fails:Regexps with encoding modifiers supports /e (EUC encoding) -fails:Regexps with encoding modifiers supports /e (EUC encoding) with interpolation -fails:Regexps with encoding modifiers supports /e (EUC encoding) with interpolation /o -fails:Regexps with encoding modifiers uses EUC-JP as /e encoding -fails:Regexps with encoding modifiers preserves EUC-JP as /e encoding through interpolation -fails:Regexps with encoding modifiers supports /n (No encoding) -fails:Regexps with encoding modifiers supports /n (No encoding) with interpolation -fails:Regexps with encoding modifiers supports /n (No encoding) with interpolation /o -fails:Regexps with encoding modifiers uses US-ASCII as /n encoding if all chars are 7-bit -fails:Regexps with encoding modifiers uses ASCII-8BIT as /n encoding if not all chars are 7-bit -fails:Regexps with encoding modifiers preserves US-ASCII as /n encoding through interpolation if all chars are 7-bit -fails:Regexps with encoding modifiers preserves ASCII-8BIT as /n encoding through interpolation if all chars are 7-bit -fails:Regexps with encoding modifiers supports /s (Windows_31J encoding) -fails:Regexps with encoding modifiers supports /s (Windows_31J encoding) with interpolation -fails:Regexps with encoding modifiers supports /s (Windows_31J encoding) with interpolation and /o -fails:Regexps with encoding modifiers uses Windows-31J as /s encoding -fails:Regexps with encoding modifiers preserves Windows-31J as /s encoding through interpolation -fails:Regexps with encoding modifiers supports /u (UTF8 encoding) -fails:Regexps with encoding modifiers supports /u (UTF8 encoding) with interpolation -fails:Regexps with encoding modifiers supports /u (UTF8 encoding) with interpolation and /o -fails:Regexps with encoding modifiers uses UTF-8 as /u encoding -fails:Regexps with encoding modifiers preserves UTF-8 as /u encoding through interpolation -fails:Regexps with encoding modifiers selects last of multiple encoding specifiers diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/escapes_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/escapes_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -fails:Regexps with escape characters support \x (hex characters) -fails:Regexps with escape characters support \c (control characters) diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/grouping_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/grouping_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:Regexps with grouping raise a SyntaxError when parentheses aren't balanced diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/interpolation_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/interpolation_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -fails:Regexps with interpolation allows interpolation of literal regexps -fails:Regexps with interpolation allows interpolation of any class that responds to to_s -fails:Regexps with interpolation allows interpolation which mixes modifiers -fails:Regexps with interpolation gives precedence to escape sequences over substitution -fails:Regexps with interpolation throws RegexpError for malformed interpolation -fails:Regexps with interpolation allows interpolation in extended mode -fails:Regexps with interpolation allows escape sequences in interpolated regexps diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/modifiers_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/modifiers_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -fails:Regexps with modifers supports /m (multiline) -fails:Regexps with modifers supports /x (extended syntax) -fails:Regexps with modifers supports /o (once) -fails:Regexps with modifers invokes substitutions for /o only once -fails:Regexps with modifers supports (?imx-imx) (inline modifiers) -fails:Regexps with modifers supports (?imx-imx:expr) (scoped inline modifiers) -fails:Regexps with modifers supports . with /m -fails:Regexps with modifers supports ASII/Unicode modifiers -fails:Regexps with modifers raises SyntaxError for ASII/Unicode modifiers diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/repetition_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/repetition_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -fails:Regexps with repetition does not treat {m,n}+ as possessive diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp_tags.txt --- a/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp_tags.txt Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -fails:Literal Regexps matches against $_ (last input) in a conditional if no explicit matchee provided -fails:Literal Regexps throws SyntaxError for malformed literals -fails:Literal Regexps supports paired delimiters with %r -fails:Literal Regexps supports grouping constructs that are also paired delimiters -fails:Literal Regexps allows second part of paired delimiters to be used as non-paired delimiters -fails:Literal Regexps supports non-paired delimiters delimiters with %r -fails:Literal Regexps allows unescaped / to be used with %r -fails:Literal Regexps supports . (any character except line terminator) -fails:Literal Regexps supports | (alternations) -fails:Literal Regexps supports (?> ) (embedded subexpression) -fails:Literal Regexps supports (?# ) -fails:Literal Regexps supports (?<= ) (positive lookbehind) -fails:Literal Regexps supports (? 2 }; puts bar.to_s"); - } - - @Test - public void testInclude() { - assertPrints("true\nfalse\n", "foo = [1, 2, 3, 4]; puts foo.include? 2; puts foo.include? 5"); - } - - @Test - public void testSub() { - assertPrints("[1, 4]\n", "puts ([1, 2, 2, 3, 4] - [2, 3]).to_s"); - } - - @Test - public void testJoin() { - assertPrints("1.2.3\n", "puts [1, 2, 3].join('.')"); - } - - @Test - public void testShift() { - assertPrints("1\n2\n3\n", "a = [1, 2, 3]; while b = a.shift; puts b; end"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BignumTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BignumTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Bignum} class. - */ -public class BignumTests extends RubyTests { - - @Test - public void testImmediate() { - assertPrints("123456789123456789\n", "puts 123456789123456789"); - assertPrints("574658776654483828\n", "puts 574658776654483828"); - } - - @Test - public void testAddImmediate() { - assertPrints("821572354901397406\n", "puts 123456789123456789+698115565777940617"); - assertPrints("7675735362615108\n", "puts 867676857675 + 7674867685757433"); - assertPrints("8792416214481\n", "puts 8785647643454 + (6768571027)"); - assertPrints("8089240320234\n", "puts (7132953783486) + ((956286536748))"); - } - - @Test - public void testSubImmediate() { - assertPrints("574658776654483828\n", "puts 698115565777940617-123456789123456789"); - assertPrints("7674000008899758\n", "puts 7674867685757433 - 867676857675"); - assertPrints("8778879072427\n", "puts 8785647643454 - (6768571027)"); - assertPrints("6176667246738\n", "puts (7132953783486) - ((956286536748))"); - } - - @Test - public void testLessImmediate() { - assertPrints("false\n", "puts 698115565777940617 < 123456789123456789"); - assertPrints("true\n", "puts 867676857675 < 7674867685757433"); - assertPrints("false\n", "puts 8785647643454 < (6768571027)"); - assertPrints("true\n", "puts (956286536748) < ((7132953783486))"); - } - - @Test - public void testDivmod() { - assertPrints("100\n2342\n", "puts 1000000000000000000000002342.divmod(10000000000000000000000000)"); - assertPrints("Fixnum\n", "puts 1000000000000000000000002342.divmod(10000000000000000000000000)[0].class"); - assertPrints("Fixnum\n", "puts 1000000000000000000000002342.divmod(10000000000000000000000000)[1].class"); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BoolTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BoolTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code true} and {@code false}. Note that there is no {@code Bool} class or type. There is - * {@code TrueClass}, {@code FalseClass}, and instances of them {@code true} and {@code false}. - */ -public class BoolTests extends RubyTests { - - @Test - public void testImmediate() { - assertPrints("true\n", "puts true"); - assertPrints("false\n", "puts false"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ContinuationTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ContinuationTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Continuation} class. - */ -public class ContinuationTests extends RubyTests { - - @Test - public void testRequired() { - assertPrints("", "callcc { |c| c.call }"); - } - - @Test - public void testOneShotGoingUpCallstack() { - assertPrints("1\n3\n", "callcc { |c| puts 1; c.call; puts 2 }; puts 3"); - } - - @Test - public void testOneShotGoingUpCallstackReturnValue() { - assertPrints("14\n", "puts callcc { |c| c.call 14 }"); - } - - @Test - public void testNestedOneShotGoingUpCallstack() { - assertPrints("1\n2\n4\n5\n", "callcc { |c1| puts 1; callcc { |c2| puts 2; c2.call; puts 3 }; puts 4 }; puts 5"); - assertPrints("1\n2\n5\n", "callcc { |c1| puts 1; callcc { |c2| puts 2; c1.call; puts 3 }; puts 4 }; puts 5"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FiberTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FiberTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Fiber} class. - */ -public class FiberTests extends RubyTests { - - @Test - public void testResume() { - assertPrints("14\n", "f = Fiber.new { |x| puts x }; f.resume 14"); - } - - @Test - public void testYield() { - assertPrints("14\n", "f = Fiber.new { |x| Fiber.yield x }; puts f.resume(14)"); - } - - @Test - public void testCountdown() { - assertPrints("", "f = Fiber.new do |n|\n" + // - " loop do\n" + // - " n = Fiber.yield n - 1\n" + // - " end\n" + // - "end\n" + // - "\n" + // - "n = 1000\n" + // - "\n" + // - "while n > 0\n" + // - " n = f.resume n\n" + // - "end\n"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FixnumTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FixnumTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Fixnum} class. - */ -public class FixnumTests extends RubyTests { - - @Test - public void testImmediate() { - assertPrints("2\n", "puts 2"); - assertPrints("14\n", "puts 14"); - assertPrints("-14\n", "puts -14"); - } - - @Test - public void testNegate() { - assertPrints("-1\n", "x = 1; puts -x"); - assertPrints("1\n", "x = -1; puts -x"); - } - - @Test - public void testAddImmediate() { - assertPrints("16\n", "puts 14+2"); - assertPrints("14\n", "puts 12 + 2"); - assertPrints("17\n", "puts 9 + (8)"); - assertPrints("10\n", "puts (6) + ((4))"); - } - - @Test - public void testSubImmediate() { - assertPrints("12\n", "puts 14-2"); - assertPrints("10\n", "puts 12 - 2"); - assertPrints("1\n", "puts 9 - (8)"); - assertPrints("2\n", "puts (6) - ((4))"); - } - - @Test - public void testMulImmediate() { - assertPrints("28\n", "puts 14 * 2"); - assertPrints("20\n", "puts 2 * 10"); - assertPrints("72\n", "puts 9 * (8)"); - assertPrints("24\n", "puts (4) * ((6))"); - } - - @Test - public void testDivImmediate() { - assertPrints("7\n", "puts 14 / 2"); - assertPrints("0\n", "puts 2 / 10"); - assertPrints("1\n", "puts 9 / (8)"); - assertPrints("0\n", "puts (4) / ((6))"); - } - - @Test - public void testEqualImmediate() { - assertPrints("true\n", "puts 14 == 14"); - assertPrints("true\n", "puts 2 == 2"); - assertPrints("false\n", "puts 9 == (8)"); - assertPrints("false\n", "puts (4) == ((6))"); - } - - @Test - public void testNotEqualImmediate() { - assertPrints("false\n", "puts 14 != 14"); - assertPrints("false\n", "puts 2 != 2"); - assertPrints("true\n", "puts 9 != (8)"); - assertPrints("true\n", "puts (4) != ((6))"); - } - - @Test - public void testLessImmediate() { - assertPrints("false\n", "puts 14 < 2"); - assertPrints("true\n", "puts 2 < 10"); - assertPrints("false\n", "puts 9 < (8)"); - assertPrints("true\n", "puts (4) < ((6))"); - } - - @Test - public void testGreaterEqualImmediate() { - assertPrints("true\n", "puts 14 >= 14"); - assertPrints("true\n", "puts 14 >= 2"); - assertPrints("false\n", "puts 2 >= 10"); - assertPrints("true\n", "puts 9 >= (8)"); - assertPrints("false\n", "puts (4) >= ((6))"); - } - - @Test - public void testLeftShift() { - assertPrints("0\n", "puts 0 << 0"); - assertPrints("0\n", "puts 0 << 1"); - assertPrints("1\n", "puts 1 << 0"); - assertPrints("0\n", "puts 1 << -1"); - assertPrints("0\n", "puts 1 << -2"); - assertPrints("28\n", "puts 14 << 1"); - assertPrints("7\n", "puts 14 << -1"); - assertPrints("4294967296\n", "puts 1 << 32"); - assertPrints("340282366920938463463374607431768211456\n", "puts 1 << 128"); - assertPrints("0\n", "puts 1 << -32"); - assertPrints("Fixnum\n", "puts (14 << 1).class"); - assertPrints("Bignum\n", "puts (1 << 32).class"); - } - - @Test - public void testDivmod() { - // @formatter:off - final int[][] tests = new int[][]{ - new int[]{13, 4, 3, 1}, - new int[]{13, -4, -4, -3}, - new int[]{-13, 4, -4, 3}, - new int[]{-13, -4, 3, -1}}; - // @formatter:on - - for (int[] test : tests) { - final int a = test[0]; - final int b = test[1]; - final int q = test[2]; - final int r = test[3]; - assertPrints(String.format("%d\n%d\n", q, r), String.format("puts %d.divmod(%d)", a, b)); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FloatTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FloatTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Float} class. - */ -public class FloatTests extends RubyTests { - - @Test - public void testImmediate() { - assertPrints("2.5\n", "puts 2.5"); - assertPrints("14.33\n", "puts 14.33"); - } - - @Test - public void testAddImmediate() { - assertPrints("16.2\n", "puts 14.1+2.1"); - assertPrints("14.2\n", "puts 12.1 + 2.1"); - assertPrints("17.2\n", "puts 9.1 + (8.1)"); - assertPrints("10.2\n", "puts (6.1) + ((4.1))"); - } - - @Test - public void testSubImmediate() { - assertPrints("12.1\n", "puts 14.2-2.1"); - assertPrints("10.1\n", "puts 12.2 - 2.1"); - assertPrints("1.0999999999999996\n", "puts 9.2 - (8.1)"); - assertPrints("2.1000000000000005\n", "puts (6.2) - ((4.1))"); - } - - @Test - public void testMulImmediate() { - assertPrints("29.82\n", "puts 14.2*2.1"); - assertPrints("25.62\n", "puts 12.2 * 2.1"); - assertPrints("74.52\n", "puts 9.2 * (8.1)"); - assertPrints("25.419999999999998\n", "puts (6.2) * ((4.1))"); - assertPrints("7.5\n", "puts 2.5 * 3"); - assertPrints("7.5\n", "puts 3 * 2.5"); - } - - @Test - public void testDivImmediate() { - assertPrints("6.761904761904761\n", "puts 14.2/2.1"); - assertPrints("5.809523809523809\n", "puts 12.2 / 2.1"); - assertPrints("1.1358024691358024\n", "puts 9.2 / (8.1)"); - assertPrints("1.5121951219512197\n", "puts (6.2) / ((4.1))"); - assertPrints("0.8333333333333334\n", "puts 2.5 / 3"); - assertPrints("1.2\n", "puts 3 / 2.5"); - } - - @Test - public void testLessImmediate() { - assertPrints("false\n", "puts 14.2<2.2"); - assertPrints("true\n", "puts 2.2 < 10.2"); - assertPrints("false\n", "puts 9.2 < (8.2)"); - assertPrints("true\n", "puts (4.2) < ((6.2))"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/HashTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/HashTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Hash} class. - */ -public class HashTests extends RubyTests { - - @Test - public void testLiteral() { - assertPrints("Hash\n", "puts ({}).class"); - assertPrints("Hash\n", "puts ({1 => 2, 3 => 4}).class"); - assertPrints("Hash\n", "puts ({key1: 2, key3: 4}).class"); - } - - @Test - public void testIndex() { - assertPrints("4\n", "foo = {1 => 2, 3 => 4}; puts foo[3]"); - } - - @Test - public void testIndexSet() { - assertPrints("6\n", "foo = {1 => 2, 3 => 4}; foo[5] = 6; puts foo[5]"); - } - - @Test - public void testKeys() { - assertPrints("[1, 3]\n", "foo = {1 => 2, 3 => 4}; puts foo.keys.to_s"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/IntegerTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/IntegerTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Integer} class. - */ -public class IntegerTests extends RubyTests { - - @Test - public void testTimes() { - assertPrints("0\n", "1.times { |i| puts i }"); - assertPrints("0\n1\n2\n", "3.times { |i| puts i }"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/KernelTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/KernelTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.runtime.configuration.*; -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code Kernel}. - */ -public class KernelTests extends RubyTests { - - @Test - public void testPutsEmpty() { - assertPrints("\n", "puts"); - } - - @Test - public void testPutsString() { - assertPrints("1\n", "puts 1"); - } - - @Test - public void testPrintfNoFormatting() { - assertPrints("", "printf"); - assertPrints("foo", "printf \"foo\""); - assertPrints("foo\n", "printf \"foo\\n\""); - } - - @Test - public void testPrintfDecimal() { - assertPrints("foo14bar", "printf \"foo%dbar\", 14"); - } - - @Test - public void testGets() { - assertPrintsWithInput("test\n", "puts gets", "test\n"); - } - - @Test - public void testInteger() { - assertPrints("14\n", "puts Integer(\"14\")"); - } - - @Test - public void testEval() { - assertPrints("16\n", "puts eval(\"14 + 2\")"); - } - - @Test - public void testBindingLocalVariables() { - // Use the current binding for eval - assertPrints("16\n", "x = 14; y = 2; puts eval(\"x + y\", binding)"); - - // Use the binding returned from a method for eval - assertPrints("16\n", "def foo; x = 14; y = 2; binding; end; puts eval(\"x + y\", foo)"); - } - - @Test - public void testBindingInstanceVariables() { - // Use the binding returned from a method in an object for eval - assertPrints("16\n", "class Foo; def foo; @x = 14; @y = 2; binding; end; end; puts eval(\"@x + @y\", Foo.new.foo)"); - } - - @Ignore - @Test - public void testSetTraceFuncLine() { - final ConfigurationBuilder configuration = new ConfigurationBuilder(); - configuration.setTrace(true); - - final String code = "def foo\n" + // - " a = 14\n" + // - " b = 2\n" + // - " a + b\n" + // - "end\n" + // - "\n" + // - "set_trace_func proc { |event, file, line, id, binding, classname|\n" + // - " if event == \"line\"\n" + // - " puts file + \":\" + line.to_s\n" + // - " end\n" + // - "}\n" + // - "\n" + // - "foo"; - final String input = ""; - final String expected = "(test):13\n(test):2\n(test):3\n(test):4\n"; - assertPrints(new Configuration(configuration), expected, "(test)", code, input); - } - - @Test - public void testBlockGiven() { - assertPrints("false\n", "def foo; puts block_given?; end; foo"); - assertPrints("true\n", "def foo; puts block_given?; end; foo do; end"); - assertPrints("true\n", "def foo; puts block_given?; end; foo {}"); - assertPrints("true\n", "def foo; puts block_given?; end; foo &:+"); - } - - @Test - public void testLoop() { - assertPrints("14\n", "loop do; break; end; puts 14"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/MathTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/MathTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Math} class. - */ -public class MathTests extends RubyTests { - - @Test - public void testPI() { - assertPrints("3.141592653589793\n", "puts Math::PI"); - } - - @Test - public void testSqrt() { - assertPrints("1.0\n", "puts Math.sqrt(1)"); - assertPrints("1.0\n", "puts Math::sqrt(1)"); - assertPrints("3.7416573867739413\n", "puts Math::sqrt(14)"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ModuleTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ModuleTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Module} class. - */ -public class ModuleTests extends RubyTests { - - @Test - public void testAttrAccessor() { - assertPrints("14\n", "class Foo; attr_accessor :x end; foo=Foo.new; foo.x=14; puts foo.x"); - assertPrints("14\n", "class Foo; attr_accessor(:x) end; foo=Foo.new; foo.x=14; puts foo.x"); - assertPrints("16\n", "class Foo; attr_accessor(:x, :y) end; foo=Foo.new; foo.x=14; foo.y=2; puts foo.x + foo.y"); - assertPrints("16\n", "class Foo; attr_accessor :x end; foo=Foo.new; foo.x=2; foo.x+=14; puts foo.x"); - } - - @Test - public void testDefineMethod() { - /* - * We use Object#send instead of calling define_method directly because that method is - * private. - */ - - assertPrints("14\n", "class Foo; end; Foo.send(:define_method, :foo) do; puts 14; end; Foo.new.foo"); - } - - @Test - public void testDefinedBeforeScopeRun() { - assertPrints("Module\n", "module Foo; puts Foo.class; end"); - } - - @Test - public void testDefinedInRootScopeBeforeScopeRun() { - assertPrints("Module\n", "module Foo; puts ::Foo.class; end"); - } - - @Test - public void testModuleEval() { - assertPrints("14\n", "class Foo; puts 14; end; Foo.module_eval('def foo; end'); Foo.new.foo"); - } - - @Test - public void testNextInBlock() { - assertPrints("1\n1\n1\n", "3.times do; puts 1; next; puts 2; end"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectSpaceTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectSpaceTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.runtime.configuration.*; -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code ObjectSpace} module. - */ -public class ObjectSpaceTests extends RubyTests { - - @Test - public void testEachObjectClass() { - assertPrints("true\n", "found_string = false; ObjectSpace.each_object(Class) { |o| if o == String; found_string = true; end }; puts found_string"); - } - - @Test - public void testId2RefClass() { - assertPrints("true\n", "puts ObjectSpace._id2ref(String.object_id) == String"); - } - - @Test - public void testEachObjectString() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setFullObjectSpace(true); - final String code = "foo = \"foo\"; found_foo = false; ObjectSpace.each_object(String) { |o| if o == foo; found_foo= true; end }; puts found_foo"; - final String input = ""; - final String expected = "true\n"; - assertPrints(new Configuration(configurationBuilder), expected, "(test)", code, input); - } - - @Test - public void testId2RefString() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setFullObjectSpace(true); - final String code = "foo = \"foo\"; puts ObjectSpace._id2ref(foo.object_id) == foo"; - final String input = ""; - final String expected = "true\n"; - assertPrints(new Configuration(configurationBuilder), expected, "(test)", code, input); - } - - @Test - public void testGarbageCollect() { - assertPrints("", "ObjectSpace.garbage_collect"); - assertPrints("", "ObjectSpace.start"); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Object} class. - */ -public class ObjectTests extends RubyTests { - - @Test - public void testARGV() { - assertPrints("1\n2\n3\n", "puts ARGV", "1", "2", "3"); - } - - @Test - public void testInstanceVariableDefined() { - assertPrints("true\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_defined?(:@bar)"); - assertPrints("true\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_defined?(\"@bar\")"); - assertPrints("true\n", "class Foo; def initialize; instance_variable_set(:@bar, 14); end; end; puts Foo.new.instance_variable_defined?(\"@bar\")"); - assertPrints("false\n", "class Foo; def initialize; @foo=14; end; end; puts Foo.new.instance_variable_defined?(:@bar)"); - assertPrints("false\n", "class Foo; def initialize; @foo=14; end; end; puts Foo.new.instance_variable_defined?(\"@bar\")"); - assertPrints("false\n", "class Foo; def initialize; instance_variable_set(:@foo, 14); end; end; puts Foo.new.instance_variable_defined?(\"@bar\")"); - } - - @Test - public void testInstanceVariableGet() { - assertPrints("14\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_get(:@bar)"); - assertPrints("14\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_get(\"@bar\")"); - } - - @Test - public void testInstanceVariableSet() { - assertPrints("14\n", "class Foo; attr_accessor :bar; end; foo = Foo.new; foo.instance_variable_set(:@bar, 14); puts foo.bar"); - assertPrints("14\n", "class Foo; attr_accessor :bar; end; foo = Foo.new; foo.instance_variable_set(\"@bar\", 14); puts foo.bar"); - } - - @Test - public void testInstanceVariables() { - assertPrints("a\nb\n", "class Foo; def initialize; @a=2; @b=14; end; end; puts Foo.new.instance_variables"); - assertPrints("a\nb\n", "class Foo; def initialize; @a=2; instance_variable_set(:@b, 14); end; end; puts Foo.new.instance_variables"); - } - - @Test - public void testSend() { - assertPrints("14\n", "self.send(:puts, 14)"); - assertPrints("14\n", "self.send(\"puts\", 14)"); - } - - @Test - public void testExtend() { - assertPrints("14\n", "class Foo; end; module Bar; def bar; puts 14; end; end; foo = Foo.new; foo.extend(Bar); foo.bar"); - } - - @Test - public void testSingletonMethods() { - assertPrints("[:baz]\n", "class Foo; def bar; end; end; foo = Foo.new; def foo.baz; end; puts foo.singleton_methods.to_s"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ProcTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ProcTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Proc} class. - */ -public class ProcTests extends RubyTests { - - @Test - public void testKernelProc() { - assertPrints("1\n", "x = proc { puts 1 }; x.call"); - assertPrints("1\n", "x = proc { 1 }; puts x.call"); - } - - @Test - public void testKernelLambda() { - assertPrints("1\n", "x = lambda { puts 1 }; x.call"); - assertPrints("1\n", "x = lambda { 1 }; puts x.call"); - } - - @Test - public void testKernelProcNew() { - assertPrints("1\n", "x = Proc.new { puts 1 }; x.call"); - assertPrints("1\n", "x = Proc.new { 1 }; puts x.call"); - } - - @Test - public void testProcReturn() { - assertPrints("1\n", "def foo; x = proc { return 1 }; x.call; return 2; end; puts foo"); - } - - @Test - public void testLambdaReturn() { - assertPrints("2\n", "def foo; x = lambda { return 1 }; x.call; return 2; end; puts foo"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RangeTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RangeTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Range} class. - */ -public class RangeTests extends RubyTests { - - @Test - public void testImmediate() { - assertPrints("1..2\n", "puts 1..2"); - assertPrints("1..2\n", "puts (1..2)"); - assertPrints("1..2\n", "puts ((1)..2)"); - assertPrints("1...2\n", "puts 1...2"); - } - - @Test - public void testVariables() { - assertPrints("1..2\n", "x = 1; puts x..2"); - assertPrints("1..2\n", "y = 2; puts 1..y"); - assertPrints("1..2\n", "x = 1; y = 2; puts x..y"); - } - - @Test - public void testToArray() { - assertPrints("0\n1\n2\n", "puts (0..2).to_a"); - assertPrints("1\n2\n", "puts (1..2).to_a"); - assertPrints("1\n2\n", "puts (1...3).to_a"); - assertPrints("1\n2\n3\n", "puts (1..3).to_a"); - } - - @Test - public void testEach() { - assertPrints("", "(1...1).each { |n| puts n }"); - assertPrints("1\n", "(1...2).each { |n| puts n }"); - assertPrints("1\n2\n", "(1...3).each { |n| puts n }"); - assertPrints("1\n2\n3\n", "(1...4).each { |n| puts n }"); - assertPrints("1\n", "(1..1).each { |n| puts n }"); - assertPrints("1\n2\n", "(1..2).each { |n| puts n }"); - assertPrints("1\n2\n3\n", "(1..3).each { |n| puts n }"); - assertPrints("1\n2\n3\n4\n", "(1..4).each { |n| puts n }"); - assertPrints("0\n1\n", "(0..1).each { |n| puts n }"); - assertPrints("", "(4..-2).each { |n| puts n }"); - assertPrints("-4\n-3\n-2\n", "(-4..-2).each { |n| puts n }"); - assertPrints("-1\n0\n1\n", "(-1..1).each { |n| puts n }"); - } - - @Test - public void testMap() { - assertPrints("2\n4\n6\n", "puts (1..3).map { |n| n*2 }"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RegexpTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RegexpTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Regexp} class. - */ -public class RegexpTests extends RubyTests { - - @Test - public void testLiteral() { - assertPrints("Regexp\n", "puts /foo/.class"); - } - - @Test - public void testInterpolatedLiteral() { - assertPrints("Regexp\n", "puts /foo#{1}/.class"); - } - - @Test - public void testMatch() { - assertPrints("0\n", "puts(/foo/ =~ \"foo\")"); - assertPrints("0\n", "puts(\"foo\" =~ /foo/)"); - assertPrints("3\n", "puts(/foo/ =~ \"abcfoo\")"); - assertPrints("3\n", "puts(\"abcfoo\" =~ /foo/)"); - assertPrints("\n", "puts(/foo/ =~ \"abc\")"); - assertPrints("\n", "puts(\"abc\" =~ /foo/)"); - } - - @Test - public void testFrameLocalVariableResults() { - assertPrints("foo\nbar\nbaz\n", "/(foo)(bar)(baz)/ =~ 'foobarbaz'; puts $1; puts $2; puts $3"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/StringTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/StringTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code String} class. - */ -public class StringTests extends RubyTests { - - @Test - public void testToI() { - assertPrints("2\n", "puts \"2\".to_i"); - assertPrints("-2\n", "puts \"-2\".to_i"); - assertPrints("123456789123456789\n", "puts \"123456789123456789\".to_i"); - } - - @Test - public void testFormat() { - assertPrints("a\n", "puts \"a\""); - assertPrints("1\n", "puts \"%d\" % 1"); - assertPrints("a1b\n", "puts \"a%db\" % 1"); - assertPrints("a1.00000b\n", "puts \"a%fb\" % 1"); - assertPrints("a2.50000b\n", "puts \"a%fb\" % 2.5"); - assertPrints("3.400000000\n", "puts \"%.9f\" % 3.4"); - assertPrints("3.400000000\n", "puts \"%0.9f\" % 3.4"); - } - - @Test - public void testThreequal() { - assertPrints("false\n", "puts \"a\" === \"b\""); - assertPrints("true\n", "puts \"a\" === \"a\""); - } - - @Test - public void testIndex() { - assertPrints("a\n", "puts 'a'[0]"); - assertPrints("config\n", "puts 'foo.config'[-6..-1]"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/SymbolTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/SymbolTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Symbol} class. - */ -public class SymbolTests extends RubyTests { - - @Test - public void testParses() { - assertPrints("", ":foo"); - assertPrints("", ":\"foo\""); - } - - @Test - public void testPuts() { - assertPrints("foo\n", "puts :foo"); - } - - @Test - public void testInterpolated() { - assertPrints("foo123\n", "puts :\"foo1#{2}3\""); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ThreadTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ThreadTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013 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.test.core; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test the {@code Thread} class. - */ -public class ThreadTests extends RubyTests { - - @Test - public void testCreateJoin() { - assertPrints("1\n2\n", "t = Thread.new { puts 1 }; t.join; puts 2"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/AndTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/AndTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code and} expressions, which unusually for Ruby are not methods. This is because with - * Ruby's eager evaluation there would be no way to implement the short circuit semantics. - */ -public class AndTests extends RubyTests { - - @Test - public void testImmediate() { - assertPrints("false\n", "puts false && false"); - assertPrints("false\n", "puts true && false"); - assertPrints("false\n", "puts false && true"); - assertPrints("true\n", "puts true && true"); - assertPrints("false\n", "puts (false and false)"); - assertPrints("false\n", "puts (true and false)"); - assertPrints("false\n", "puts (false and true)"); - assertPrints("true\n", "puts (true and true)"); - } - - @Test - public void testShortCircuits() { - assertPrints("false\nfalse\nfalse\n", "x = y = false; puts (x = false) && (y = false); puts x, y"); - assertPrints("false\ntrue\nfalse\n", "x = y = false; puts (x = true) && (y = false); puts x, y"); - assertPrints("false\nfalse\nfalse\n", "x = y = false; puts (x = false) && (y = true); puts x, y"); - assertPrints("true\ntrue\ntrue\n", "x = y = false; puts (x = true) && (y = true); puts x, y"); - assertPrints("false\nfalse\nfalse\n", "x = y = false; puts ((x = false) and (y = false)); puts x, y"); - assertPrints("false\ntrue\nfalse\n", "x = y = false; puts ((x = true) and (y = false)); puts x, y"); - assertPrints("false\nfalse\nfalse\n", "x = y = false; puts ((x = false) and (y = true)); puts x, y"); - assertPrints("true\ntrue\ntrue\n", "x = y = false; puts ((x = true) and (y = true)); puts x, y"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/BlockTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/BlockTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test blocks. - */ -public class BlockTests extends RubyTests { - - @Test - public void testSimpleYield() { - assertPrints("1\n", "def foo; yield; end; foo { puts 1 };"); - assertPrints("1\n", "def foo; yield; end; foo do; puts 1; end;"); - } - - @Test - public void testYieldOneParameter() { - assertPrints("1\n", "def foo; yield 1; end; foo { |x| puts x };"); - assertPrints("1\n", "def foo; yield 1; end; foo do |x|; puts x; end;"); - } - - @Test - public void testYieldTwoParameters() { - assertPrints("1\n2\n", "def foo; yield 1, 2; end; foo { |x, y| puts x; puts y; };"); - assertPrints("1\n2\n", "def foo; yield 1, 2; end; foo do |x, y|; puts x; puts y; end;"); - } - - @Test - public void testSelfCapturedInBlock() { - assertPrints("main\n", "[1].each { |n| puts self.to_s }"); - } - - @Test - public void testBlockArgumentsDestructure() { - /* - * This really subtle. If you pass an array to a block with more than one parameters, it - * will be destructured. Any other type won't be destructured. There's no annotation to - * indicate that, like there would be with a method with the * operator. - */ - - assertPrints("1\n", "[1].each { |x| puts x.to_s }"); - assertPrints("[1, 2]\n", "[[1, 2]].each { |xy| puts xy.to_s }"); - assertPrints("1\n2\n", "[[1, 2]].each { |x, y| puts x, y }"); - } - - @Test - public void testBlocksHaveTheirOwnScopeForAssignment() { - assertPrints("\n", "1.times { x = 14 }; puts defined? x"); - assertPrints("\n", "1.times do; x = 14; end; puts defined? x"); - } - - @Test - public void testImplicitForBlocksDoNotHaveTheirOwnScopeForAssignment() { - assertPrints("local-variable\n", "for n in [1]; x = 14; end; puts defined? x"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/CaseTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/CaseTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code case} expressions. - */ -public class CaseTests extends RubyTests { - - @Test - public void testSingle() { - assertPrints("1\n4\n", "case 'a'; when 'a'; puts 1; when 'b'; puts 2; else; puts 3; end; puts 4"); - assertPrints("2\n4\n", "case 'b'; when 'a'; puts 1; when 'b'; puts 2; else; puts 3; end; puts 4"); - assertPrints("3\n4\n", "case 'c'; when 'a'; puts 1; when 'b'; puts 2; else; puts 3; end; puts 4"); - } - - @Test - public void testMultiple() { - assertPrints("1\n4\n", "case 'a'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4"); - assertPrints("1\n4\n", "case 'b'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4"); - assertPrints("2\n4\n", "case 'c'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4"); - assertPrints("3\n4\n", "case 'd'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4"); - } - - @Test - public void testSimpleConditions() { - assertPrints("1\n", "case; when true; puts 1; when false; puts 2; end"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassLocalTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassLocalTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test @@ class variables. There is a lot of counter-intuitive behavior here - they aren't instance - * variables in class objects. The books describe them as being in a 'class hierarchy', rather than - * in a class. Also, the object they are defined it is not consistent - sometimes it is the class of - * self, sometimes it's just self. - */ -public class ClassLocalTests extends RubyTests { - - @Test - public void testBasic() { - assertPrints("14\n", "@@x = 14; puts @@x"); - } - - /* - * Test that they are defined for a hierarchy, not a class. - */ - - @Test - public void testHeirarchyNotClassVariable() { - assertPrints("2\n", "class Foo; @@value = 14; end; class Bar < Foo; @@value = 2; end; class Foo; puts @@value; end"); - } - - /* - * Test that they take the correct class at different times. In a method, they use the class of - * self. In a class definition they use that class, not the class of self, which is Class. - */ - - @Test - public void testCorrectClass() { - assertPrints("1\n", "class Foo; @@x = 1; def foo; puts @@x; end; end; Foo.new.foo"); - } - - @Test - public void testWithinSelfMethod() { - assertPrints("14\n", "class Foo; @@foo = 14; def self.foo; @@foo; end; end; puts Foo.foo"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code class} expressions. - */ -public class ClassTests extends RubyTests { - - @Test - public void testDefine() { - assertPrints("Foo\n", "class Foo; end; puts Foo"); - } - - @Test - public void testMethods() { - assertPrints("14\n", "class Foo; def test; return 14; end; end; foo=Foo.new; puts foo.test"); - assertPrints("14\n", "class Foo; def test(x); return x; end; end; foo=Foo.new; puts foo.test(14)"); - } - - @Test - public void testDefineHasScope() { - assertPrints("14\n", "x=14; class Foo; x=0; end; puts x"); - assertPrints("14\n", "class Foo; x=14; puts x; end"); - } - - @Test - public void testInitialise() { - assertPrints("14\n", "class Foo; def initialize; puts 14; end; end; Foo.new"); - assertPrints("14\n", "class Foo; def initialize(x); puts x; end; end; Foo.new 14"); - assertPrints("14\n", "class Foo; def initialize(x); puts x; end; end; Foo.new(14)"); - } - - @Test - public void testInstanceVariables() { - assertPrints("14\n", "class Foo; def a; @x=14; end; def b; @x; end; end; foo=Foo.new; foo.a; puts foo.b"); - } - - @Test - public void testMissingVariables() { - assertPrints("NilClass\n", "class Foo; def a; @x; end; end; foo=Foo.new; puts foo.a.class"); - } - - @Test - public void testClassConstants() { - assertPrints("14\n", "class Foo; X=14; def foo; puts X; end; end; foo=Foo.new; foo.foo"); - } - - @Test - public void testReopeningSingletonClass() { - assertPrints("1\n", "foo = Object.new; class << foo; def bar; puts 1; end; end; foo.bar"); - } - - @Test - public void testInheritance() { - assertPrints("14\n", "class Foo; def foo; puts 14; end; end; class Bar < Foo; end; Bar.new.foo"); - } - - @Test - public void testSingletonInheritance() { - assertPrints("14\n", "class Foo; def self.foo; puts 14; end; end; class Bar < Foo; end; Bar.foo"); - } - - @Test - public void testNestedClass() { - assertPrints("14\n", "class Foo; class Bar; def bar; 14; end; end; def foo; Bar.new; end; end; puts Foo.new.foo.bar"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ConstantTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ConstantTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -public class ConstantTests extends RubyTests { - - @Test - public void testTopLevelConstants() { - assertPrints("14\n", "X=14; class Foo; def foo; puts X; end; end; f=Foo.new; f.foo"); - } - - @Test - public void testNestedConstants() { - assertPrints("", "module X; class A; end; class B; class C < A; end; end; end"); - } - - @Test - public void testSearchInParentModules() { - assertPrints("14\n", "module A; C = 14; module B; def self.test; puts C; end; end; end; A::B.test"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ForTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ForTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code for} expressions. - */ -public class ForTests extends RubyTests { - - @Test - public void testArray() { - assertPrints("1\n2\n3\n", "for x in [1, 2, 3]; puts x; end"); - assertPrints("1\n2\n3\n", "y = [1, 2, 3]; for x in y; puts x; end"); - } - - @Test - public void testRange() { - assertPrints("1\n2\n3\n", "for x in 1..3; puts x; end"); - assertPrints("1\n2\n3\n", "y = 1..3; for x in y; puts x; end"); - assertPrints("1\n2\n", "for x in 1...3; puts x; end"); - } - - @Test - public void testScopeRO() { - assertPrints("14\n", "x=14; for n in [1]; puts x; end"); - } - - @Test - public void testScopeRW() { - assertPrints("14\n", "x=0; for n in [1]; x=x+14; puts x; end"); - } - - @Test - public void testNoNewScope() { - assertPrints("14\n", "for i in [1]; v = 14; end; puts v"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/GlobalVariableTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/GlobalVariableTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test global variables. - */ -public class GlobalVariableTests extends RubyTests { - - @Test - public void testMinimal() { - assertPrints("14\n", "$foo = 14; puts $foo"); - } - - @Test - public void testScope() { - assertPrints("14\n", "def foo; $bar = 14; end; foo; puts $bar"); - assertPrints("14\n", "$bar = 14; def foo; puts $bar; end; foo"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/IfTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/IfTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code if} expressions. - */ -public class IfTests extends RubyTests { - - @Test - public void testImmediateIf() { - assertPrints("1\n", "if true; puts 1 end"); - assertPrints("", "if false; puts 1 end"); - } - - @Test - public void testImmediateTrailingIf() { - assertPrints("1\n", "puts 1 if true"); - assertPrints("", "puts 1 if false"); - } - - @Test - public void testImmediateIfElse() { - assertPrints("1\n", "if true; puts 1 else puts 2 end"); - assertPrints("2\n", "if false; puts 1 else puts 2 end"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/InterpolatedStringTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/InterpolatedStringTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test interpolated strings - that is string literals with #{...} sections in them. Within those - * you can have arbitrary Ruby expressions. - */ -public class InterpolatedStringTests extends RubyTests { - - @Test - public void testBasic() { - assertPrints("123\n", "puts \"1#{2}3\""); - } - - @Test - public void testMethodCall() { - assertPrints("123\n", "def foo; 2; end; puts \"1#{foo}3\""); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/LocalTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/LocalTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test local variables. - */ -public class LocalTests extends RubyTests { - - @Test - public void testAssignmentTopLevel() { - assertPrints("1\n", "x = 1; puts x"); - } - - @Test - public void testAssignmentWithinMethod() { - assertPrints("1\n", "def foo; x = 1; puts x; end; foo"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MethodTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MethodTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.test.*; - -/** - * Test method definitions and calls. - */ -public class MethodTests extends RubyTests { - - @Test - public void testDefineCallNoArguments() { - assertPrints("1\n", "def foo; puts 1; end; foo()"); - assertPrints("1\n", "def foo; puts 1; end; foo"); - } - - @Test - public void testDefineCallOnePreArgument() { - assertPrints("1\n", "def foo(a); puts a; end; foo(1)"); - assertPrints("1\n", "def foo(a); puts a; end; foo 1"); - } - - @Test - public void testDefineCallTwoPreArguments() { - assertPrints("1\n2\n", "def foo(a, b); puts a; puts b; end; foo(1, 2)"); - assertPrints("1\n2\n", "def foo(a, b); puts a; puts b; end; foo 1, 2"); - } - - @Test - public void testSingleReturn() { - assertPrints("1\n", "def foo; return 1; end; puts foo"); - assertPrints("1\n", "def foo(n); return n; end; puts foo(1)"); - } - - @Test - public void testImplicitReturn() { - assertPrints("1\n", "def foo; 1; end; puts foo"); - assertPrints("3\n", "def foo; 1+2; end; puts foo"); - assertPrints("14\n", "def foo; x=14; end; puts foo"); - } - - @Test - public void testNestedCall() { - assertPrints("1\n", "def foo(n); return n; end; def bar(n); return foo(n); end; puts bar(1)"); - assertPrints("1\n1\n1\n", "def foo(n); puts n; return n; end; def bar(n); puts n; return foo(n); end; puts bar(1)"); - assertPrints("1\n1\n", "def foo(a, b); puts a; puts b; end; def bar(n); foo(n, n); end; bar(1)"); - } - - @Test - public void testNestedOperatorCall() { - assertPrints("3\n", "def foo(a, b); puts a + b; end; foo(1, 2)"); - } - - /** - * Tests that arguments are evaluated before method dispatch takes place, by putting an action - * in one of the arguments that modifies the method that we should find in dispatch. - */ - @Test - public void testArgumentsExecutedBeforeDispatch() { - /* - * We have to use Object#send instead of calling define_method directly because that method - * is private. - */ - - assertPrints("12\n", "def foo\n" + // - " Fixnum.send(:define_method, :+) do |other|\n" + // - " self - other\n" + // - " end \n" + // - " 2\n" + // - "end\n" + // - "puts 14 + foo"); - } - - @Test(expected = RaiseException.class) - public void testTooFewArguments1() { - assertPrints("", "def foo(a); end; foo()"); - } - - @Test(expected = RaiseException.class) - public void testTooFewArguments2() { - assertPrints("", "def foo(a, b); end; foo(1)"); - } - - @Test(expected = RaiseException.class) - public void testTooFewArguments3() { - assertPrints("", "def foo(a, b, c); end; foo(1, 2)"); - } - - @Test(expected = RaiseException.class) - public void testTooManyArguments1() { - assertPrints("", "def foo(); end; foo(1)"); - } - - @Test(expected = RaiseException.class) - public void testTooManyArguments2() { - assertPrints("", "def foo(a); end; foo(1, 2)"); - } - - @Test(expected = RaiseException.class) - public void testTooManyArguments3() { - assertPrints("", "def foo(a, b); end; foo(1, 2, 3)"); - } - - @Test - public void testPolymophicMethod() { - assertPrints("A\nB\n", "class A\n" + // - " def foo\n" + // - " puts \"A\"\n" + // - " end\n" + // - "end\n" + // - "\n" + // - "class B\n" + // - " def foo\n" + // - " puts \"B\"\n" + // - " end\n" + // - "end\n" + // - "\n" + // - "def bar(x)\n" + // - " x.foo\n" + // - "end\n" + // - "\n" + // - "a = A.new\n" + // - "b = B.new\n" + // - "\n" + // - "bar(a)\n" + // - "bar(b)\n"); - } - - @Test - public void testOneDefaultValue() { - assertPrints("1\n2\n", "def foo(a=1); puts a; end; foo; foo(2)"); - } - - @Test - public void testTwoDefaultValues() { - assertPrints("1\n2\n3\n2\n3\n4\n", "def foo(a=1,b=2); puts a; puts b; end; foo; foo(3); foo(3, 4)"); - } - - @Test - public void testOneDefaultValueAfterNonDefault() { - assertPrints("2\n1\n2\n3\n", "def foo(a, b=1); puts a; puts b; end; foo(2); foo(2, 3)"); - } - - @Test - public void testOneDefaultValueBeforeNonDefault() { - assertPrints("1\n2\n2\n3\n", "def foo(a=1, b); puts a; puts b; end; foo(2); foo(2, 3)"); - } - - @Test - public void testBlockArgument() { - assertPrints("1\n2\n3\n", "def foo(&block); block.call(14); end; puts 1; foo { |n| puts 2 }; puts 3"); - } - - @Test - public void testBlockArgumentWithOthers() { - assertPrints("1\n2\n3\n4\n5\n", "def foo(a, b, &block); puts a; block.call(14); puts b; end; puts 1; foo(2, 4) { |n| puts 3 }; puts 5"); - } - - @Test - public void testBlockPass() { - assertPrints("1\n2\n3\n", "def bar; yield; end; def foo(&block); bar(&block); end; puts 1; foo { puts 2 }; puts 3"); - } - - @Test - public void testBlockPassWithOthers() { - assertPrints("1\n2\n3\n4\n5\n", "def bar(a, b); puts a; yield; puts b; end; def foo(a, b, &block); bar(a, b, &block); end; puts 1; foo(2, 4) { puts 3 }; puts 5"); - } - - @Test - public void testSplatWhole() { - assertPrints("1\n2\n3\n", "def foo(a, b, c); puts a; puts b; puts c; end; d = [1, 2, 3]; foo(*d)"); - } - - @Test - public void testSplatSome() { - assertPrints("1\n2\n3\n", "def foo(a, b, c); puts a; puts b; puts c; end; d = [2, 3]; foo(1, *d)"); - } - - @Test - public void testSplatParam() { - assertPrints("[1, 2, 3]\n", "def foo(*bar); puts bar.to_s; end; foo(1, 2, 3)"); - } - - @Test - public void testSplatParamWithOther() { - assertPrints("1\n[2]\n", "def foo(a, *b); puts a.to_s; puts b.to_s; end; foo(1, 2)"); - } - - @Test - public void testSplatParamWithBlockPass() { - assertPrints("[1, 2, 3]\n", "def foo(*bar, &block); block.call(bar); end; foo(1, 2, 3) { |x| puts x.to_s }"); - } - - @Test - public void testSingletonMethod() { - assertPrints("1\n", "foo = Object.new; def foo.bar; puts 1; end; foo.bar"); - } - - @Test - public void testAlias() { - assertPrints("1\n", "def foo; puts 1; end; alias bar foo; bar"); - assertPrints("1\n", "class Foo; def foo; puts 1; end; alias bar foo; end; Foo.new.bar"); - } - - @Test - public void testAliasMethod() { - assertPrints("1\n", "class Foo; def foo; puts 1; end; alias_method :bar, :foo; end; Foo.new.bar"); - } - - @Test - public void testSymbolAsBlock() { - assertPrints("6\n", "puts [1, 2, 3].inject(&:+)"); - } - - @Test - public void testSuper() { - assertPrints("1\n2\n3\n", "class Foo; def foo; puts 2; end; end; class Bar < Foo; def foo; puts 1; super; puts 3; end; end; Bar.new.foo"); - } - - @Test - public void testSuperWithArgs() { - assertPrints("1\n2\n3\n", "class Foo; def foo(n); puts n; end; end; class Bar < Foo; def foo(n); puts 1; super(n); puts 3; end; end; Bar.new.foo(2)"); - } - - @Test - public void testPushSplat() { - assertPrints("[1, 0, 4]\n", "a = [1, 2, 3, 4]; b = [1, 2]; a[*b] = 0; puts a.to_s"); - } - - @Test - public void testBlocksPassedIntoBlocks() { - assertPrints("14\n", "def foo; 1.times do; yield; end; end; foo do; puts 14; end"); - } - - @Test - public void testBlocksNotPassedIntoFullMethods() { - assertPrints("no block\n", "def foo(&block); if block; puts 'block'; else; puts 'no block'; end; end; def bar; foo; end; bar do; end"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ModuleTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ModuleTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code module} expressions. - */ -public class ModuleTests extends RubyTests { - - @Test - public void testDefine() { - assertPrints("Foo\n", "module Foo; end; puts Foo"); - } - - @Test - public void testWithConstantDefinition() { - assertPrints("14\n", "module Foo; FOO=14; end; puts Foo::FOO"); - } - - @Test - public void testWithConstantDefinitionAndAccessInDeclaration() { - assertPrints("14\n", "module Foo; FOO=14; puts FOO; end"); - } - - @Test - public void testCanAccessObjectConstantsInModuleDefinition() { - assertPrints("", "class Foo; end; module Bar; foo = Foo.new; end"); - } - - @Test - public void testInclude() { - assertPrints("14\n", "module Foo; FOO=14; end; module Bar; include Foo; end; puts Bar::FOO"); - } - - @Test - public void testModuleFunction() { - assertPrints("1\n", "module Foo; def bar; puts 1; end; module_function :bar; end; Foo::bar"); - } - - @Test - public void testDistinctModule() { - assertPrints("true\n", "module A; module X; end; end; module B; module X; end; end; puts A::X.object_id != B::X.object_id"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MultipleAssignmentTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MultipleAssignmentTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test multiple assignment, which is sort of like pattern matching for arrays. The arrays can be - * implicit on the RHS. - */ -public class MultipleAssignmentTests extends RubyTests { - - @Test - public void testToLocal() { - assertPrints("1\n2\n", "x, y = [1, 2]; puts x, y"); - assertPrints("1\n2\n", "x, y = 1, 2; puts x, y"); - assertPrints("1\n2\n", "x = [1, 2]; y, z = x; puts y, z"); - } - - @Test - public void testToArrayIndex() { - assertPrints("1\n2\n", "x = []; x[0], x[1] = 1, 2; puts x"); - } - - @Test - public void testSwap() { - assertPrints("2\n1\n", "a = [1]; b = [2]; a[0], b[0] = b[0], a[0]; puts a, b"); - } - - @Test - public void testProducesArray() { - assertPrints("1\n2\n", "puts((a, b = 1, 2))"); - } - - @Test - public void testWithSplat() { - assertPrints("1\n[2, 3]\n", "a, *b = [1, 2, 3]; puts a; puts b.to_s"); - } - - @Test - public void testWithSplatEmpty() { - assertPrints("1\n[]\n", "a, *b = [1]; puts a.to_s; puts b.to_s"); - } - - @Test - public void testWithSingleValueRHS() { - assertPrints("14\n\n\n", "a, b, c = 14; puts a; puts b; puts c"); - assertPrints("\n\n\n", "a, b, c = nil; puts a; puts b; puts c"); - } - - @Test - public void testWithSingleSplatLHSAndSingleValueRHS() { - assertPrints("[14]\n", "a = *14; puts a.to_s"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/OrTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/OrTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code or} expressions, which unusually for Ruby are not methods. This is because with - * Ruby's eager evaluation there would be no way to implement the short circuit semantics. - */ -public class OrTests extends RubyTests { - - @Test - public void testImmediate() { - assertPrints("false\n", "puts false || false"); - assertPrints("true\n", "puts true || false"); - assertPrints("true\n", "puts false || true"); - assertPrints("true\n", "puts true || true"); - assertPrints("false\n", "puts (false or false)"); - assertPrints("true\n", "puts (true or false)"); - assertPrints("true\n", "puts (false or true)"); - assertPrints("true\n", "puts (true or true)"); - } - - @Test - public void testShortCircuits() { - assertPrints("false\nfalse\nfalse\n", "x = y = false; puts (x = false) || (y = false); puts x, y"); - assertPrints("true\ntrue\nfalse\n", "x = y = false; puts (x = true) || (y = false); puts x, y"); - assertPrints("true\nfalse\ntrue\n", "x = y = false; puts (x = false) || (y = true); puts x, y"); - assertPrints("true\ntrue\nfalse\n", "x = y = false; puts (x = true) || (y = true); puts x, y"); - assertPrints("false\nfalse\nfalse\n", "x = y = false; puts ((x = false) or (y = false)); puts x, y"); - assertPrints("true\ntrue\nfalse\n", "x = y = false; puts ((x = true) or (y = false)); puts x, y"); - assertPrints("true\nfalse\ntrue\n", "x = y = false; puts ((x = false) or (y = true)); puts x, y"); - assertPrints("true\ntrue\nfalse\n", "x = y = false; puts ((x = true) or (y = true)); puts x, y"); - } - - @Test - public void testOrAssign() { - assertPrints("true\n", "def foo; puts 1; false; end; x = true; x ||= foo; puts x"); - assertPrints("1\nfalse\n", "def foo; puts 1; false; end; x = false; x ||= foo; puts x"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/PolymorphismTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/PolymorphismTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test characteristics of polymorphism. - */ -public class PolymorphismTests extends RubyTests { - - /** - * Test that a polymorphic method that will specialize to double will then not treat integers as - * doubles. - */ - @Test - public void testSimpleOperatorRedefinition() { - assertPrints("16.759999999999998\n16\n", // - "def add(x, y)\n" + // - " x + y\n" + // - "end\n" + // - "puts add(14.5, 2.26)\n" + // - "puts add(14, 2)\n"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RaiseRescueTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RaiseRescueTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code raise} and {@code rescue}. - */ -public class RaiseRescueTests extends RubyTests { - - @Test(expected = RaiseException.class) - public void testZeroDivisionError() { - assertPrints("", "1/0"); - } - - @Test - public void testBeginRescue() { - assertPrints("", "begin; rescue; end"); - assertPrints("", "begin; rescue => e; end"); - assertPrints("", "begin; rescue ZeroDivisionError => e; end"); - assertPrints("", "begin; rescue; ensure; end"); - assertPrints("", "begin; rescue => e; ensure; end"); - assertPrints("", "begin; rescue ZeroDivisionError => e; ensure; end"); - assertPrints("", "begin; rescue; else; end"); - assertPrints("", "begin; rescue => e; else; end"); - assertPrints("", "begin; rescue ZeroDivisionError => e; else; end"); - assertPrints("", "def foo; rescue; end"); - assertPrints("", "def foo; rescue => e; end"); - assertPrints("", "def foo; rescue ZeroDivisionError => e; end"); - assertPrints("", "def foo; rescue; ensure; end"); - assertPrints("", "def foo; rescue => e; ensure; end"); - assertPrints("", "def foo; rescue ZeroDivisionError => e; ensure; end"); - assertPrints("", "def foo; rescue; else; end"); - assertPrints("", "def foo; rescue => e; else; end"); - assertPrints("", "def foo; rescue ZeroDivisionError => e; else; end"); - } - - @Test - public void testRescueZeroDivisionError() { - assertPrints("divided by 0\n3\n4\n", "begin; 1/0; puts 1; rescue => e; puts e; else puts 2; ensure puts 3; end; puts 4"); - assertPrints("divided by 0\n3\n4\n", "begin; 1/0; puts 1; rescue ZeroDivisionError => e; puts e; else puts 2; ensure puts 3; end; puts 4"); - assertPrints("1\n2\n3\n4\n", "begin; 1/1; puts 1; rescue ZeroDivisionError => e; puts e; else puts 2; ensure puts 3; end; puts 4"); - assertPrints("1\n2\n3\n4\n", "begin; 1/1; puts 1; rescue ZeroDivisionError => e; puts e; rescue NameError => e; puts e; else puts 2; ensure puts 3; end; puts 4"); - } - - @Test - public void testSplatRescue() { - assertPrints("2\n", "ERRORS=[ZeroDivisionError]; begin; 1/0; puts 1; rescue *ERRORS; puts 2; end"); - } - - @Test - public void testRetry() { - assertPrints("1\n3\n1\n2\n5\n", "x=0; begin; puts 1; 1/x; puts 2; rescue ZeroDivisionError; puts 3; x=1; retry; puts 4; end; puts 5"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RedefinitionTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RedefinitionTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test that methods can be redefined. - */ -public class RedefinitionTests extends RubyTests { - - /** - * Test that a method on Fixnum can be redefined and that we will use the new definition. The - * call that expects to find the redefinition needs to have already been specialized, which is - * why do it through a method. - */ - @Test - public void testSimpleOperatorRedefinition() { - assertPrints("3\n-1\n", // - "def add(x, y)\n" + // - " x + y\n" + // - "end\n" + // - "puts add(1, 2)\n" + // - "class Fixnum\n" + // - " def +(other)\n" + // - " self - other\n" + // - " end\n" + // - "end\n" + // - "puts add(1, 2)\n"); - } - - /** - * This is quite a subtle test. We redefine Float#+. We have a method which calls +. It is - * initially specialized to Fixnum, but then used with Float. The tricky bit is that Float has - * not been redefined since the operator has been specialized. The operator thinks it is up to - * date. When we emit a + node, we need to check if any class that that node could specialize to - * has been redefined. - */ - @Test - public void testSpecialisationConsidersRedefinitionInOtherClasses() { - assertPrints("16\n12.25\n", // - "def add(a, b)\n" + // - " a + b\n" + // - "end\n" + // - "class Float\n" + // - " def +(other)\n" + // - " self - other\n" + // - " end\n" + // - "end\n" + // - "puts add(14, 2)\n" + // - "puts add(14.5, 2.25)"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ShortcutTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ShortcutTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test shortcut expressions (syntactic sugar) such as {@code +=} and {@code |=}. - */ -public class ShortcutTests extends RubyTests { - - @Test - public void testShortcutAddAssign() { - assertPrints("2\n", "x = 1; x += 1; puts x"); - } - - @Test - public void testShortcutSubAssign() { - assertPrints("0\n", "x = 1; x -= 1; puts x"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/SpecialVariableTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/SpecialVariableTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test variables with special semantics, such as the 'global variables', {@code $_}, {@code $~} - * etc. - */ -public class SpecialVariableTests extends RubyTests { - - @Test - public void testGetsResult() { - assertPrintsWithInput("test\n", "gets; puts $_", "test\n"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/UntilTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/UntilTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2013 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code until} expressions. - */ -public class UntilTests extends RubyTests { - - @Test - public void testSimpleWhile() { - assertPrints("0\n", "x = 10; until x == 0; x -= 1; end; puts x"); - assertPrints("10\n", "x = 0; until x == 10; x += 1; end; puts x"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/WhileTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/WhileTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /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. 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.test.language; - -import org.junit.*; - -import com.oracle.truffle.ruby.test.*; - -/** - * Test {@code while} expressions. - */ -public class WhileTests extends RubyTests { - - @Test - public void testSimpleWhile() { - assertPrints("0\n", "x = 10; while x > 0; x -= 1; end; puts x"); - assertPrints("10\n", "x = 0; while x < 10; x += 1; end; puts x"); - } - - @Test - public void testBreak() { - assertPrints("1\n", "x = 0; while x < 10; x += 1; break; end; puts x"); - } - - @Test - public void testNext() { - assertPrints("10\n", "x = 0; while x < 10; x += 1; next; end; puts x"); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/runtime/ObjectLayoutTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/runtime/ObjectLayoutTests.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2013 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.test.runtime; - -import org.junit.*; - -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.objects.*; - -import static org.junit.Assert.*; - -/** - * Test the object layout classes. - */ -public class ObjectLayoutTests { - - @Test - public void testNewInstanceVariable() { - final RubyContext context = new RubyContext(null); - - // Create a class and an instance - - final RubyClass classA = new RubyClass(context, null, null, null, "A"); - final ObjectLayout layoutClassA = classA.getObjectLayoutForInstances(); - - final RubyBasicObject objectA = new RubyBasicObject(classA); - final ObjectLayout layoutObjectA = objectA.getObjectLayout(); - - // Add an instance variable to the instance - - objectA.setInstanceVariable("foo", 14); - - // That should have changed the layout of the class - - assertNotSame(layoutClassA, classA.getObjectLayoutForInstances()); - - // If we notify the object, it should also change the layout of that - - objectA.updateLayout(); - assertNotSame(layoutObjectA, objectA.getObjectLayout()); - - // We should be able to find that instance variable as a storage location in the class - - assertNotNull(classA.getObjectLayoutForInstances().findStorageLocation("foo")); - - // We should be able to read that value back out - - assertEquals(14, objectA.getInstanceVariable("foo")); - } - - @Test - public void testOverflowPrimitives() { - final RubyContext context = new RubyContext(null); - - // Create a class and an instance - - final RubyClass classA = new RubyClass(context, null, null, null, "A"); - final RubyBasicObject objectA = new RubyBasicObject(classA); - - // Add many more Fixnums that we have space for primitives - - final int count = 100; - - for (int n = 0; n < count; n++) { - objectA.setInstanceVariable("foo" + n, n); - } - - // We should be able to read them back out - - for (int n = 0; n < count; n++) { - assertEquals(n, objectA.getInstanceVariable("foo" + n)); - } - } - - @Test - public void testGeneralisation() { - final RubyContext context = new RubyContext(null); - - // Create a class and two instances - - final RubyClass classA = new RubyClass(context, null, null, null, "A"); - final RubyBasicObject object1 = new RubyBasicObject(classA); - final RubyBasicObject object2 = new RubyBasicObject(classA); - - // Set an instance variable to be a Fixnum in object 1 - - object1.setInstanceVariable("foo", 14); - - // We should be able to read that instance variable back, and it should still be a Fixnum - - assertEquals(14, object1.getInstanceVariable("foo")); - assertSame(Integer.class, object1.getInstanceVariable("foo").getClass()); - - // The underlying instance store should be Fixnum - - assertSame(FixnumStorageLocation.class, object1.getObjectLayout().findStorageLocation("foo").getClass()); - - /* - * The same instance variable in object 2 should be Nil. Note that this requires that we - * realise that even though the instance variable is known about in the layout of object 2, - * and we are using a primitive int to hold it, that it hasn't been set and is actually Nil. - * We don't want it to appear as 0. - */ - - assertSame(NilPlaceholder.INSTANCE, object2.getInstanceVariable("foo")); - - /* - * We should be able to set the same instance variable in object 2 to also be a Fixnum - * without changing the layout. - */ - - final ObjectLayout objectLayout2 = object2.getObjectLayout(); - object2.setInstanceVariable("foo", 2); - assertEquals(2, object2.getInstanceVariable("foo")); - assertSame(Integer.class, object2.getInstanceVariable("foo").getClass()); - assertSame(objectLayout2, object2.getObjectLayout()); - - // Set the instance variable in object 2 to be a Float - - object2.setInstanceVariable("foo", 2.25); - - // We should be able to read that instance variable back, and it should still be a Fixnum - - assertEquals(2.25, object2.getInstanceVariable("foo")); - assertSame(Double.class, object2.getInstanceVariable("foo").getClass()); - - // Object 1 should give still think the instance variable is a Fixnum - - assertEquals(14, object1.getInstanceVariable("foo")); - assertSame(Integer.class, object1.getInstanceVariable("foo").getClass()); - - // The underlying instance store in both objects should now be Object - - assertSame(ObjectStorageLocation.class, object1.getObjectLayout().findStorageLocation("foo").getClass()); - assertSame(ObjectStorageLocation.class, object2.getObjectLayout().findStorageLocation("foo").getClass()); - - } - - @Test - public void testSubclasses() { - final RubyContext context = new RubyContext(null); - - // Create two classes, A, and a subclass, B, and an instance of each - - final RubyClass classA = new RubyClass(context, null, null, null, "A"); - final RubyClass classB = new RubyClass(context, null, null, classA, "B"); - - ObjectLayout layoutClassA = classA.getObjectLayoutForInstances(); - ObjectLayout layoutClassB = classA.getObjectLayoutForInstances(); - - final RubyBasicObject objectA = new RubyBasicObject(classA); - final RubyBasicObject objectB = new RubyBasicObject(classB); - - ObjectLayout layoutObjectA = objectA.getObjectLayout(); - ObjectLayout layoutObjectB = objectB.getObjectLayout(); - - // Add an instance variable to the instance of A - - objectA.setInstanceVariable("foo", 14); - - // That should have changed the layout of both classes - - assertNotSame(layoutClassA, classA.getObjectLayoutForInstances()); - assertNotSame(layoutClassB, classB.getObjectLayoutForInstances()); - - layoutClassA = classA.getObjectLayoutForInstances(); - layoutClassB = classA.getObjectLayoutForInstances(); - - // If we notify the objects, both of them should have changed layouts - - objectA.updateLayout(); - objectB.updateLayout(); - assertNotSame(layoutObjectA, objectA.getObjectLayout()); - assertNotSame(layoutObjectB, objectB.getObjectLayout()); - - layoutObjectA = objectA.getObjectLayout(); - layoutObjectB = objectB.getObjectLayout(); - - // We should be able to find that instance variable as a storage location in both classes - - assertNotNull(classA.getObjectLayoutForInstances().findStorageLocation("foo")); - assertNotNull(classB.getObjectLayoutForInstances().findStorageLocation("foo")); - - // We should be able to read that value back out - - assertEquals(14, objectA.getInstanceVariable("foo")); - - // Add an instance variable to the instance of B - - objectB.setInstanceVariable("bar", 2); - - // This should not have changed the layout of A or the instance of A - - assertSame(layoutClassA, classA.getObjectLayoutForInstances()); - assertSame(layoutObjectA, objectA.getObjectLayout()); - - // But the layout of B and the instance of B should have changed - - assertNotSame(layoutClassB, classB.getObjectLayoutForInstances()); - - objectB.updateLayout(); - assertNotSame(layoutObjectB, objectB.getObjectLayout()); - - // We should be able to find the new instance variable in the instance of B but not A - - assertNull(classA.getObjectLayoutForInstances().findStorageLocation("bar")); - assertNotNull(classB.getObjectLayoutForInstances().findStorageLocation("bar")); - - // We should be able to read that value back out - - assertEquals(2, objectB.getInstanceVariable("bar")); - } - - @Test - public void testPerObjectInstanceVariables() { - final RubyContext context = new RubyContext(null); - - // Create a class and an instance - - final RubyClass classA = new RubyClass(context, context.getCoreLibrary().getClassClass(), null, null, "A"); - final RubyBasicObject objectA = new RubyBasicObject(classA); - - ObjectLayout layoutClassA = classA.getObjectLayoutForInstances(); - ObjectLayout layoutObjectA = objectA.getObjectLayout(); - - // Add an instance variable to the instance of A - - objectA.setInstanceVariable("foo", 2); - - // That should have changed the layout of the class and the object - - assertNotSame(layoutClassA, classA.getObjectLayoutForInstances()); - assertNotSame(layoutObjectA, objectA.getObjectLayout()); - layoutClassA = classA.getObjectLayoutForInstances(); - layoutObjectA = classA.getObjectLayout(); - - // We should be able to read the value back out - - assertEquals(2, objectA.getInstanceVariable("foo")); - - /* - * Switch object A to having a private object layout, as would be done by calls such as - * instance_variable_set. - */ - - objectA.switchToPrivateLayout(); - - // Set an instance variable on object A - - objectA.setInstanceVariable("bar", 14); - - // The layout of object A, however, should have changed - - // CS: it hasn't changed because it's still null - // assertNotSame(layoutObjectA, objectA.getObjectLayout()); - - // We should be able to read the value back out - - assertEquals(14, objectA.getInstanceVariable("bar")); - - /* - * We should also be able to read the first variable back out, even though we've switched to - * private layout since then. - */ - - assertEquals(2, objectA.getInstanceVariable("foo")); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import java.io.*; - -import org.junit.*; - -import com.oracle.truffle.sl.*; - -public class AbstractTest { - - public static final int REPEATS = 10; - private static final String NEWLINE = System.getProperty("line.separator"); - - private static String concat(String[] string) { - StringBuilder result = new StringBuilder(); - for (String s : string) { - result.append(s).append(NEWLINE); - } - return result.toString(); - } - - private static String repeat(String s, int count) { - StringBuilder result = new StringBuilder(s.length() * count); - for (int i = 0; i < count; i++) { - result.append(s); - } - return result.toString(); - } - - protected static void executeSL(String[] input, String[] expectedOutput, boolean useConsole) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - PrintStream printer = new PrintStream(useConsole ? new SplitOutputStream(out, System.err) : out); - PrintStream origErr = System.err; - System.setErr(printer); - - SimpleLanguage.run("(test)", concat(input), printer, REPEATS, false); - - System.setErr(origErr); - Assert.assertEquals(repeat(concat(expectedOutput), REPEATS), new String(out.toByteArray())); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AddTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AddTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class AddTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " print(3 + 4); ", - " print(3 + \"4\"); ", - " print(\"3\" + 4); ", - " print(\"3\" + \"4\"); ", - " print(3 + 4000000000000); ", - " print(3000000000000 + 4); ", - " print(3000000000000 + 4000000000000); ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "7", - "34", - "34", - "34", - "4000000000003", - "3000000000004", - "7000000000000", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/BuiltinsTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/BuiltinsTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class BuiltinsTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " print(\"Hello World!\"); ", - " time(); ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "Hello World!", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/CallTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/CallTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class CallTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function ret(a) { return a; } ", - "function dub(a) { return a * 2; } ", - "function inc(a) { return a + 1; } ", - "function dec(a) { return a - 1; } ", - "function call(f, v) { return f(v); } ", - "function main { ", - " print(ret(42));", - " print(dub(21));", - " print(inc(41));", - " print(dec(43));", - " print(call(ret, 42));", - " print(call(dub, 21));", - " print(call(inc, 41));", - " print(call(dec, 43));", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "42", - "42", - "42", - "42", - "42", - "42", - "42", - "42", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/ComparisonTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/ComparisonTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class ComparisonTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " print(4 < 20); ", - " print(4 < \"20\"); ", - " print(\"4\" < 20); ", - " print(\"4\" < \"20\"); ", - " print(4 < 20000000000000); ", - " print(4000000000000 < 20); ", - " print(4000000000000 < 20000000000000); ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "true", - "false", - "false", - "false", - "true", - "false", - "true", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/DivTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/DivTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class DivTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " print(4 / 2); ", - " print(4 / 4000000000000); ", - " print(3000000000000 / 3); ", - " print(3000000000000 / 3000000000000); ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "2", - "0", - "1000000000000", - "1", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/FibonacciTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/FibonacciTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import javax.script.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.sl.*; -import com.oracle.truffle.sl.runtime.*; - -// @formatter:off -public class FibonacciTest extends AbstractTest{ - - private static String[] INPUT = new String[] { - "function fib(num) { ", - " if (num < 1) {return 0;}", - " n1 = 0;", - " n2 = 1;", - " i = 1;", - " while (i < num) {", - " next = n2 + n1;", - " n1 = n2;", - " n2 = next;", - " i = i + 1;", - " }", - " return n2;", - "}", - "function main(num) { ", - " return fib(num);", - "} ", - }; - - // java reference - private static int test(int num) { - if (num <= 0) { - return 0; - } - int n1 = 0; - int n2 = 1; - for (int i = 1; i < num; i++) { - final int next = n2 + n1; - n1 = n2; - n2 = next; - } - return n2; - } - - private static final int TEST_VALUE = 42; - private static final int ITERATIONS = 5000; - - @Test - public void test() throws ScriptException { - StringBuilder s = new StringBuilder(); - for (String line : INPUT) { - s.append(line).append("\n"); - } - final SLContext context = new SLContext(System.out); - final Source source = context.getSourceManager().get("(fib test)", s.toString()); - SLScript script = SLScript.create(context, source); - Integer reference = test(TEST_VALUE); - for (int i = 0; i < ITERATIONS; i++) { - if (!reference.equals(script.run(TEST_VALUE))) { - throw new AssertionError(); - } - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopPrintTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopPrintTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class LoopPrintTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " i = 0; ", - " while (i < 1000) { ", - " i = i + 1; ", - " } ", - " print(i); ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "1000", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class LoopTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " i = 0; ", - " while (i < 1000) { ", - " i = i + 1; ", - " } ", - " return i; ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "1000", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/MulTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/MulTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class MulTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " print(3 * 4); ", - " print(3 * 4000000000000); ", - " print(3000000000000 * 4); ", - " print(3000000000000 * 4000000000000); ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "12", - "12000000000000", - "12000000000000", - "12000000000000000000000000", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012, 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.truffle.sl.test; + +import org.junit.*; +import org.junit.runner.*; + +@RunWith(SLTestRunner.class) +@SLTestSuite({"graal/com.oracle.truffle.sl.test/tests", "tests"}) +public class SLSimpleTestSuite { + + public static void main(String[] args) throws Exception { + 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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2012, 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.truffle.sl.test; + +import java.io.*; +import java.nio.charset.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.*; + +import org.junit.*; +import org.junit.internal.*; +import org.junit.runner.*; +import org.junit.runner.manipulation.*; +import org.junit.runner.notification.*; +import org.junit.runners.*; +import org.junit.runners.model.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.source.*; +import com.oracle.truffle.sl.*; +import com.oracle.truffle.sl.runtime.*; +import com.oracle.truffle.sl.test.SLTestRunner.TestCase; + +public final class SLTestRunner extends ParentRunner { + + private static final int REPEATS = 10; + + private static final String SOURCE_SUFFIX = ".sl"; + private static final String INPUT_SUFFIX = ".input"; + private static final String OUTPUT_SUFFIX = ".output"; + + private static final String LF = System.getProperty("line.separator"); + + static class TestCase { + protected final Description name; + protected final Source source; + protected final String testInput; + protected final String expectedOutput; + protected String actualOutput; + + protected TestCase(Class testClass, String name, Source source, String testInput, String expectedOutput) { + this.name = Description.createTestDescription(testClass, name); + this.source = source; + this.testInput = testInput; + this.expectedOutput = expectedOutput; + } + } + + private final SourceManager sourceManager = new SourceManager(); + private final List testCases; + + public SLTestRunner(Class runningClass) throws InitializationError { + super(runningClass); + try { + testCases = createTests(runningClass); + } catch (IOException e) { + throw new InitializationError(e); + } + } + + @Override + protected Description describeChild(TestCase child) { + return child.name; + } + + @Override + protected List getChildren() { + return testCases; + } + + protected List createTests(final Class c) throws IOException, InitializationError { + SLTestSuite suite = c.getAnnotation(SLTestSuite.class); + if (suite == null) { + throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLTestSuite.class.getSimpleName(), c.getName(), SLTestRunner.class.getSimpleName())); + } + + String[] pathes = suite.value(); + + Path root = null; + for (String path : pathes) { + root = FileSystems.getDefault().getPath(path); + if (Files.exists(root)) { + break; + } + } + if (root == null && pathes.length > 0) { + throw new FileNotFoundException(pathes[0]); + } + + final Path rootPath = root; + + final List foundCases = new ArrayList<>(); + Files.walkFileTree(rootPath, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException { + String sourceName = sourceFile.getFileName().toString(); + if (sourceName.endsWith(SOURCE_SUFFIX)) { + String baseName = sourceName.substring(0, sourceName.length() - SOURCE_SUFFIX.length()); + + Path inputFile = sourceFile.resolveSibling(baseName + INPUT_SUFFIX); + String testInput = ""; + if (Files.exists(inputFile)) { + testInput = readAllLines(inputFile); + } + + Path outputFile = sourceFile.resolveSibling(baseName + OUTPUT_SUFFIX); + String expectedOutput = ""; + if (Files.exists(outputFile)) { + expectedOutput = readAllLines(outputFile); + } + + foundCases.add(new TestCase(c, baseName, sourceManager.get(sourceName, readAllLines(sourceFile)), testInput, expectedOutput)); + } + return FileVisitResult.CONTINUE; + } + }); + return foundCases; + } + + private static String readAllLines(Path file) throws IOException { + // fix line feeds for non unix os + StringBuilder outFile = new StringBuilder(); + for (String line : Files.readAllLines(file, Charset.defaultCharset())) { + outFile.append(line).append(LF); + } + return outFile.toString(); + } + + @Override + protected void runChild(TestCase testCase, RunNotifier notifier) { + notifier.fireTestStarted(testCase.name); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + PrintStream printer = new PrintStream(out); + try { + SLContext context = new SLContext(sourceManager, new BufferedReader(new StringReader(repeat(testCase.testInput, REPEATS))), printer); + SLMain.run(context, testCase.source, null, REPEATS); + + String actualOutput = new String(out.toByteArray()); + Assert.assertEquals(repeat(testCase.expectedOutput, REPEATS), actualOutput); + } catch (Throwable ex) { + notifier.fireTestFailure(new Failure(testCase.name, ex)); + } finally { + notifier.fireTestFinished(testCase.name); + } + } + + private static String repeat(String s, int count) { + StringBuilder result = new StringBuilder(s.length() * count); + for (int i = 0; i < count; i++) { + result.append(s); + } + return result.toString(); + } + + public static void runInMain(Class testClass, String[] args) throws InitializationError, NoTestsRemainException { + JUnitCore core = new JUnitCore(); + core.addListener(new TextListener(System.out)); + SLTestRunner suite = new SLTestRunner(testClass); + if (args.length > 0) { + suite.filter(new NameFilter(args[0])); + } + Result r = core.run(suite); + if (!r.wasSuccessful()) { + System.exit(1); + } + } + + private static final class NameFilter extends Filter { + private final String pattern; + + private NameFilter(String pattern) { + this.pattern = pattern.toLowerCase(); + } + + @Override + public boolean shouldRun(Description description) { + return description.getMethodName().toLowerCase().contains(pattern); + } + + @Override + public String describe() { + return "Filter contains " + pattern; + } + } + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestSuite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestSuite.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012, 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.truffle.sl.test; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SLTestSuite { + + /** + * Defines the base path of the test suite. Multiple base pathes can be specified. However only + * the first base that exists is used to lookup the test cases. + */ + String[] value(); + +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SplitOutputStream.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SplitOutputStream.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import java.io.*; - -public class SplitOutputStream extends OutputStream { - - private final OutputStream[] outputs; - - public SplitOutputStream(OutputStream... outputs) { - this.outputs = outputs; - } - - @Override - public void write(int b) throws IOException { - for (OutputStream out : outputs) { - out.write(b); - } - } - - @Override - public void write(byte[] b) throws IOException { - for (OutputStream out : outputs) { - out.write(b); - } - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - for (OutputStream out : outputs) { - out.write(b, off, len); - } - } - - @Override - public void flush() throws IOException { - for (OutputStream out : outputs) { - out.flush(); - } - } - - @Override - public void close() throws IOException { - for (OutputStream out : outputs) { - out.close(); - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SubTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SubTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class SubTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " print(3 - 4); ", - " print(3 - 4000000000000); ", - " print(3000000000000 - 4); ", - " print(3000000000000 - 4000000000000); ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "-1", - "-3999999999997", - "2999999999996", - "-1000000000000", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SumTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SumTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class SumTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { ", - " i = 0; ", - " sum = 0; ", - " while (i < 100000) { ", - " sum = sum + 1000000; ", - " i = i + 1; ", - " } ", - " return sum; ", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "100000000000", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.test; - -import org.junit.*; - -// @formatter:off -public class TernaryTest extends AbstractTest { - - private static String[] INPUT = new String[] { - "function main { " + - " print(#(1 < 2) ? 1 : 2);" + - " print(#(2 < 1) ? 100000000000000 : 1); ", - " print(#(1 < 2) ? 100000000000000 : 1); ", - " print(#(2 < 1) ? \"wrong\" : \"true\");", - " print(#(2 < 1) ? \"wrong\" : 1);", - "} ", - }; - - private static String[] OUTPUT = new String[] { - "1", - "1", - "100000000000000", - "true", - "1", - }; - - @Test - public void test() { - executeSL(INPUT, OUTPUT, false); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Add.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Add.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,7 @@ +7 +34 +34 +34 +4000000000003 +3000000000004 +7000000000000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Add.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Add.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,9 @@ +function main() { + println(3 + 4); + println(3 + "4"); + println("3" + 4); + println("3" + "4"); + println(3 + 4000000000000); + println(3000000000000 + 4); + println(3000000000000 + 4000000000000); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Arithmetic.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Arithmetic.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,10 @@ +5 +1 +-3 +14 +11 +5 +-3 +1 +18 +11 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Arithmetic.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Arithmetic.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,12 @@ +function main() { + println(3 + 4 - 2); + println(3 - 4 + 2); + println(3 - 4 - 2); + println(3 * 4 + 2); + println(3 + 4 * 2); + println(3 + (4 - 2)); + println(3 - (4 + 2)); + println(3 - (4 - 2)); + println(3 * (4 + 2)); + println(3 + (4 * 2)); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Break.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Break.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +942 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Break.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Break.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,10 @@ +function main() { + i = 0; + while (i < 1000) { + if (i >= 942) { + break; + } + i = i + 1; + } + return i; +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Builtins.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Builtins.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Hello World! diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Builtins.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Builtins.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,4 @@ +function main() { + println("Hello World!"); + nanoTime(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/CalcShell.input --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/CalcShell.input Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,15 @@ +i +80 +c +return cur + i; +r +c +if (i <= 2) { return 1; } else { return prev + cur; } +r +i +100 +r +c +if (i == 0) { return 1; } else { return cur * i; } +r +x diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/CalcShell.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/CalcShell.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,35 @@ +available commands: +x: exit +c: define the calculation function with the parameters prev, cur, and i + prev and cur start with 0; i is the loop variable from 0 to n + example: 'return cur + i;' computes the sum of 1 to n + example: 'if (i == 0) { return 1; } else { return cur * i; }' computes the factorial of i + example: 'if (i <= 2) { return 1; } else { return prev + cur; }' computes the nth Fibonacci number +i: define the number of iterations, i.e, the number n in the examples above +r: Run the calculation loop often, and print the first and last result +t: Run the calculation loop a couple of time, and print timing information for each run +h: Print this help message + +cmd> +n> +cmd> +function> +cmd> +** first: 3240 +** last: 3240 +cmd> +function> +cmd> +** first: 23416728348467685 +** last: 23416728348467685 +cmd> +n> +cmd> +** first: 354224848179261915075 +** last: 354224848179261915075 +cmd> +function> +cmd> +** first: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 +** last: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 +cmd> diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/CalcShell.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/CalcShell.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,89 @@ +function iterations() { + return 80; +} + +function calcLoop(n) { + i = 0; + prev = cur = 0; + while (i <= n) { + next = calc(prev, cur, i); + prev = cur; + cur = next; + i = i + 1; + } + return cur; +} + +function timing(n) { + i = 0; + while (i < 20) { + start = nanoTime(); + calcLoop(n); + end = nanoTime(); + i = i + 1; + + println("** run " + i + ": " + (end - start) + " ns"); + } +} + +function run(n) { + firstResult = calcLoop(n); + println("** first: " + firstResult); + i = 0; + while (i < 100) { + calcLoop(n); + i = i + 1; + } + lastResult = calcLoop(n); + println("** last: " + lastResult); + + if (firstResult != lastResult) { + println("ERROR: result not stable"); + } +} + +function help() { + println("available commands:"); + println("x: exit"); + println("c: define the calculation function with the parameters prev, cur, and i"); + println(" prev and cur start with 0; i is the loop variable from 0 to n"); + println(" example: 'return cur + i;' computes the sum of 1 to n"); + println(" example: 'if (i == 0) { return 1; } else { return cur * i; }' computes the factorial of i"); + println(" example: 'if (i <= 2) { return 1; } else { return prev + cur; }' computes the nth Fibonacci number"); + println("i: define the number of iterations, i.e, the number n in the examples above"); + println("r: Run the calculation loop often, and print the first and last result"); + println("t: Run the calculation loop a couple of time, and print timing information for each run"); + println("h: Print this help message"); + println(""); +} + +function main() { + help(); + + while (1 == 1) { + println("cmd>"); + cmd = readln(); + if (cmd == "x" || cmd == "") { + return; + } + if (cmd == "h") { + help(); + } + if (cmd == "c") { + println("function>"); + code = readln(); + defineFunction("function calc(prev, cur, i) { " + code + "}"); + } + if (cmd == "t") { + timing(iterations()); + } + if (cmd == "r") { + run(iterations()); + } + if (cmd == "i") { + println("n>"); + n = readln(); + defineFunction("function iterations() { return " + n + "; }"); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Call.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Call.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,8 @@ +42 +42 +42 +42 +42 +42 +42 +42 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Call.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Call.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,16 @@ +function ret(a) { return a; } +function dub(a) { return a * 2; } +function inc(a) { return a + 1; } +function dec(a) { return a - 1; } +function call(f, v) { return f(v); } + +function main() { + println(ret(42)); + println(dub(21)); + println(inc(41)); + println(dec(43)); + println(call(ret, 42)); + println(call(dub, 21)); + println(call(inc, 41)); + println(call(dec, 43)); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Comparison.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Comparison.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,54 @@ +< +true +false +false +true +false +true +false +false +<= +true +false +true +true +false +true +false +true +> +false +true +false +false +true +false +true +false +>= +false +true +true +false +true +false +true +true +== +false +false +true +false +false +false +false +true +!= +true +true +false +true +true +true +true +false diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Comparison.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Comparison.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,61 @@ +function main() { + println("<"); + println(4 < 20); + println(40 < 2); + println(4 < 4); + println(4 < 200000000000000000000000000); + println(40000000000000000000000000 < 20); + println(40000000000000000000000000 < 200000000000000000000000000); + println(400000000000000000000000000 < 20000000000000000000000000); + println(40000000000000000000000000 < 40000000000000000000000000); + + println("<="); + println(4 <= 20); + println(40 <= 2); + println(4 <= 4); + println(4 <= 200000000000000000000000000); + println(40000000000000000000000000 <= 20); + println(40000000000000000000000000 <= 200000000000000000000000000); + println(400000000000000000000000000 <= 20000000000000000000000000); + println(40000000000000000000000000 <= 40000000000000000000000000); + + println(">"); + println(4 > 20); + println(40 > 2); + println(4 > 4); + println(4 > 200000000000000000000000000); + println(40000000000000000000000000 > 20); + println(40000000000000000000000000 > 200000000000000000000000000); + println(400000000000000000000000000 > 20000000000000000000000000); + println(40000000000000000000000000 > 40000000000000000000000000); + + println(">="); + println(4 >= 20); + println(40 >= 2); + println(4 >= 4); + println(4 >= 200000000000000000000000000); + println(40000000000000000000000000 >= 20); + println(40000000000000000000000000 >= 200000000000000000000000000); + println(400000000000000000000000000 >= 20000000000000000000000000); + println(40000000000000000000000000 >= 40000000000000000000000000); + + println("=="); + println(4 == 20); + println(40 == 2); + println(4 == 4); + println(4 == 200000000000000000000000000); + println(40000000000000000000000000 == 20); + println(40000000000000000000000000 == 200000000000000000000000000); + println(400000000000000000000000000 == 20000000000000000000000000); + println(40000000000000000000000000 == 40000000000000000000000000); + + println("!="); + println(4 != 20); + println(40 != 2); + println(4 != 4); + println(4 != 200000000000000000000000000); + println(40000000000000000000000000 != 20); + println(40000000000000000000000000 != 200000000000000000000000000); + println(400000000000000000000000000 != 20000000000000000000000000); + println(40000000000000000000000000 != 40000000000000000000000000); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/ControlFlow.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/ControlFlow.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +1 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/ControlFlow.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/ControlFlow.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,10 @@ +function foo() {} +function bar() {} + +function main() { + foo(); + if (1 < 2) { + bar(); + return 1; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/DefineFunction.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/DefineFunction.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,2 @@ +42 +38 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/DefineFunction.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/DefineFunction.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,11 @@ +function foo() { + println(test(40, 2)); +} + +function main() { + defineFunction("function test(a, b) { return a + b; }"); + foo(); + + defineFunction("function test(a, b) { return a - b; }"); + foo(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Div.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Div.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,4 @@ +2 +0 +1000000000000 +1 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Div.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Div.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,6 @@ +function main() { + println(4 / 2); + println(4 / 4000000000000); + println(3000000000000 / 3); + println(3000000000000 / 3000000000000); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Fibonacci.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Fibonacci.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,10 @@ +1: 1 +2: 1 +3: 2 +4: 3 +5: 5 +6: 8 +7: 13 +8: 21 +9: 34 +10: 55 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Fibonacci.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Fibonacci.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,21 @@ +function fib(num) { + if (num < 1) {return 0;} + n1 = 0; + n2 = 1; + i = 1; + while (i < num) { + next = n2 + n1; + n1 = n2; + n2 = next; + i = i + 1; + } + return n2; +} + +function main() { + i = 1; + while (i <= 10) { + println(i + ": " + fib(i)); + i = i + 1; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/FunctionLiteral.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/FunctionLiteral.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,2 @@ +42 +38 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/FunctionLiteral.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/FunctionLiteral.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,16 @@ +function add(a, b) { + return a + b; +} + +function sub(a, b) { + return a - b; +} + +function foo(f) { + println(f(40, 2)); +} + +function main() { + foo(add); + foo(sub); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/HelloWorld.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/HelloWorld.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Hello World! diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/HelloWorld.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/HelloWorld.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,3 @@ +function main() { + println("Hello World!"); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Inlining.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Inlining.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +1260000 \ No newline at end of file diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Inlining.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Inlining.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,18 @@ + +function a() {return 42;} +function b() {return a();} +function c() {return b();} +function d() {return c();} +function e() {return c();} +function f() {return c();} +function g() {return d() + e() + f();} + +function main() { + i = 0; + result = 0; + while (i < 10000) { + result = result + g(); + i = i + 1; + } + return result; +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Loop.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Loop.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +1000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Loop.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Loop.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,7 @@ +function main() { + i = 0; + while (i < 1000) { + i = i + 1; + } + return i; +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopCall.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopCall.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +1000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopCall.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopCall.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,20 @@ +function add(a, b) { + return a + b; +} + +function loop(n) { + i = 0; + while (i < n) { + i = add(i, 1); + } + return i; +} + +function main() { + i = 0; + while (i < 20) { + loop(1000); + i = i + 1; + } + println(loop(1000)); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopInvalidate.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopInvalidate.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +1000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopInvalidate.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopInvalidate.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,21 @@ +function add(a, b) { + return a + b; +} + +function loop(n) { + i = 0; + while (i < n) { + i = add(i, 1); + } + return i; +} + +function main() { + i = 0; + while (i < 20) { + loop(1000); + i = i + 1; + } + add("a", "b"); + println(loop(1000)); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +1000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,22 @@ +function add(a, b) { + return a + b; +} + +function loop(n) { + i = 0; + while (i < n) { + i = add(i, 1); + } + return i; +} + +function main() { + add("a", "b"); + + i = 0; + while (i < 20) { + loop(1000); + i = i + 1; + } + println(loop(1000)); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopPrint.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopPrint.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +1000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,16 @@ +function loop(n) { + i = 0; + while (i < n) { + i = i + 1; + } + return i; +} + +function main() { + i = 0; + while (i < 20) { + loop(1000); + i = i + 1; + } + println(loop(1000)); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Mul.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Mul.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,4 @@ +12 +12000000000000 +12000000000000 +12000000000000000000000000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Mul.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Mul.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,6 @@ +function main() { + println(3 * 4); + println(3 * 4000000000000); + println(3000000000000 * 4); + println(3000000000000 * 4000000000000); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Null.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Null.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,7 @@ +null +true +false +false +true +false +true diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Null.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Null.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,13 @@ +/* The easiest way to generate null: a function without a return statement implicitly returns null. */ +function null() { +} + +function main() { + println(null()); + println(null() == null()); + println(null() != null()); + println(null() == 42); + println(null() != 42); + println(null() == "42"); + println(null() != "42"); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/String.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/String.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,10 @@ +snull +snull +sbar +sfoo +nulls +nulls +bars +foos +2 < 4: true +Type error at String.sl line 9 col 36: operation "<" not defined for Number 2, String "4" diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/String.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/String.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,25 @@ +function null() { +} + +function foo() { + return "bar"; +} + +function f(a, b) { + return a + " < " + b + ": " + (a < b); +} + +function main() { + println("s" + null()); + println("s" + null); + println("s" + foo()); + println("s" + foo); + + println(null() + "s"); + println(null() + "s"); + println(foo() + "s"); + println(foo + "s"); + + println(f(2, 4)); + println(f(2, "4")); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Sub.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Sub.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,4 @@ +-1 +-3999999999997 +2999999999996 +-1000000000000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Sub.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Sub.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,6 @@ +function main() { + println(3 - 4); + println(3 - 4000000000000); + println(3000000000000 - 4); + println(3000000000000 - 4000000000000); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Sum.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Sum.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +50005000 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/Sum.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Sum.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,9 @@ +function main() { + i = 0; + sum = 0; + while (i <= 10000) { + sum = sum + i; + i = i + 1; + } + return sum; +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError01.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError01.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Type error at TypeError01.sl line 2 col 5: operation "-" not defined for Number 3, String "4" diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError01.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError01.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,3 @@ +function main() { + 3 - "4"; +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError02.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError02.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Type error at TypeError02.sl line 2 col 6: operation "if" not defined for String "4" diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError02.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError02.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,3 @@ +function main() { + if ("4") { } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError03.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError03.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Type error at TypeError03.sl line 2 col 7: operation "&&" not defined for String "4", ANY diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError03.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError03.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,3 @@ +function main() { + "4" && 4; +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError04.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError04.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Type error at TypeError04.sl line 2 col 11: operation "||" not defined for Boolean false, Number 4 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError04.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError04.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,3 @@ +function main() { + (1 > 2) || 4; +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Type error at TypeError05.sl line 3 col 3: operation "invoke" not defined for Boolean true diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError05.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError05.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,4 @@ +function main() { + f = 1 < 2; + f(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError06.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError06.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Type error: operation "defineFunction" not defined for Number 3 diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError06.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError06.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,3 @@ +function main() { + defineFunction(3); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError07.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError07.output Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,1 @@ +Type error: operation "defineFunction" not defined for NULL diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl.test/tests/error/TypeError07.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError07.sl Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,3 @@ +function main() { + defineFunction(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLException.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,36 @@ +/* + * 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.truffle.sl; + +/** + * SL does not need a sophisticated error checking and reporting mechanism, so all unexpected + * conditions just abort execution. This exception class is used when we abort from within the SL + * implementation. + */ +public class SLException extends RuntimeException { + private static final long serialVersionUID = -6799734410727348507L; + + public SLException(String message) { + super(message); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2012, 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; + +import java.io.*; +import java.math.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.*; +import com.oracle.truffle.sl.builtins.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.nodes.call.*; +import com.oracle.truffle.sl.nodes.controlflow.*; +import com.oracle.truffle.sl.nodes.expression.*; +import com.oracle.truffle.sl.nodes.local.*; +import com.oracle.truffle.sl.parser.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * SL is a simple language to demonstrate and showcase features of Truffle. The implementation is as + * simple and clean as possible in order to help understanding the ideas and concepts of Truffle. + * The language has first class functions, but no object model. + *

+ * SL is dynamically typed, i.e., there are no type names specified by the programmer. SL is + * strongly typed, i.e., there is no automatic conversion between types. If an operation is not + * available for the types encountered at run time, a type error is reported and execution is + * stopped. For example, {@code 4 - "2"} results in a type error because subtraction is only defined + * for numbers. + * + *

+ * Types: + *

    + *
  • Number: arbitrary precision integer numbers. The implementation uses the Java primitive type + * {@code long} to represent numbers that fit into the 64 bit range, and {@link BigInteger} for + * numbers that exceed the range. Using a primitive type such as {@code long} is crucial for + * performance. + *
  • Boolean: implemented as the Java primitive type {@code boolean}. + *
  • String: implemented as the Java standard type {@link String}. + *
  • Function: implementation type {@link SLFunction}. + *
  • Null (with only one value {@code null}): implemented as the singleton + * {@link SLNull#SINGLETON}. + *
+ * The class {@link SLTypes} lists these types for the Truffle DSL, i.e., for type-specialized + * operations that are specified using Truffle DSL annotations. + * + *

+ * Language concepts: + *

    + *
  • Literals for {@link SLBigIntegerLiteralNode numbers} , {@link SLStringLiteralNode strings}, + * and {@link SLFunctionLiteralNode functions}. + *
  • Basic arithmetic, logical, and comparison operations: {@link SLAddNode +}, {@link SLSubNode + * -}, {@link SLMulNode *}, {@link SLDivNode /}, {@link SLLogicalAndNode logical and}, + * {@link SLLogicalOrNode logical or}, {@link SLEqualNode ==}, !=, {@link SLLessThanNode <}, + * {@link SLLessOrEqualNode <=}, >, >=. + *
  • Local variables: local variables must be defined (via a {@link SLWriteLocalVariableNode + * write}) before they can be used (by a {@link SLReadLocalVariableNode read}). Local variables are + * not visible outside of the block where they were first defined. + *
  • 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 SLInvokeNode invocations} are efficiently implemented with + * {@link SLAbstractDispatchNode polymorphic inline caches}. + *
+ * + *

+ * Syntax and parsing:
+ * The syntax is described as an attributed grammar. The {@link Parser} and {@link Scanner} are + * automatically generated by the parser generator Coco/R (available from http://ssw.jku.at/coco/). The grammar contains semantic + * actions that build the AST for a method. To keep these semantic actions short, they are mostly + * calls to the {@link SLNodeFactory} that performs the actual node creation. All functions found in + * the SL source are added to the {@link SLFunctionRegistry}, which is accessible from the + * {@link SLContext}. + * + *

+ * Builtin functions:
+ * Library functions that are available to every SL source without prior definition are called + * builtin functions. They are added to the {@link SLFunctionRegistry} when the {@link SLContext} is + * created. There current builtin functions are + *

    + *
  • {@link SLReadlnBuiltin readln}: Read a String from the {@link SLContext#getInput() standard + * input}. + *
  • {@link SLPrintlnBuiltin println}: Write a value to the {@link SLContext#getOutput() standard + * output}. + *
  • {@link SLNanoTimeBuiltin nanoTime}: Returns the value of a high-resolution time, in + * nanoseconds. + *
  • {@link SLDefineFunctionBuiltin defineFunction}: Parses the functions provided as a String + * argument and adds them to the function registry. Functions that are already defined are replaced + * with the new version. + *
+ */ +public class SLMain { + + /** + * The main entry point. Use the mx command "mx sl" to run it with the correct class path setup. + */ + public static void main(String[] args) throws IOException { + SourceManager sourceManager = new SourceManager(); + + Source source; + if (args.length == 0) { + source = sourceManager.get("stdin", System.in); + } else { + source = sourceManager.get(args[0]); + } + + int repeats = 1; + if (args.length >= 2) { + repeats = Integer.parseInt(args[1]); + } + + SLContext context = new SLContext(sourceManager, new BufferedReader(new InputStreamReader(System.in)), System.out); + run(context, source, System.out, repeats); + } + + /** + * Parse and run the specified SL source. Factored out in a separate method so that it can also + * be used by the unit test harness. + */ + public static void run(SLContext context, Source source, PrintStream logOutput, int repeats) { + if (logOutput != null) { + logOutput.println("== running on " + Truffle.getRuntime().getName()); + } + + /* Parse the SL source file. */ + Parser.parseSL(context, source); + /* Lookup our main entry point, which is per definition always named "main". */ + SLFunction main = context.getFunctionRegistry().lookup("main"); + if (main.getCallTarget() == null) { + throw new SLException("No function main() defined in SL source file."); + } + + /* Change to true if you want to see the AST on the console. */ + boolean printASTToLog = false; + /* Change to dump the AST to IGV over the network. */ + boolean dumpASTToIGV = false; + + printScript("before execution", context, logOutput, printASTToLog, dumpASTToIGV); + try { + for (int i = 0; i < repeats; i++) { + long start = System.nanoTime(); + /* Call the main entry point, without any arguments. */ + try { + Object result = main.getCallTarget().call(null, new SLArguments(new Object[0])); + if (result != SLNull.SINGLETON) { + context.getOutput().println(result); + } + } catch (UnsupportedSpecializationException ex) { + context.getOutput().println(formatTypeError(ex)); + } + long end = System.nanoTime(); + + if (logOutput != null && repeats > 1) { + logOutput.println("== iteration " + (i + 1) + ": " + ((end - start) / 1000000) + " ms"); + } + } + + } finally { + printScript("after execution", context, logOutput, printASTToLog, dumpASTToIGV); + } + } + + /** + * When dumpASTToIGV is true: dumps the AST of all functions to the IGV visualizer, via a socket + * connection. IGV can be started with the mx command "mx igv". + *

+ * When printASTToLog is true: prints the ASTs to the console. + */ + private static void printScript(String groupName, SLContext context, PrintStream logOutput, boolean printASTToLog, boolean dumpASTToIGV) { + if (dumpASTToIGV) { + GraphPrintVisitor graphPrinter = new GraphPrintVisitor(); + graphPrinter.beginGroup(groupName); + for (SLFunction function : context.getFunctionRegistry().getFunctions()) { + RootCallTarget callTarget = function.getCallTarget(); + if (callTarget != null) { + graphPrinter.beginGraph(function.toString()).visit(callTarget.getRootNode()); + } + } + graphPrinter.printToNetwork(true); + } + if (printASTToLog && logOutput != null) { + for (SLFunction function : context.getFunctionRegistry().getFunctions()) { + RootCallTarget callTarget = function.getCallTarget(); + if (callTarget != null) { + logOutput.println("=== " + function); + NodeUtil.printTree(logOutput, callTarget.getRootNode()); + } + } + } + } + + /** + * Provides a user-readable message for run-time type errors. SL is strongly typed, i.e., there + * are no automatic type conversions of values. Therefore, Truffle does the type checking for + * us: if no matching node specialization for the actual values is found, then we have a type + * error. Specialized nodes use the {@link UnsupportedSpecializationException} to report that no + * specialization was found. We therefore just have to convert the information encapsulated in + * this exception in a user-readable form. + */ + private static String formatTypeError(UnsupportedSpecializationException ex) { + StringBuilder result = new StringBuilder(); + result.append("Type error"); + if (ex.getNode() != null && ex.getNode().getSourceSection() != null) { + SourceSection ss = ex.getNode().getSourceSection(); + result.append(" at ").append(ss.getSource().getName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn()); + } + result.append(": operation"); + if (ex.getNode() != null && ex.getNode().getClass().getAnnotation(NodeInfo.class) != null) { + result.append(" \"").append(ex.getNode().getClass().getAnnotation(NodeInfo.class).shortName()).append("\""); + } + result.append(" not defined for"); + + String sep = " "; + for (int i = 0; i < ex.getSuppliedValues().length; i++) { + Object value = ex.getSuppliedValues()[i]; + Node node = ex.getSuppliedNodes()[i]; + if (node != null) { + result.append(sep); + sep = ", "; + + if (value instanceof Long || value instanceof BigInteger) { + result.append("Number ").append(value); + } else if (value instanceof Boolean) { + result.append("Boolean ").append(value); + } else if (value instanceof String) { + result.append("String \"").append(value).append("\""); + } else if (value instanceof SLFunction) { + result.append("Function ").append(value); + } else if (value == SLNull.SINGLETON) { + result.append("NULL"); + } else if (value == null) { + // value is not evaluated because of short circuit evaluation + result.append("ANY"); + } else { + result.append(value); + } + } + } + return result.toString(); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.*; - -@TypeSystemReference(SLTypes.class) -public class SLNode extends Node { - - public SLNode() { - // No source attribution - super(null); - } - - @Override - public String toString() { - return getEncapsulatingSourceSection() != null ? getEncapsulatingSourceSection().toString() : super.toString(); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl; - -import java.math.*; -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.AddNodeFactory; -import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.DivNodeFactory; -import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.MulNodeFactory; -import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.SubNodeFactory; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.parser.*; -import com.oracle.truffle.sl.runtime.*; - -public class SLNodeFactory { - - private final SLContext context; - - private Parser parser; - private FrameDescriptor frameDescriptor; - private TypedNode returnValue; - - private Source source; - private String currentFunctionName; - - public SLNodeFactory(SLContext context) { - this.context = context; - } - - public void setSource(Source source) { - this.source = source; - } - - public void setParser(Parser parser) { - this.parser = parser; - } - - public void startFunction() { - frameDescriptor = new FrameDescriptor(); - } - - public void createFunction(StatementNode body, String name, String[] parameterNames) { - context.getFunctionRegistry().register(name, FunctionRootNode.createFunction(body, frameDescriptor, name, returnValue, parameterNames)); - this.currentFunctionName = name; - this.returnValue = null; - } - - private T assignSource(T node) { - node.assignSourceSection(ParserUtils.createSourceSection(source, currentFunctionName, parser)); - return node; - } - - public TypedNode createLocal(String name) { - return assignSource(new ReadUninitializedNode(context, frameDescriptor.findOrAddFrameSlot(name, FrameSlotKind.Int))); - } - - public TypedNode createStringLiteral(String value) { - return assignSource(new StringLiteralNode(value)); - } - - public TypedNode createAssignment(TypedNode read, TypedNode assignment) { - FrameSlot slot = ((ReadUninitializedNode) read).getSlot(); - return assignSource(WriteLocalNodeFactory.create(slot, assignment)); - } - - public StatementNode createWhile(ConditionNode condition, StatementNode body) { - return assignSource(new WhileNode(condition, body)); - } - - public StatementNode createBlock(List statements) { - return assignSource(new BlockNode(statements.toArray(new StatementNode[statements.size()]))); - } - - public TypedNode createCall(TypedNode function, TypedNode[] parameters) { - return assignSource(CallNode.create(function, parameters)); - } - - public TypedNode createBinary(String operation, TypedNode left, TypedNode right) { - TypedNode binary; - switch (operation) { - case "+": - binary = AddNodeFactory.create(left, right); - break; - case "*": - binary = MulNodeFactory.create(left, right); - break; - case "/": - binary = DivNodeFactory.create(left, right); - break; - case "-": - binary = SubNodeFactory.create(left, right); - break; - case "<": - binary = LessThanNodeFactory.create(left, right); - break; - case "&&": - binary = LogicalAndNodeFactory.create(left, right); - break; - default: - throw new RuntimeException("unexpected operation: " + operation); - } - return assignSource(binary); - } - - public TypedNode createNumericLiteral(String value) { - try { - return assignSource(new IntegerLiteralNode(Integer.parseInt(value))); - } catch (NumberFormatException ex) { - return assignSource(new BigIntegerLiteralNode(new BigInteger(value))); - } - } - - public StatementNode createReturn(TypedNode value) { - FrameSlot slot = frameDescriptor.findOrAddFrameSlot("", FrameSlotKind.Int); - if (returnValue == null) { - returnValue = ReadLocalNodeFactory.create(slot); - } - StatementNode write = WriteLocalNodeFactory.create(slot, value); - return assignSource(new ReturnNode(write)); - } - - public TypedNode createTernary(TypedNode condition, TypedNode thenPart, TypedNode elsePart) { - return assignSource(TernaryNodeFactory.create(condition, thenPart, elsePart)); - } - - public StatementNode createIf(ConditionNode condition, StatementNode then, StatementNode elseNode) { - return assignSource(IfNodeFactory.create(then, elseNode, condition)); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLScript.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLScript.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2012, 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; - -import java.io.*; - -import javax.script.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.sl.parser.*; -import com.oracle.truffle.sl.runtime.*; - -public final class SLScript { - - private final SLContext context; - private final CallTarget main; - - private SLScript(SLContext context, CallTarget mainFunction) { - this.context = context; - this.main = mainFunction; - } - - public SLContext getContext() { - return context; - } - - public CallTarget getMain() { - return main; - } - - public Object run(Object... arguments) { - return main.call(null, new SLArguments(arguments)); - } - - @Override - public String toString() { - return main.toString(); - } - - public static SLScript create(SLContext context, Source source) throws ScriptException { - SLNodeFactory factory = new SLNodeFactory(context); - Parser parser = new Parser(new Scanner(source.getInputStream()), factory); - factory.setParser(parser); - factory.setSource(source); - String error = parser.ParseErrors(); - if (!error.isEmpty()) { - throw new ScriptException(String.format("Error(s) parsing script: %s", error)); - } - - CallTarget main = context.getFunctionRegistry().lookup("main"); - if (main == null) { - throw new ScriptException("No main function found."); - } - return new SLScript(context, main); - } - - public static SLScript create(SLContext context, InputStream input) throws ScriptException { - SLNodeFactory factory = new SLNodeFactory(context); - Parser parser = new Parser(new Scanner(input), factory); - factory.setParser(parser); - factory.setSource(new Source() { - public String getName() { - return "Unknown"; - } - - public String getCode() { - return null; - } - - @Override - public String getPath() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Reader getReader() { - // TODO Auto-generated method stub - return null; - } - - @Override - public InputStream getInputStream() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getCode(int lineNumber) { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getLineCount() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getLineNumber(int offset) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getLineStartOffset(int lineNumber) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getLineLength(int lineNumber) { - // TODO Auto-generated method stub - return 0; - } - }); - String error = parser.ParseErrors(); - if (!error.isEmpty()) { - throw new ScriptException(String.format("Error(s) parsing script: %s", error)); - } - - CallTarget main = context.getFunctionRegistry().lookup("main"); - if (main == null) { - throw new ScriptException("No main function found."); - } - return new SLScript(context, main); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.sl.runtime.*; - -@TypeSystem({int.class, BigInteger.class, boolean.class, String.class, CallTarget.class, SLNull.class, Object[].class}) -public class SLTypes { - - @TypeCheck - public boolean isSLNull(Object value) { - return SLNull.INSTANCE == value; - } - - @TypeCast - public SLNull asSLNull(Object value) { - assert isSLNull(value); - return SLNull.INSTANCE; - } - - @ImplicitCast - public BigInteger castBigInteger(int integer) { - return BigInteger.valueOf(integer); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SimpleLanguage.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SimpleLanguage.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl; - -import java.io.*; - -import javax.script.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -public class SimpleLanguage { - - private static final Object[] NO_ARGUMENTS = new Object[0]; - - public static void main(String[] args) { - run(args[0], System.out, 10, true); - } - - public static void run(String name, String input, PrintStream printOutput, int repeats, boolean log) { - if (log) { - // CheckStyle: stop system..print check - System.out.printf("== running on %s\n", Truffle.getRuntime().getName()); - // CheckStyle: resume system..print check - } - - final SLContext context = new SLContext(printOutput); - final Source source = context.getSourceManager().get(name, input); - - run(context, source, printOutput, repeats, log); - } - - public static void run(String fileName, PrintStream printOutput, int repeats, boolean log) { - if (log) { - // CheckStyle: stop system..print check - System.out.printf("== running on %s\n", Truffle.getRuntime().getName()); - // CheckStyle: resume system..print check - } - - final SLContext context = new SLContext(printOutput); - final Source source = context.getSourceManager().get(fileName); - - run(context, source, printOutput, repeats, log); - } - - public static void run(SLContext context, Source source, PrintStream printOutput, int repeats, boolean log) { - - SLScript script; - try { - script = SLScript.create(context, source); - } catch (ScriptException e) { - // TODO temporary hack - throw new RuntimeException(e); - } - - if (log) { - printScript(script); - } - try { - for (int i = 0; i < repeats; i++) { - long start = System.nanoTime(); - Object result = script.run(NO_ARGUMENTS); - long end = System.nanoTime(); - - if (result != null) { - printOutput.println(result); - } - if (log) { - // CheckStyle: stop system..print check - System.out.printf("== iteration %d: %.3f ms\n", (i + 1), (end - start) / 1000000.0); - // CheckStyle: resume system..print check - } - } - - } finally { - if (log) { - printScript(script); - } - } - } - - private static void printScript(SLScript script) { - NodeUtil.printTree(System.out, ((DefaultCallTarget) script.getMain()).getRootNode()); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/BuiltinNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/BuiltinNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.builtins; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -@NodeField(name = "context", type = SLContext.class) -@NodeChild(value = "arguments", type = TypedNode[].class) -public abstract class BuiltinNode extends TypedNode { - - public abstract SLContext getContext(); - - public abstract TypedNode[] getArguments(); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/DefaultBuiltins.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/DefaultBuiltins.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.builtins; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -public abstract class DefaultBuiltins { - - public static void install(SLContext c) { - installBuiltin(c, PrintBuiltinFactory.getInstance(), "print"); - installBuiltin(c, TimeBuiltinFactory.getInstance(), "time"); - } - - private static void installBuiltin(SLContext context, NodeFactory factory, String name) { - context.getFunctionRegistry().register(name, FunctionRootNode.createBuiltin(context, factory, name)); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/PrintBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/PrintBuiltin.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.builtins; - -import com.oracle.truffle.api.dsl.*; - -public abstract class PrintBuiltin extends BuiltinNode { - - @Specialization - public int doInt(int value) { - getContext().getPrintOutput().println(value); - return value; - } - - @Specialization - public boolean doBoolean(boolean value) { - getContext().getPrintOutput().println(value); - return value; - } - - @Specialization - public String doString(String value) { - getContext().getPrintOutput().println(value); - return value; - } - - @Specialization - public Object doGeneric(Object value) { - getContext().getPrintOutput().println(value.toString()); - return value; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 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.builtins; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Base class for all builtin functions. It contains the Truffle DSL annotation {@link NodeChild} + * that defines the function arguments.
+ * Builtin functions need access to the {@link SLContext}. Instead of defining a Java field manually + * and setting it in a constructor, we use the Truffle DSL annotation {@link NodeField} that + * generates the field and constructor automatically. + *

+ * The builtin functions are registered in {@link SLContext#installBuiltins}. Every builtin node + * subclass is instantiated there, wrapped into a function, and added to the + * {@link SLFunctionRegistry}. This ensures that builtin functions can be called like user-defined + * functions; there is no special function lookup or call node for builtin functions. + */ +@NodeChild(value = "arguments", type = SLExpressionNode[].class) +@NodeField(name = "context", type = SLContext.class) +public abstract class SLBuiltinNode extends SLExpressionNode { + + /** + * Accessor for the {@link SLContext}. The implementation of this method is generated + * automatically based on the {@link NodeField} annotation on the class. + */ + public abstract SLContext getContext(); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 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.builtins; + +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.parser.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Builtin function to define (or redefine) functions. The provided source code is parsed the same + * way as the initial source of the script, so the same syntax applies. + */ +@NodeInfo(shortName = "defineFunction") +public abstract class SLDefineFunctionBuiltin extends SLBuiltinNode { + + @Specialization + public String defineFunction(String code) { + doDefineFunction(getContext(), code); + return code; + } + + @SlowPath + 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); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNanoTimeBuiltin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNanoTimeBuiltin.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, 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.builtins; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Builtin function that returns the value of a high-resolution time, in nanoseconds. + */ +@NodeInfo(shortName = "nanoTime") +public abstract class SLNanoTimeBuiltin extends SLBuiltinNode { + + @Specialization + public long nanoTime() { + return System.nanoTime(); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012, 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.builtins; + +import java.io.*; + +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Builtin function to write a value to the {@link SLContext#getOutput() standard output}. The + * different specialization leverage the typed {@code println} methods available in Java, i.e., + * primitive values are printed without converting them to a {@link String} first. + *

+ * Printing involves a lot of Java code, so we need to tell the optimizing system that it should not + * unconditionally inline everything reachable from the println() method. This is done via the + * {@link SlowPath} annotations. + */ +@NodeInfo(shortName = "println") +public abstract class SLPrintlnBuiltin extends SLBuiltinNode { + + @Specialization + public long println(long value) { + doPrint(getContext().getOutput(), value); + return value; + } + + @SlowPath + private static void doPrint(PrintStream out, long value) { + out.println(value); + } + + @Specialization + public boolean println(boolean value) { + doPrint(getContext().getOutput(), value); + return value; + } + + @SlowPath + private static void doPrint(PrintStream out, boolean value) { + out.println(value); + } + + @Specialization + public String println(String value) { + doPrint(getContext().getOutput(), value); + return value; + } + + @SlowPath + private static void doPrint(PrintStream out, String value) { + out.println(value); + } + + @Specialization + public Object println(Object value) { + doPrint(getContext().getOutput(), value); + return value; + } + + @SlowPath + private static void doPrint(PrintStream out, Object value) { + out.println(value); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLReadlnBuiltin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLReadlnBuiltin.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,61 @@ +/* + * 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.truffle.sl.builtins; + +import java.io.*; + +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Builtin function that reads a String from the {@link SLContext#getInput() standard input}. + */ +@NodeInfo(shortName = "readln") +public abstract class SLReadlnBuiltin extends SLBuiltinNode { + + @Specialization + public String readln() { + String result = doRead(getContext().getInput()); + if (result == null) { + /* + * We do not have a sophisticated end of file handling, so returning an empty string is + * a reasonable alternative. Note that the Java null value should never be used, since + * it can interfere with the specialization logic in generated source code. + */ + result = ""; + } + return result; + } + + @SlowPath + private static String doRead(BufferedReader in) { + try { + return in.readLine(); + } catch (IOException ex) { + throw new SLException(ex.getMessage()); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/TimeBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/TimeBuiltin.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.builtins; - -import com.oracle.truffle.api.dsl.*; - -public abstract class TimeBuiltin extends BuiltinNode { - - public static final long START_TIME = System.currentTimeMillis(); - - @Specialization - public int doInt() { - return (int) (System.currentTimeMillis() - START_TIME); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArgumentsNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArgumentsNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -public final class ArgumentsNode extends TypedNode { - - @Children private final TypedNode[] arguments; - - public ArgumentsNode(TypedNode[] arguments) { - this.arguments = adoptChildren(arguments); - } - - public TypedNode[] getArguments() { - return arguments; - } - - @Override - public Object[] executeGeneric(VirtualFrame frame) { - return executeArray(frame); - } - - @Override - @ExplodeLoop - public Object[] executeArray(VirtualFrame frame) { - Object[] argumentValues = new Object[arguments.length]; - for (int i = 0; i < arguments.length; i++) { - argumentValues[i] = arguments[i].executeGeneric(frame); - } - return argumentValues; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; - -public abstract class ArithmeticNode extends BinaryNode { - - public abstract static class AddNode extends ArithmeticNode { - - @Specialization(rewriteOn = ArithmeticException.class) - int doInt(int left, int right) { - return ExactMath.addExact(left, right); - } - - @Specialization - BigInteger doBigInteger(BigInteger left, BigInteger right) { - return left.add(right); - } - - @Specialization - String doString(String left, String right) { - return left + right; - } - - @Specialization(guards = "isString") - String add(Object left, Object right) { - return left.toString() + right.toString(); - } - } - - public abstract static class SubNode extends ArithmeticNode { - - @Specialization(rewriteOn = ArithmeticException.class) - int sub(int left, int right) { - return ExactMath.subtractExact(left, right); - } - - @Specialization - BigInteger sub(BigInteger left, BigInteger right) { - return left.subtract(right); - } - - } - - public abstract static class DivNode extends ArithmeticNode { - - @Specialization(rewriteOn = ArithmeticException.class) - int div(int left, int right) { - return left / right; - } - - @Specialization - BigInteger div(BigInteger left, BigInteger right) { - return left.divide(right); - } - } - - public abstract static class MulNode extends ArithmeticNode { - - @Specialization(rewriteOn = ArithmeticException.class) - int mul(int left, int right) { - return ExactMath.multiplyExact(left, right); - } - - @Specialization - BigInteger mul(BigInteger left, BigInteger right) { - return left.multiply(right); - } - - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BigIntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BigIntegerLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import java.math.*; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -public final class BigIntegerLiteralNode extends TypedNode { - - private final BigInteger value; - - public BigIntegerLiteralNode(BigInteger value) { - this.value = value; - } - - @Override - public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException { - return value; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BinaryNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BinaryNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.dsl.*; - -@NodeChildren({@NodeChild("leftNode"), @NodeChild("rightNode")}) -public abstract class BinaryNode extends TypedNode { - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BlockNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BlockNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -public class BlockNode extends StatementNode { - - @Children private final StatementNode[] statements; - - public BlockNode(StatementNode[] statements) { - this.statements = adoptChildren(statements); - } - - @Override - @ExplodeLoop - public void executeVoid(VirtualFrame frame) { - for (StatementNode statement : statements) { - statement.executeVoid(frame); - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BreakException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BreakException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.nodes.*; - -public final class BreakException extends ControlFlowException { - - private static final long serialVersionUID = -91013036379258890L; -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BreakNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BreakNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; - -public final class BreakNode extends StatementNode { - - private final BreakException target; - - public BreakNode(BreakException target) { - this.target = target; - } - - @Override - public void executeVoid(VirtualFrame frame) { - throw target; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -public abstract class CallNode extends TypedNode { - - private static final int INLINE_CACHE_SIZE = 2; - - @Child protected TypedNode functionNode; - @Child protected ArgumentsNode argumentsNode; - - public CallNode(TypedNode functionNode, ArgumentsNode argumentsNode) { - this.functionNode = adoptChild(functionNode); - this.argumentsNode = adoptChild(argumentsNode); - } - - @Override - public final Object executeGeneric(VirtualFrame frame) { - CallTarget function; - try { - function = functionNode.executeCallTarget(frame); - } catch (UnexpectedResultException e) { - throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported."); - } - Object[] arguments = argumentsNode.executeArray(frame); - return executeCall(frame, function, arguments); - } - - public abstract Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments); - - public static CallNode create(TypedNode function, TypedNode[] arguments) { - return new UninitializedCallNode(function, new ArgumentsNode(arguments), 0); - } - - private static final class UninitializedCallNode extends CallNode { - - protected final int depth; - - UninitializedCallNode(TypedNode function, ArgumentsNode args, int depth) { - super(function, args); - this.depth = depth; - } - - UninitializedCallNode(UninitializedCallNode copy) { - super(null, null); - this.depth = copy.depth + 1; - } - - @Override - public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) { - CompilerDirectives.transferToInterpreter(); - return specialize(function).executeCall(frame, function, arguments); - } - - private CallNode specialize(CallTarget function) { - CompilerAsserts.neverPartOfCompilation(); - - if (depth < INLINE_CACHE_SIZE) { - DefaultCallTarget callTarget = (DefaultCallTarget) function; - FunctionRootNode root = (FunctionRootNode) callTarget.getRootNode(); - CallNode next = new UninitializedCallNode(this); - InlinableDirectCallNode directCall = new InlinableDirectCallNode(functionNode, argumentsNode, next, callTarget); - replace(directCall); - if (root.isInlineImmediatly()) { - return directCall.inlineImpl(); - } else { - return directCall; - } - } else { - CallNode topMost = (CallNode) NodeUtil.getNthParent(this, depth); - return topMost.replace(new GenericCallNode(topMost.functionNode, topMost.argumentsNode)); - } - } - - } - - private abstract static class DirectCallNode extends CallNode { - - protected final DefaultCallTarget cachedFunction; - - @Child protected CallNode nextNode; - - public DirectCallNode(TypedNode function, ArgumentsNode arguments, DefaultCallTarget cachedFunction, CallNode next) { - super(function, arguments); - this.cachedFunction = cachedFunction; - this.nextNode = adoptChild(next); - } - - @Override - public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) { - if (this.cachedFunction == function) { - return executeCurrent(frame, arguments); - } - return nextNode.executeCall(frame, function, arguments); - } - - protected abstract Object executeCurrent(VirtualFrame frame, Object[] arguments); - - } - - private static final class InlinableDirectCallNode extends DirectCallNode implements InlinableCallSite { - - @CompilationFinal private int callCount; - - InlinableDirectCallNode(TypedNode function, ArgumentsNode arguments, CallNode next, DefaultCallTarget cachedFunction) { - super(function, arguments, cachedFunction, next); - } - - @Override - public Object executeCurrent(VirtualFrame frame, Object[] arguments) { - if (CompilerDirectives.inInterpreter()) { - callCount++; - } - return cachedFunction.call(frame.pack(), new SLArguments(arguments)); - } - - InlinedDirectCallNode inlineImpl() { - CompilerAsserts.neverPartOfCompilation(); - RootNode root = cachedFunction.getRootNode(); - TypedNode inlinedNode = ((FunctionRootNode) root).inline(); - assert inlinedNode != null; - return replace(new InlinedDirectCallNode(this, inlinedNode), "Inlined " + root); - } - - @Override - public boolean inline(FrameFactory factory) { - inlineImpl(); - /* SL is always able to inline if required. */ - return true; - } - - @Override - public int getCallCount() { - return callCount; - } - - @Override - public void resetCallCount() { - callCount = 0; - } - - @Override - public Node getInlineTree() { - RootNode root = cachedFunction.getRootNode(); - if (root instanceof FunctionRootNode) { - return ((FunctionRootNode) root).getUninitializedBody(); - } - return null; - } - - @Override - public CallTarget getCallTarget() { - return cachedFunction; - } - - } - - private static class InlinedDirectCallNode extends DirectCallNode implements InlinedCallSite { - - private final FrameDescriptor descriptor; - @Child private TypedNode inlinedBody; - - InlinedDirectCallNode(InlinableDirectCallNode prev, TypedNode inlinedBody) { - super(prev.functionNode, prev.argumentsNode, prev.cachedFunction, prev.nextNode); - this.descriptor = cachedFunction.getRootNode().getFrameDescriptor(); - this.inlinedBody = adoptChild(inlinedBody); - } - - @Override - public Object executeCurrent(VirtualFrame frame, Object[] arguments) { - SLArguments slArguments = new SLArguments(arguments); - VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), slArguments, descriptor); - return inlinedBody.executeGeneric(newFrame); - } - - @Override - public CallTarget getCallTarget() { - return cachedFunction; - } - - } - - private static final class GenericCallNode extends CallNode { - - GenericCallNode(TypedNode functionNode, ArgumentsNode arguments) { - super(functionNode, arguments); - } - - @Override - public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) { - return function.call(frame.pack(), new SLArguments(arguments)); - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ConditionNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ConditionNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; - -public abstract class ConditionNode extends StatementNode { - - public abstract boolean executeCondition(VirtualFrame frame); - - @Override - public void executeVoid(VirtualFrame frame) { - executeCondition(frame); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ContinueException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ContinueException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.nodes.*; - -public final class ContinueException extends ControlFlowException { - - private static final long serialVersionUID = 5329687983726237188L; -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ContinueNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ContinueNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; - -public final class ContinueNode extends StatementNode { - - private final ContinueException target; - - public ContinueNode(ContinueException target) { - this.target = target; - } - - @Override - public void executeVoid(VirtualFrame frame) { - throw target; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FrameSlotNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FrameSlotNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; - -public abstract class FrameSlotNode extends TypedNode { - - protected final FrameSlot slot; - - public FrameSlotNode(FrameSlot slot) { - this.slot = slot; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionBodyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionBodyNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -public class FunctionBodyNode extends TypedNode { - - @Child private StatementNode body; - @Child private TypedNode returnValue; - @Child private StatementNode writeArguments; - - private FrameDescriptor frameDescriptor; - - public FunctionBodyNode(FrameDescriptor frameDescriptor, StatementNode body, TypedNode returnValue, String[] parameterNames) { - this.frameDescriptor = frameDescriptor; - this.body = adoptChild(body); - this.returnValue = adoptChild(returnValue); - this.writeArguments = adoptChild(new BlockNode(createWriteArguments(parameterNames))); - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - writeArguments.executeVoid(frame); - try { - body.executeVoid(frame); - } catch (ReturnException ex) { - // Nothing to do, we just need to return. - } - if (returnValue != null) { - return returnValue.executeGeneric(frame); - } else { - return null; - } - } - - @Override - public Node copy() { - FunctionBodyNode copy = (FunctionBodyNode) super.copy(); - copy.frameDescriptor = frameDescriptor.shallowCopy(); - return copy; - } - - private StatementNode[] createWriteArguments(String[] parameterNames) { - StatementNode[] writeNodes = new StatementNode[parameterNames.length]; - for (int i = 0; i < parameterNames.length; i++) { - FrameSlot frameSlot = frameDescriptor.findOrAddFrameSlot(parameterNames[i]); - writeNodes[i] = WriteLocalNodeFactory.create(frameSlot, new ReadArgumentNode(i)); - } - return writeNodes; - } - - public FrameDescriptor getFrameDescriptor() { - return frameDescriptor; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionRootNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionRootNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -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.builtins.*; -import com.oracle.truffle.sl.runtime.*; - -public final class FunctionRootNode extends RootNode { - - @Child private TypedNode body; - - private final TypedNode uninitializedBody; - private final String name; - private final boolean inlineImmediatly; - - private FunctionRootNode(FrameDescriptor frameDescriptor, TypedNode body, String name, boolean inlineImmediatly) { - super(null, frameDescriptor); - this.uninitializedBody = NodeUtil.cloneNode(body); - this.body = adoptChild(body); - this.name = name; - this.inlineImmediatly = inlineImmediatly; - } - - public static CallTarget createBuiltin(SLContext context, NodeFactory factory, String name) { - int argumentCount = factory.getExecutionSignature().size(); - TypedNode[] arguments = new TypedNode[argumentCount]; - for (int i = 0; i < arguments.length; i++) { - arguments[i] = new ReadArgumentNode(i); - } - BuiltinNode buitinBody = factory.createNode(arguments, context); - FunctionRootNode root = new FunctionRootNode(new FrameDescriptor(), buitinBody, name, true); - return Truffle.getRuntime().createCallTarget(root); - } - - public static CallTarget createFunction(StatementNode body, FrameDescriptor frameDescriptor, String name, TypedNode returnValue, String[] parameterNames) { - FunctionBodyNode bodyContainer = new FunctionBodyNode(frameDescriptor, body, returnValue, parameterNames); - FunctionRootNode root = new FunctionRootNode(frameDescriptor, bodyContainer, name, false); - return Truffle.getRuntime().createCallTarget(root); - } - - @Override - public Object execute(VirtualFrame frame) { - return body.executeGeneric(frame); - } - - public boolean isInlineImmediatly() { - return inlineImmediatly; - } - - public TypedNode inline() { - return NodeUtil.cloneNode(uninitializedBody); - } - - public Node getUninitializedBody() { - return uninitializedBody; - } - - @Override - public String toString() { - return "function " + name; - } - - public String getName() { - return name; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IfNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IfNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; - -@NodeChild(value = "conditionNode", type = ConditionNode.class) -public abstract class IfNode extends StatementNode { - - @Child private StatementNode thenPartNode; - @Child private StatementNode elsePartNode; - - private final BranchProfile ifBranch = new BranchProfile(); - private final BranchProfile elseBranch = new BranchProfile(); - - public IfNode(StatementNode thenPart, StatementNode elsePart) { - this.thenPartNode = adoptChild(thenPart); - this.elsePartNode = adoptChild(elsePart); - } - - protected IfNode(IfNode node) { - this(node.thenPartNode, node.elsePartNode); - } - - @Specialization - public void doVoid(VirtualFrame frame, boolean condition) { - if (condition) { - ifBranch.enter(); - thenPartNode.executeVoid(frame); - } else { - if (elsePartNode != null) { - elseBranch.enter(); - elsePartNode.executeVoid(frame); - } - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IntegerLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -public final class IntegerLiteralNode extends TypedNode { - - private final int value; - - public IntegerLiteralNode(int value) { - this.value = value; - } - - @Override - public int executeInteger(VirtualFrame frame) throws UnexpectedResultException { - return value; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - return value; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import java.math.*; - -import com.oracle.truffle.api.dsl.*; - -public abstract class LessThanNode extends BinaryNode { - - @Specialization - public boolean doInteger(int left, int right) { - return left < right; - } - - @Specialization - public boolean doBigInteger(BigInteger left, BigInteger right) { - return left.compareTo(right) < 0; - } - - @Specialization(guards = "isString") - public boolean doString(Object left, Object right) { - return left.toString().compareTo(right.toString()) < 0; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LogicalAndNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LogicalAndNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.dsl.*; - -@SuppressWarnings("unused") -public abstract class LogicalAndNode extends BinaryNode { - - @ShortCircuit("rightNode") - public boolean needsRightNode(boolean left) { - return left; - } - - @ShortCircuit("rightNode") - public boolean needsRightNode(Object left) { - return left instanceof Boolean && (Boolean) left; - } - - @Specialization - public boolean doBoolean(boolean left, boolean hasRight, boolean right) { - return hasRight && right; - } - - @Generic - public Object doGeneric(Object left, boolean hasRight, Object right) { - throw new RuntimeException("operation not defined for type " + left.getClass().getSimpleName()); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/NullLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/NullLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.sl.runtime.*; - -public final class NullLiteralNode extends TypedNode { - - @Override - public Object executeGeneric(VirtualFrame frame) { - return executeNull(frame); - } - - @Override - public SLNull executeNull(VirtualFrame frame) { - return SLNull.INSTANCE; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadArgumentNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadArgumentNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.sl.runtime.*; - -public class ReadArgumentNode extends TypedNode { - - private final int index; - - private final BranchProfile outOfBounds = new BranchProfile(); - private final BranchProfile inBounds = new BranchProfile(); - - public ReadArgumentNode(int index) { - this.index = index; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - Object[] args = SLArguments.get(frame).arguments; - if (index < args.length) { - inBounds.enter(); - return args[index]; - } else { - outOfBounds.enter(); - return SLNull.INSTANCE; - } - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadFunctionNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadFunctionNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; -import com.oracle.truffle.sl.runtime.*; - -public final class ReadFunctionNode extends TypedNode { - - private final SLFunctionRegistry registry; - private final String name; - private final BranchProfile invalidFunction = new BranchProfile(); - - public ReadFunctionNode(SLFunctionRegistry registry, String name) { - this.registry = registry; - this.name = name; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - return executeCallTarget(frame); - } - - @Override - public CallTarget executeCallTarget(VirtualFrame frame) { - CallTarget target = registry.lookup(name); - if (target != null) { - return target; - } - invalidFunction.enter(); - throw new RuntimeException("Function with name '" + name + "' not found."); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadLocalNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadLocalNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; - -@PolymorphicLimit(1) -public abstract class ReadLocalNode extends FrameSlotNode { - - public ReadLocalNode(FrameSlot slot) { - super(slot); - } - - public ReadLocalNode(ReadLocalNode specialized) { - this(specialized.slot); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public int doInteger(VirtualFrame frame) throws FrameSlotTypeException { - return frame.getInt(slot); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public boolean doBoolean(VirtualFrame frame) throws FrameSlotTypeException { - return frame.getBoolean(slot); - } - - @Specialization(rewriteOn = {FrameSlotTypeException.class}) - public Object doObject(VirtualFrame frame) throws FrameSlotTypeException { - return frame.getObject(slot); - } - - @Generic - public Object doGeneric(VirtualFrame frame) { - return frame.getValue(slot); - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadUninitializedNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadUninitializedNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.sl.runtime.*; - -public class ReadUninitializedNode extends TypedNode { - - private final SLContext context; - private final FrameSlot slot; - - public ReadUninitializedNode(SLContext context, FrameSlot slot) { - this.context = context; - this.slot = slot; - } - - public FrameSlot getSlot() { - return slot; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - CompilerDirectives.transferToInterpreter(); - Object result = frame.getValue(slot); - String identifier = (String) slot.getIdentifier(); - if (result == null) { - // function access - return replace(new ReadFunctionNode(context.getFunctionRegistry(), identifier)).executeGeneric(frame); - } else { - // local variable access - return replace(ReadLocalNodeFactory.create(slot)).executeGeneric(frame); - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReturnException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReturnException.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.nodes.*; - -public final class ReturnException extends ControlFlowException { - - private static final long serialVersionUID = 4073191346281369231L; -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReturnNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReturnNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; - -public class ReturnNode extends StatementNode { - - private static final ReturnException EXCEPTION = new ReturnException(); - - @Child private StatementNode expr; - - public ReturnNode(StatementNode expr) { - this.expr = adoptChild(expr); - } - - @Override - public void executeVoid(VirtualFrame frame) { - expr.executeVoid(frame); - throw EXCEPTION; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012, 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; + +import com.oracle.truffle.api.dsl.*; + +/** + * Utility base class for operations that take two arguments (per convention called "left" and + * "right"). For concrete subclasses of this class, the Truffle DSL creates two child fields, and + * the necessary constructors and logic to set them. + */ +@NodeChildren({@NodeChild("leftNode"), @NodeChild("rightNode")}) +public abstract class SLBinaryNode extends SLExpressionNode { +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012, 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; + +import java.math.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Base class for all SL nodes that produce a value and therefore benefit from type specialization. + * The annotation {@Link TypeSystemReference} specifies the SL types. Specifying it here + * defines the type system for all subclasses. + */ +@TypeSystemReference(SLTypes.class) +public abstract class SLExpressionNode extends SLStatementNode { + + /** + * The execute method when no specialization is possible. This is the most general case, + * therefore it must be provided by all subclasses. + */ + public abstract Object executeGeneric(VirtualFrame frame); + + /** + * When we use an expression at places where a {@SLStatmentNode statement} is + * already sufficient, the return value is just discarded. + */ + @Override + public void executeVoid(VirtualFrame frame) { + executeGeneric(frame); + } + + /* + * Execute methods for specialized types. They all follow the same pattern: they call the + * generic execution method and then expect a result of their return type. Type-specialized + * subclasses overwrite the appropriate methods. + */ + + public long executeLong(VirtualFrame frame) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectLong(executeGeneric(frame)); + } + + public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectBigInteger(executeGeneric(frame)); + } + + public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectBoolean(executeGeneric(frame)); + } + + public String executeString(VirtualFrame frame) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectString(executeGeneric(frame)); + } + + public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectSLFunction(executeGeneric(frame)); + } + + public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException { + return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame)); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012, 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; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.builtins.*; +import com.oracle.truffle.sl.nodes.controlflow.*; + +/** + * The root of all SL execution trees. It is a Truffle requirement that the tree root extends the + * class {@link RootNode}. This class is used for both builtin and user-defined functions. For + * builtin functions, the {@link #bodyNode} is a subclass of {@link SLBuiltinNode}. For user-defined + * functions, the {@link #bodyNode} is a {@link SLFunctionBodyNode}. + */ +public final class SLRootNode extends RootNode { + + /** The function body that is executed, and specialized during execution. */ + @Child private SLExpressionNode bodyNode; + + /** + * A copy of the uninitialized body. When performing method inlining, it is beneficial to inline + * the unspecialized function body, so that it is specialized in the context of the caller. This + * makes the specializations of the inlined function more precise. + */ + private final SLExpressionNode uninitializedBodyNode; + + /** The name of the function, for printing purposes only. */ + private final String name; + + public SLRootNode(FrameDescriptor frameDescriptor, SLExpressionNode bodyNode, String name) { + super(null, frameDescriptor); + /* Deep copy the body before any specialization occurs during execution. */ + this.uninitializedBodyNode = NodeUtil.cloneNode(bodyNode); + this.bodyNode = adoptChild(bodyNode); + this.name = name; + } + + @Override + public Object execute(VirtualFrame frame) { + return bodyNode.executeGeneric(frame); + } + + @Override + public boolean isSplittable() { + return true; + } + + @Override + public RootNode split() { + return new SLRootNode(getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBodyNode), name); + } + + @Override + public String toString() { + return "root " + name; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, 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; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * The base class of all Truffle nodes for SL. All nodes (even expressions) can be used as + * statements, i.e., without returning a value. The {@link VirtualFrame} provides access to the + * local variables. + */ +public abstract class SLStatementNode extends Node { + + /** + * Execute this node as as statement, where no return value is necessary. + */ + public abstract void executeVoid(VirtualFrame frame); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, 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; + +import java.math.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.sl.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * The type system of SL, as explained in {@link SLMain}. Based on the {@link TypeSystem} + * annotation, the Truffle DSL generates the subclass {@link SLTypesGen} with type test and type + * conversion methods for all types. In this class, we only cover types where the automatically + * generated ones would not be sufficient. + */ +@TypeSystem({long.class, BigInteger.class, boolean.class, String.class, SLFunction.class, SLNull.class}) +public abstract class SLTypes { + + /** + * Example of a manually specified type check that replaces the automatically generated type + * check that the Truffle DSL would generate. For {@link SLNull}, we do not need an + * {@code instanceof} check, because we know that there is only a {@link SLNull#SINGLETON + * singleton} instance. + */ + @TypeCheck + public boolean isSLNull(Object value) { + return value == SLNull.SINGLETON; + } + + /** + * Example of a manually specified type cast that replaces the automatically generated type cast + * that the Truffle DSL would generate. For {@link SLNull}, we do not need an actual cast, + * because we know that there is only a {@link SLNull#SINGLETON singleton} instance. + */ + @TypeCast + public SLNull asSLNull(Object value) { + assert isSLNull(value); + return SLNull.SINGLETON; + } + + /** + * 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) { + return BigInteger.valueOf(value); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/StatementNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/StatementNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.sl.*; - -public abstract class StatementNode extends SLNode { - - public abstract void executeVoid(VirtualFrame frame); - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/StringLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/StringLiteralNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; - -public final class StringLiteralNode extends TypedNode { - - private final String value; - - public StringLiteralNode(String value) { - this.value = value; - } - - @Override - public String executeString(VirtualFrame frame) { - return value; - } - - @Override - public Object executeGeneric(VirtualFrame frame) { - return value; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TernaryNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TernaryNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import java.math.*; - -import com.oracle.truffle.api.dsl.*; - -@SuppressWarnings("unused") -@NodeChildren({@NodeChild(value = "conditionNode", type = ConditionNode.class), @NodeChild("ifPartNode"), @NodeChild("elsePartNode")}) -public abstract class TernaryNode extends TypedNode { - - @ShortCircuit("ifPartNode") - public boolean needsIfPart(boolean condition) { - return condition; - } - - @ShortCircuit("elsePartNode") - public boolean needsElsePart(boolean condition, boolean hasIfPart, Object ifPart) { - return !hasIfPart; - } - - @Specialization - public int doInteger(boolean condition, boolean hasIfPart, int ifPart, boolean hasElsePart, int elsePart) { - return hasIfPart ? ifPart : elsePart; - } - - @Specialization - public BigInteger doBigInteger(boolean condition, boolean hasIfPart, BigInteger ifPart, boolean hasElsePart, BigInteger elsePart) { - return hasIfPart ? ifPart : elsePart; - } - - @Specialization - public Object doObject(boolean condition, boolean hasIfPart, Object ifPart, boolean hasElsePart, Object elsePart) { - return hasIfPart ? ifPart : elsePart; - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import java.math.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.*; -import com.oracle.truffle.sl.runtime.*; - -public abstract class TypedNode extends ConditionNode { - - @Override - public final boolean executeCondition(VirtualFrame frame) { - try { - return executeBoolean(frame); - } catch (UnexpectedResultException ex) { - throw new RuntimeException("Illegal type for condition: " + ex.getResult().getClass().getSimpleName()); - } - } - - public abstract Object executeGeneric(VirtualFrame frame); - - public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.SLTYPES.expectBoolean(executeGeneric(frame)); - } - - public int executeInteger(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.SLTYPES.expectInteger(executeGeneric(frame)); - } - - public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.SLTYPES.expectBigInteger(executeGeneric(frame)); - } - - public String executeString(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.SLTYPES.expectString(executeGeneric(frame)); - } - - public CallTarget executeCallTarget(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.SLTYPES.expectCallTarget(executeGeneric(frame)); - } - - public Object[] executeArray(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.SLTYPES.expectObjectArray(executeGeneric(frame)); - } - - public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException { - return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame)); - } - - @Override - public final void executeVoid(VirtualFrame frame) { - executeGeneric(frame); - } - - public boolean isString(Object a, Object b) { - return a instanceof String || b instanceof String; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WhileNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WhileNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.utilities.*; - -public class WhileNode extends StatementNode { - - @Child private ConditionNode condition; - - @Child private StatementNode body; - - private final BreakException breakTarget; - private final ContinueException continueTarget; - - private final BranchProfile continueMismatch = new BranchProfile(); - private final BranchProfile continueMatch = new BranchProfile(); - private final BranchProfile breakMismatch = new BranchProfile(); - private final BranchProfile breakMatch = new BranchProfile(); - - public WhileNode(ConditionNode condition, StatementNode body) { - this.condition = adoptChild(condition); - this.body = adoptChild(body); - - this.breakTarget = new BreakException(); - this.continueTarget = new ContinueException(); - } - - @Override - public void executeVoid(VirtualFrame frame) { - try { - while (condition.executeCondition(frame)) { - try { - body.executeVoid(frame); - } catch (ContinueException ex) { - if (ex != continueTarget) { - continueMismatch.enter(); - throw ex; - } - continueMatch.enter(); - // Fall through to next loop iteration. - } - } - } catch (BreakException ex) { - if (ex != breakTarget) { - breakMismatch.enter(); - throw ex; - } - breakMatch.enter(); - // Done executing this loop, exit method to execute statement following the loop. - } - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.nodes; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; - -@NodeChild(value = "rightNode", type = TypedNode.class) -public abstract class WriteLocalNode extends FrameSlotNode { - - public WriteLocalNode(FrameSlot slot) { - super(slot); - } - - public WriteLocalNode(WriteLocalNode node) { - this(node.slot); - } - - @Specialization(guards = "isIntKind") - public int write(VirtualFrame frame, int right) { - frame.setInt(slot, right); - return right; - } - - @Specialization(guards = "isBooleanKind") - public boolean write(VirtualFrame frame, boolean right) { - frame.setBoolean(slot, right); - return right; - } - - @Specialization(guards = "isObjectKind") - public Object writeGeneric(VirtualFrame frame, Object right) { - frame.setObject(slot, right); - return right; - } - - protected final boolean isIntKind() { - return isKind(FrameSlotKind.Int); - } - - protected final boolean isBooleanKind() { - return isKind(FrameSlotKind.Boolean); - } - - protected final boolean isObjectKind() { - if (slot.getKind() != FrameSlotKind.Object) { - CompilerDirectives.transferToInterpreter(); - slot.setKind(FrameSlotKind.Object); - } - return true; - } - - private boolean isKind(FrameSlotKind kind) { - return slot.getKind() == kind || initialSetKind(kind); - } - - private boolean initialSetKind(FrameSlotKind kind) { - if (slot.getKind() == FrameSlotKind.Illegal) { - CompilerDirectives.transferToInterpreter(); - slot.setKind(kind); - return true; - } - return false; - } - -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,53 @@ +/* + * 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.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Before a call is executed the first time, the dispatch node is a + * {@link SLUninitializedDispatchNode}. During execution, the call is optimized using a polymorphic + * inline cache, i.e., a chain of {@link SLDirectDispatchNode}s. The chain is terminated by a + * {@link SLUninitializedDispatchNode}. If the chain gets too long (longer than + * {@link #INLINE_CACHE_SIZE}), i.e., if the call is too polymorphic, the whole chain is replaced by + * 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 I}: {@link SLInvokeNode}; {@code U}: + * {@link SLUninitializedDispatchNode}; {@code D}: {@link SLDirectDispatchNode}; {@code G}: + * {@link SLGenericDispatchNode}): + *

    + *
  1. After parsing: {@code I->U} + *
  2. After execution of function {@code f1}: {@code I->D(f1)->U} + *
  3. After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U} + *
  4. After execution of function {@code f3}: {@code I->G} + *
+ * */ +public abstract class SLAbstractDispatchNode extends Node { + + protected static final int INLINE_CACHE_SIZE = 2; + + protected abstract Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments); +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,112 @@ +/* + * 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.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * An entry in the polymorphic inline cache. + */ +final class SLDirectDispatchNode extends SLAbstractDispatchNode { + + /** The cached function. */ + private final SLFunction cachedFunction; + + /** + * {@link CallNode} is part of the Truffle API and handles all the steps necessary for method + * inlining: if the call is executed frequently and the callee is small, then the call is + * inlined, i.e., the call node is replaced with a copy of the callee's AST. + */ + @Child private CallNode callCachedTargetNode; + + /** Assumption that the {@link #callCachedTargetNode} is still valid. */ + private final Assumption cachedTargetStable; + + /** + * The next entry of the polymorphic inline cache, either another {@link SLDirectDispatchNode} + * or a {@link SLUninitializedDispatchNode}. + */ + @Child private SLAbstractDispatchNode nextNode; + + protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { + this.cachedFunction = cachedFunction; + this.callCachedTargetNode = adoptChild(Truffle.getRuntime().createCallNode(cachedFunction.getCallTarget())); + this.cachedTargetStable = cachedFunction.getCallTargetStable(); + this.nextNode = adoptChild(next); + } + + /** + * Perform the inline cache check. If it succeeds, execute the cached + * {@link #cachedTargetStable call target}; if it fails, defer to the next element in the chain. + *

+ * Since SL is a quite simple language, the benefit of the inline cache is quite small: after + * checking that the actual function to be executed is the same as the + * {@link SLDirectDispatchNode#cachedFunction}, we can safely execute the cached call target. + * You can reasonably argue that caching the call target is overkill, since we could just + * retrieve it via {@code function.getCallTarget()}. However, in a more complex language the + * lookup of the call target is usually much more complicated than in SL. In addition, caching + * the call target allows method inlining. + */ + @Override + protected Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments) { + /* + * The inline cache check. Note that cachedFunction must be a final field so that the + * compiler can optimize the check. + */ + if (this.cachedFunction == function) { + /* Inline cache hit, we are safe to execute the cached call target. */ + try { + /* + * Support for function redefinition: When a function is redefined, the call target + * maintained by the SLFunction object is change. To avoid a check for that, we use + * an Assumption that is invalidated by the SLFunction when the change is performed. + * Since checking an assumption is a no-op in compiled code, the line below does not + * add any overhead during optimized execution. + */ + cachedTargetStable.check(); + + /* + * Now we are really ready to perform the call. We use a Truffle CallNode for that, + * because it does all the work for method inlining. + */ + return callCachedTargetNode.call(frame.pack(), arguments); + + } catch (InvalidAssumptionException ex) { + /* + * The function has been redefined. Remove ourself from the polymorphic inline + * cache, so that we fail the check only once. Note that this replacement has subtle + * semantics: we are changing a node in the tree that is currently executed. This is + * only safe because we know that after the call to replace(), there is no more code + * that requires that this node is part of the tree. + */ + replace(nextNode); + /* Execute the next node in the chain by falling out of the if block. */ + } + } + /* Inline cache miss, defer to the next element in the chain. */ + return nextNode.executeDispatch(frame, function, arguments); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,42 @@ +/* + * 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.frame.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such + * calls are not optimized any further, e.g., no method inlining is performed. + */ +final class SLGenericDispatchNode extends SLAbstractDispatchNode { + + @Override + protected Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments) { + /* + * SL has a quite simple call lookup: just ask the function for the current call target, and + * call it. + */ + return function.getCallTarget().call(frame.pack(), arguments); + } +} diff -r d0e82d536325 -r a124cc76cde9 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 Wed Mar 05 19:40:15 2014 -0800 @@ -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 d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,84 @@ +/* + * 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.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * The last entry of a polymorphic inline cache. + */ +final class SLUninitializedDispatchNode extends SLAbstractDispatchNode { + + /** + * When we reach this method, all the previous cache entries did not match the function. If the + * cache is still small enough, we extend it by adding another {@link SLDirectDispatchNode}. If + * the cache reached its maximum size, we replace the whole dispatch chain with a + * {@link SLGenericDispatchNode}. + */ + @Override + protected Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments) { + /* The following code modifies the AST, so compiled code must be invalidated. */ + CompilerDirectives.transferToInterpreterAndInvalidate(); + + /* + * Count the number of SLDirectDispatchNodes we already have in the cache. We walk the chain + * of parent nodes until we hit the SLCallNode. We know that a SLCallNode is always present. + */ + Node cur = this; + int depth = 0; + while (cur.getParent() instanceof SLAbstractDispatchNode) { + cur = cur.getParent(); + depth++; + } + SLInvokeNode invokeNode = (SLInvokeNode) cur.getParent(); + + 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()); + + } 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(); + replacement = new SLDirectDispatchNode(next, function); + /* Replace ourself with the new cache entry. */ + replace(replacement); + + } else { + /* Cache size exceeded, fall back to a single generic dispatch node. */ + replacement = new SLGenericDispatchNode(); + /* Replace the whole chain, not just ourself, with the new generic node. */ + invokeNode.dispatchNode.replace(replacement); + } + + /* + * Execute the newly created node perform the actual dispatch. That saves us from + * duplicating the actual call logic here. + */ + return replacement.executeDispatch(frame, function, arguments); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * A statement node that just executes a list of other statements. + */ +@NodeInfo(shortName = "block") +public final class SLBlockNode extends SLStatementNode { + + /** + * The array of child nodes. The annotation {@link com.oracle.truffle.api.nodes.Node.Children + * Children} informs Truffle that the field contains multiple children. It is a Truffle + * requirement that the field is {@code final} and an array of nodes. + */ + @Children private final SLStatementNode[] bodyNodes; + + public SLBlockNode(SLStatementNode[] bodyNodes) { + /* + * It is a Truffle requirement to call adoptChildren(), which performs all the necessary + * steps to add the new children to the node tree. + */ + this.bodyNodes = adoptChildren(bodyNodes); + } + + /** + * Execute all child statements. The annotation {@link ExplodeLoop} triggers full unrolling of + * the loop during compilation. This allows the {@link SLStatementNode#executeVoid} method of + * all children to be inlined. + */ + @Override + @ExplodeLoop + public void executeVoid(VirtualFrame frame) { + /* + * This assertion illustrates that the arryay length is really a constant during + * compilation. + */ + CompilerAsserts.compilationConstant(bodyNodes.length); + + for (SLStatementNode statement : bodyNodes) { + statement.executeVoid(frame); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.nodes.*; + +/** + * Exception thrown by the {@link SLBreakNode break statement} and caught by the {@link SLWhileNode + * loop statement}. Since the exception is stateless, i.e., has no instance fields, we can use a + * {@link #SINGLETON} to avoid memory allocation during interpretation. + */ +public final class SLBreakException extends ControlFlowException { + + public static final SLBreakException SINGLETON = new SLBreakException(); + + private static final long serialVersionUID = -91013036379258890L; + + /* Prevent instantiation from outside. */ + private SLBreakException() { + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * Implementation of the SL break statement. We need to unwind an unknown number of interpreter + * frames that are between this {@link SLBreakNode} and the {@link SLWhileNode} of the loop we are + * breaking out. This is done by throwing an {@link SLBreakException exception} that is caught by + * the {@link SLWhileNode#executeVoid loop node}. + */ +@NodeInfo(shortName = "break") +public final class SLBreakNode extends SLStatementNode { + + @Override + public void executeVoid(VirtualFrame frame) { + throw SLBreakException.SINGLETON; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.nodes.*; + +/** + * Exception thrown by the {@link SLContinueNode continue statement} and caught by the + * {@link SLWhileNode loop statement}. Since the exception is stateless, i.e., has no instance + * fields, we can use a {@link #SINGLETON} to avoid memory allocation during interpretation. + */ +public final class SLContinueException extends ControlFlowException { + + public static final SLContinueException SINGLETON = new SLContinueException(); + + private static final long serialVersionUID = 5329687983726237188L; + + /* Prevent instantiation from outside. */ + private SLContinueException() { + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * Implementation of the SL continue statement. We need to unwind an unknown number of interpreter + * frames that are between this {@link SLContinueNode} and the {@link SLWhileNode} of the loop we + * are continuing. This is done by throwing an {@link SLContinueException exception} that is caught + * by the {@link SLWhileNode#executeVoid loop node}. + */ +@NodeInfo(shortName = "continue") +public final class SLContinueNode extends SLStatementNode { + + @Override + public void executeVoid(VirtualFrame frame) { + throw SLContinueException.SINGLETON; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.utilities.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * The body of a user-defined SL function. This is the node references by a {@link SLRootNode} for + * user-defined functions. It handles the return value of a function: the {@link SLReturnNode return + * statement} throws an {@link SLReturnException exception} with the return value. This node catches + * the exception. If the method ends without an explicit {@code return}, return the + * {@link SLNull#SINGLETON default null value}. + */ +@NodeInfo(shortName = "body") +public final class SLFunctionBodyNode extends SLExpressionNode { + + /** The body of the function. */ + @Child private SLStatementNode bodyNode; + + /** + * Profiling information, collected by the interpreter, capturing whether the function had an + * {@link SLReturnNode explicit return statement}. This allows the compiler to generate better + * code. + */ + private final BranchProfile exceptionTaken = new BranchProfile(); + private final BranchProfile nullTaken = new BranchProfile(); + + public SLFunctionBodyNode(SLStatementNode bodyNode) { + /* + * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps + * to add the new child to the node tree. + */ + this.bodyNode = adoptChild(bodyNode); + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + try { + /* Execute the function body. */ + bodyNode.executeVoid(frame); + + } catch (SLReturnException ex) { + /* + * In the interpreter, record profiling information that the function has an explicit + * return. + */ + exceptionTaken.enter(); + /* The exception transports the actual return value. */ + return ex.getResult(); + } + + /* + * In the interpreter, record profiling information that the function ends without an + * explicit return. + */ + nullTaken.enter(); + /* Return the default null value. */ + return SLNull.SINGLETON; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.utilities.*; +import com.oracle.truffle.sl.nodes.*; + +@NodeInfo(shortName = "if") +public final class SLIfNode extends SLStatementNode { + + /** + * The condition of the {@code if}. This in a {@link SLExpressionNode} because we require a + * result value. We do not have a node type that can only return a {@code boolean} value, so + * {@link #evaluateCondition executing the condition} can lead to a type error. + */ + @Child private SLExpressionNode conditionNode; + + /** Statement (or {@SLBlockNode block}) executed when the condition is true. */ + @Child private SLStatementNode thenPartNode; + + /** Statement (or {@SLBlockNode block}) executed when the condition is false. */ + @Child private SLStatementNode elsePartNode; + + /** + * Profiling information, collected by the interpreter, capturing whether the then-branch was + * used (analogously for the {@link #elseTaken else-branch}). This allows the compiler to + * generate better code for conditions that are always true or always false. + */ + private final BranchProfile thenTaken = new BranchProfile(); + private final BranchProfile elseTaken = new BranchProfile(); + + public SLIfNode(SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) { + /* + * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps + * to add the new child to the node tree. + */ + this.conditionNode = adoptChild(conditionNode); + this.thenPartNode = adoptChild(thenPartNode); + this.elsePartNode = adoptChild(elsePartNode); + } + + @Override + public void executeVoid(VirtualFrame frame) { + if (evaluateCondition(frame)) { + /* In the interpreter, record profiling information that the then-branch was used. */ + thenTaken.enter(); + /* Execute the then-branch. */ + thenPartNode.executeVoid(frame); + } else { + /* In the interpreter, record profiling information that the else-branch was used. */ + elseTaken.enter(); + /* Execute the else-branch (which is optional according to the SL syntax). */ + if (elsePartNode != null) { + elsePartNode.executeVoid(frame); + } + } + } + + private boolean evaluateCondition(VirtualFrame frame) { + try { + /* + * The condition must evaluate to a boolean value, so we call the boolean-specialized + * execute method. + */ + return conditionNode.executeBoolean(frame); + } catch (UnexpectedResultException ex) { + /* + * The condition evaluated to a non-boolean 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[]{conditionNode}, ex.getResult()); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.nodes.*; + +/** + * Exception thrown by the {@link SLReturnNode return statement} and caught by the + * {@link SLFunctionBodyNode function body}. The exception transports the return value in its + * {@link #result} field. + */ +public final class SLReturnException extends ControlFlowException { + + private static final long serialVersionUID = 4073191346281369231L; + + private final Object result; + + public SLReturnException(Object result) { + this.result = result; + } + + public Object getResult() { + return result; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Implementation of the SL return statement. We need to unwind an unknown number of interpreter + * frames that are between this {@link SLReturnNode} and the {@link SLFunctionBodyNode} of the + * method we are exiting. This is done by throwing an {@link SLReturnException exception} that is + * caught by the {@link SLFunctionBodyNode#executeGeneric function body}. The exception transports + * the return value. + */ +@NodeInfo(shortName = "return") +public final class SLReturnNode extends SLStatementNode { + + @Child private SLExpressionNode valueNode; + + public SLReturnNode(SLExpressionNode valueNode) { + this.valueNode = adoptChild(valueNode); + } + + @Override + public void executeVoid(VirtualFrame frame) { + Object result; + if (valueNode != null) { + result = valueNode.executeGeneric(frame); + } else { + /* Return statement that was not followed by an expression, so return the SL null value. */ + result = SLNull.SINGLETON; + } + throw new SLReturnException(result); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, 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.controlflow; + +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.utilities.*; +import com.oracle.truffle.sl.nodes.*; + +@NodeInfo(shortName = "while") +public final class SLWhileNode extends SLStatementNode { + + /** + * The condition of the loop. This in a {@link SLExpressionNode} because we require a result + * value. We do not have a node type that can only return a {@code boolean} value, so + * {@link #evaluateCondition executing the condition} can lead to a type error. + */ + @Child private SLExpressionNode conditionNode; + + /** Statement (or {@SLBlockNode block}) executed as long as the condition is true. */ + @Child private SLStatementNode bodyNode; + + /** + * Profiling information, collected by the interpreter, capturing whether a {@code continue} + * statement was used in this loop. This allows the compiler to generate better code for loops + * without a {@code continue}. + */ + private final BranchProfile continueTaken = new BranchProfile(); + private final BranchProfile breakTaken = new BranchProfile(); + + public SLWhileNode(SLExpressionNode conditionNode, SLStatementNode bodyNode) { + /* + * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps + * to add the new child to the node tree. + */ + this.conditionNode = adoptChild(conditionNode); + this.bodyNode = adoptChild(bodyNode); + } + + @Override + public void executeVoid(VirtualFrame frame) { + int count = 0; + try { + while (evaluateCondition(frame)) { + try { + /* Execute the loop body. */ + bodyNode.executeVoid(frame); + + if (CompilerDirectives.inInterpreter()) { + /* In the interpreter, profile the the number of loop iteration. */ + count++; + } + } catch (SLContinueException ex) { + /* In the interpreter, record profiling information that the loop uses continue. */ + continueTaken.enter(); + /* Fall through to next loop iteration. */ + } + } + } catch (SLBreakException ex) { + /* In the interpreter, record profiling information that the loop uses break. */ + breakTaken.enter(); + /* Done executing this loop, exit method to execute statement following the loop. */ + + } finally { + if (CompilerDirectives.inInterpreter()) { + /* + * In the interpreter, report the loop count to the Truffle system. It is used for + * compilation and inlining decisions. + */ + getRootNode().reportLoopCount(count); + } + } + } + + private boolean evaluateCondition(VirtualFrame frame) { + try { + /* + * The condition must evaluate to a boolean value, so we call the boolean-specialized + * execute method. + */ + return conditionNode.executeBoolean(frame); + } catch (UnexpectedResultException ex) { + /* + * The condition evaluated to a non-boolean 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[]{conditionNode}, ex.getResult()); + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * SL node that performs the "+" operation, which performs addition on arbitrary precision numbers, + * as well as String concatenation if one of the operands is a String. + *

+ * Type specialization on the input values is essential for the performance. This is achieved via + * node rewriting: specialized subclasses handle just a single type, so that the generic node that + * can handle all types is used only in cases where different types were encountered. The subclasses + * are automatically generated by the Truffle DSL. In addition, a {@link SLAddNodeFactory factory + * class} is generated that provides, e.g., {@link SLAddNodeFactory#create node creation}. + */ +@NodeInfo(shortName = "+") +public abstract class SLAddNode extends SLBinaryNode { + + /** + * Specialization for primitive {@code long} values. This is the fast path of the + * arbitrary-precision arithmetic. We need to check for overflows of the addition, and switch to + * the {@link #add(BigInteger, BigInteger) slow path}. Therefore, we use an + * {@link ExactMath#addExact(long, long) addition method that throws an exception on overflow}. + * The {@code rewriteOn} attribute on the {@link Specialization} annotation automatically + * triggers the node rewriting on the exception. + *

+ * In compiled code, {@link ExactMath#addExact(long, long) addExact} is compiled to efficient + * machine code that uses the processor's overflow flag. Therefore, this method is compiled to + * only two machine code instructions on the fast path. + *

+ * This specialization is automatically selected by the Truffle DSL if both the left and right + * operand are {@code long} values. + */ + @Specialization(rewriteOn = ArithmeticException.class) + protected long add(long left, long right) { + return ExactMath.addExact(left, right); + } + + /** + * This is the slow path of the arbitrary-precision arithmetic. The {@link BigInteger} type of + * Java is doing everything we need. + *

+ * This specialization is automatically selected by the Truffle DSL if both the left and right + * 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. 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) { + return left.add(right); + } + + /** + * Specialization for String concatenation. The SL specification says that String concatenation + * works if either the left or the right operand is a String. The non-string operand is + * converted then automatically converted to a String. + *

+ * To implement these semantics, we tell the Truffle DSL to use a custom guard. The guard + * function is defined in {@link #isString this class}, but could also be in any superclass. + */ + @Specialization(guards = "isString") + protected String add(Object left, Object right) { + return left.toString() + right.toString(); + } + + /** + * Guard for String concatenation: returns true if either the left or the right operand is a + * {@link String}. + */ + protected boolean isString(Object a, Object b) { + return a instanceof String || b instanceof String; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * Constant literal for a arbitrary-precision number that exceeds the range of + * {@link SLLongLiteralNode}. + */ +@NodeInfo(shortName = "const") +public final class SLBigIntegerLiteralNode extends SLExpressionNode { + + private final BigInteger value; + + public SLBigIntegerLiteralNode(BigInteger value) { + this.value = value; + } + + @Override + public BigInteger executeBigInteger(VirtualFrame frame) { + return value; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return value; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * This class is similar to the extensively documented {@link SLAddNode}. Divisions by 0 throw the + * same {@link ArithmeticException exception} as in Java, SL has no special handling for it to keep + * the code simple. + */ +@NodeInfo(shortName = "/") +public abstract class SLDivNode extends SLBinaryNode { + + @Specialization + protected long div(long left, long right) { + /* No overflow is possible on a division. */ + return left / right; + } + + @Specialization + protected BigInteger div(BigInteger left, BigInteger right) { + return left.divide(right); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * The {@code ==} operator of SL is defined on all types. Therefore, we need a + * {@link #equal(Object, Object) generic implementation} that can handle all possible types. But + * since {@code ==} can only return {@code true} when the type of the left and right operand are the + * same, the specializations already cover all possible cases that can return {@code true} and the + * generic case is trivial. + *

+ * Note that we do not need the analogous {@code =!} operator, because we can just + * {@link SLLogicalNotNode negate} the {@code ==} operator. + */ +@NodeInfo(shortName = "==") +public abstract class SLEqualNode extends SLBinaryNode { + + @Specialization + protected boolean equal(long left, long right) { + return left == right; + } + + @Specialization + protected boolean equal(BigInteger left, BigInteger right) { + return left.equals(right); + } + + @Specialization + protected boolean equal(boolean left, boolean right) { + return left == right; + } + + @Specialization + protected boolean equal(String left, String right) { + return left.equals(right); + } + + @Specialization + protected boolean equal(SLFunction left, SLFunction right) { + /* + * Our function registry maintains one canonical SLFunction object per function name, so we + * do not need equals(). + */ + return left == right; + } + + @Specialization + protected boolean equal(SLNull left, SLNull right) { + /* There is only the singleton instance of SLNull, so we do not need equals(). */ + return left == right; + } + + /** + * The {@link Generic} annotation informs the Truffle DSL that this method should be executed + * when no {@link Specialization specialized method} matches. The operand types must be + * {@link Object}. + */ + @Generic + protected boolean equal(Object left, Object right) { + /* + * We covered all the cases that can return true in specializations. If we compare two + * values with different types, no specialization matches and we end up here. + */ + assert !left.equals(right); + return false; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012, 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.expression; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Constant literal for a {@link SLFunction function} value, created when a function name occurs as + * a literal in SL source code. Note that function redefinition can change the {@link CallTarget + * call target} that is executed when calling the function, but the {@link SLFunction} for a name + * never changes. This is guaranteed by the {@link SLFunctionRegistry}. + */ +@NodeInfo(shortName = "func") +public final class SLFunctionLiteralNode extends SLExpressionNode { + + private final SLFunction value; + + public SLFunctionLiteralNode(SLFunction value) { + this.value = value; + } + + @Override + public SLFunction executeFunction(VirtualFrame frame) { + return value; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return value; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * This class is similar to the {@link SLLessThanNode}. + */ +@NodeInfo(shortName = "<=") +public abstract class SLLessOrEqualNode extends SLBinaryNode { + + @Specialization + protected boolean lessOrEqual(long left, long right) { + return left <= right; + } + + @Specialization + protected boolean lessOrEqual(BigInteger left, BigInteger right) { + return left.compareTo(right) <= 0; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * This class is similar to the extensively documented {@link SLAddNode}. The only difference: the + * specialized methods return {@code boolean} instead of the input types. + */ +@NodeInfo(shortName = "<") +public abstract class SLLessThanNode extends SLBinaryNode { + + @Specialization + protected boolean lessThan(long left, long right) { + return left < right; + } + + @Specialization + protected boolean lessThan(BigInteger left, BigInteger right) { + return left.compareTo(right) < 0; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 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.expression; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * This class declares specializations similar to the extensively documented {@link SLAddNode}. It + * uses one additional feature of the Truffle DSL: {@link ShortCircuit}. + *

+ * Logical operations in SL use short circuit evaluation: if the evaluation of the left operand + * already decides the result of the operation, the right operand must not be executed. This is + * expressed in the Truffle DSL via a method annotated with {@link ShortCircuit}, which returns + * whether a child needs to be executed based on the result of already executed children. + */ +@NodeInfo(shortName = "&&") +@SuppressWarnings("unused") +public abstract class SLLogicalAndNode extends SLBinaryNode { + + /** + * This method is called after the left child was evaluated, but before the right child is + * evaluated. The right child is only evaluated when the return value is {code true}. + */ + @ShortCircuit("rightNode") + protected boolean needsRightNode(boolean left) { + return left; + } + + /** + * Similar to {@link #needsRightNode(boolean)}, but for generic cases where the type of the left + * child is not known. + */ + @ShortCircuit("rightNode") + protected boolean needsRightNode(Object left) { + return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue()); + } + + @Specialization + protected boolean doBoolean(boolean left, boolean hasRight, boolean right) { + return left && right; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,41 @@ +/* + * 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.truffle.sl.nodes.expression; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * Example of a simple unary node that uses type specialization. See {@link SLAddNode} for + * information on specializations. + */ +@NodeChild("valueNode") +@NodeInfo(shortName = "!") +public abstract class SLLogicalNotNode extends SLExpressionNode { + + @Specialization + protected boolean doBoolean(boolean value) { + return !value; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 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.expression; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * This class is similar to the {@link SLLogicalAndNode}. + */ +@NodeInfo(shortName = "||") +@SuppressWarnings("unused") +public abstract class SLLogicalOrNode extends SLBinaryNode { + + @ShortCircuit("rightNode") + protected boolean needsRightNode(boolean left) { + return !left; + } + + @ShortCircuit("rightNode") + protected boolean needsRightNode(Object left) { + return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue()); + } + + @Specialization + protected boolean doBoolean(boolean left, boolean hasRight, boolean right) { + return left || right; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012, 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.expression; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * Constant literal for a primitive {@code long} value. The unboxed value can be returned when the + * parent expects a long value and calls {@link SLLongLiteralNode#executeLong}. In the generic case, + * the primitive value is automatically boxed by Java. + */ +@NodeInfo(shortName = "const") +public final class SLLongLiteralNode extends SLExpressionNode { + + private final long value; + + public SLLongLiteralNode(long value) { + this.value = value; + } + + @Override + public long executeLong(VirtualFrame frame) throws UnexpectedResultException { + return value; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return value; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * This class is similar to the extensively documented {@link SLAddNode}. + */ +@NodeInfo(shortName = "*") +public abstract class SLMulNode extends SLBinaryNode { + + @Specialization(rewriteOn = ArithmeticException.class) + protected long mul(long left, long right) { + return ExactMath.multiplyExact(left, right); + } + + @Specialization + protected BigInteger mul(BigInteger left, BigInteger right) { + return left.multiply(right); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 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.expression; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * Constant literal for a String value. + */ +@NodeInfo(shortName = "const") +public final class SLStringLiteralNode extends SLExpressionNode { + + private final String value; + + public SLStringLiteralNode(String value) { + this.value = value; + } + + @Override + public String executeString(VirtualFrame frame) { + return value; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return value; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 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.expression; + +import java.math.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * This class is similar to the extensively documented {@link SLAddNode}. + */ +@NodeInfo(shortName = "-") +public abstract class SLSubNode extends SLBinaryNode { + + @Specialization(rewriteOn = ArithmeticException.class) + protected long sub(long left, long right) { + return ExactMath.subtractExact(left, right); + } + + @Specialization + protected BigInteger sub(BigInteger left, BigInteger right) { + return left.subtract(right); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/demo/SLAddWithoutSpecializationNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/demo/SLAddWithoutSpecializationNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,84 @@ +/* + * 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.truffle.sl.nodes.expression.demo; + +import java.math.*; + +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.nodes.expression.*; + +/** + * This is an example how the add operation would be implemented without specializations and without + * the Truffle DSL. Do not write such code in your language! See {@link SLAddNode} how the add + * operation is implemented correctly. + */ +public class SLAddWithoutSpecializationNode extends SLExpressionNode { + + @Child private SLExpressionNode leftNode; + @Child private SLExpressionNode rightNode; + + public SLAddWithoutSpecializationNode(SLExpressionNode leftNode, SLExpressionNode rightNode) { + this.leftNode = adoptChild(leftNode); + this.rightNode = adoptChild(rightNode); + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + /* Evaluate the child nodes. */ + Object left = leftNode.executeGeneric(frame); + Object right = rightNode.executeGeneric(frame); + + if (left instanceof Long && right instanceof Long) { + /* Fast path of the arbitrary-precision arithmetic. We need to check for overflows */ + try { + return ExactMath.addExact((Long) left, (Long) right); + } catch (ArithmeticException ex) { + /* Fall through to BigInteger case. */ + } + } + + /* Implicit type conversions. */ + if (left instanceof Long) { + left = BigInteger.valueOf((Long) left); + } + if (right instanceof Long) { + right = BigInteger.valueOf((Long) right); + } + if (left instanceof BigInteger && right instanceof BigInteger) { + /* Slow path of the arbitrary-precision arithmetic. */ + return ((BigInteger) left).add((BigInteger) right); + } + + /* String concatenation if either the left or the right operand is a String. */ + if (left instanceof String || right instanceof String) { + return left.toString() + right.toString(); + } + + /* Type error. */ + throw new UnsupportedSpecializationException(this, new Node[]{leftNode, rightNode}, new Object[]{left, right}); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 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.local; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.utilities.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.parser.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Reads a function argument. Arguments are passed in as a {@link SLArguments} object, which + * encapsulates an {@link SLArguments#getFromFrame Object[] array}. Language-defined subclasses of + * {@link Arguments} are the standard Truffle way to pass values between functions. + *

+ * Arguments are not type-specialized. To ensure that repeated accesses within a method are + * specialized and can, e.g., be accessed without unboxing, all arguments are loaded into local + * variables {@link SLNodeFactory#addFormalParameter in the method prologue}. + */ +public class SLReadArgumentNode extends SLExpressionNode { + + /** The argument number, i.e., the index into the array of arguments. */ + private final int index; + + /** + * Profiling information, collected by the interpreter, capturing whether the function was + * called with fewer actual arguments than formal arguments. + */ + private final BranchProfile outOfBoundsTaken = new BranchProfile(); + + public SLReadArgumentNode(int index) { + this.index = index; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + Object[] args = SLArguments.getFromFrame(frame); + if (index < args.length) { + return args[index]; + } else { + /* In the interpreter, record profiling information that the branch was used. */ + outOfBoundsTaken.enter(); + /* Use the default null value. */ + return SLNull.SINGLETON; + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 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.local; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * Node to read a local variable from a function's {@link VirtualFrame frame}. The Truffle frame API + * allows to store primitive values of all Java primitive types, and Object values. This means that + * all SL types that are objects are handled by the {@link #readObject} method. When a local + * variable changes its type, the frame access method throws an {@link FrameSlotTypeException}, + * which causes not rewriting. The rewriting code is generated by the Truffle DSL. + */ +@NodeField(name = "slot", type = FrameSlot.class) +public abstract class SLReadLocalVariableNode extends SLExpressionNode { + + /** + * Returns the descriptor of the accessed local variable. The implementation of this method is + * created by the Truffle DSL based on the {@link NodeField} annotation on the class. + */ + protected abstract FrameSlot getSlot(); + + @Specialization(rewriteOn = FrameSlotTypeException.class) + protected long readLong(VirtualFrame frame) throws FrameSlotTypeException { + return frame.getLong(getSlot()); + } + + @Specialization(rewriteOn = FrameSlotTypeException.class) + protected boolean readBoolean(VirtualFrame frame) throws FrameSlotTypeException { + return frame.getBoolean(getSlot()); + } + + @Specialization(order = 1, rewriteOn = FrameSlotTypeException.class) + protected Object readObject(VirtualFrame frame) throws FrameSlotTypeException { + return frame.getObject(getSlot()); + } + + /** + * This is the generic case that always succeeds. Since we already have another specialization + * with the same signature above, we need to order them explicitly with the order attribute. + */ + @Specialization(order = 2) + protected Object read(VirtualFrame frame) { + return frame.getValue(getSlot()); + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012, 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.local; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.sl.nodes.*; + +/** + * 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("valueNode") +@NodeField(name = "slot", type = FrameSlot.class) +public abstract class SLWriteLocalVariableNode extends SLExpressionNode { + + /** + * Returns the descriptor of the accessed local variable. The implementation of this method is + * created by the Truffle DSL based on the {@link NodeField} annotation on the class. + */ + protected abstract FrameSlot getSlot(); + + /** + * Specialized method to write a primitive {@code long} value. This is only possible if the + * local variable also has currently the type {@code long}, therefore a Truffle DSL + * {@link #isLongKind() custom guard} is specified. + */ + @Specialization(guards = "isLongKind") + protected long write(VirtualFrame frame, long value) { + frame.setLong(getSlot(), value); + return value; + } + + @Specialization(guards = "isBooleanKind") + protected boolean write(VirtualFrame frame, boolean value) { + frame.setBoolean(getSlot(), value); + return value; + } + + /** + * Generic write method that works for all possible types. + *

+ * Why is this method annotated with {@link Specialization} and not {@link Generic}? For a + * {@link Generic} method, the Truffle DSL generated code would try all other specializations + * first before calling this method. We know that all these specializations would fail their + * guards, so there is no point in calling them. Since this method takes a value of type + * {@link Object}, it is guaranteed to never fail, i.e., once we are in this specialization the + * node will never be re-specialized. + */ + @Specialization + protected Object write(VirtualFrame frame, Object value) { + if (getSlot().getKind() != FrameSlotKind.Object) { + /* + * The local variable has still a primitive type, we need to change it to Object. Since + * the variable type is important when the compiler optimizes a method, we also discard + * compiled code. + */ + CompilerDirectives.transferToInterpreterAndInvalidate(); + getSlot().setKind(FrameSlotKind.Object); + } + frame.setObject(getSlot(), value); + return value; + } + + /** + * Guard function that the local variable has the type {@code long}. + */ + protected boolean isLongKind() { + return isKind(FrameSlotKind.Long); + } + + protected boolean isBooleanKind() { + return isKind(FrameSlotKind.Boolean); + } + + private boolean isKind(FrameSlotKind kind) { + if (getSlot().getKind() == kind) { + /* Success: the frame slot has the expected kind. */ + return true; + } else if (getSlot().getKind() == FrameSlotKind.Illegal) { + /* + * This is the first write to this local variable. We can set the type to the one we + * expect. Since the variable type is important when the compiler optimizes a method, we + * also discard compiled code. + */ + CompilerDirectives.transferToInterpreterAndInvalidate(); + getSlot().setKind(kind); + return true; + } else { + /* + * Failure: the frame slot has the wrong kind, the Truffle DSL generated code will + * choose a different specialization. + */ + return false; + } + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Copyright.frame --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Copyright.frame Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Copyright.frame Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -21,5 +21,4 @@ * questions. */ - // The content of this file is automatically generated. DO NOT EDIT. - +// The content of this file is automatically generated. DO NOT EDIT. diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame Wed Mar 05 19:40:15 2014 -0800 @@ -30,8 +30,10 @@ import java.util.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; // Checkstyle: stop // @formatter:off @@ -49,9 +51,9 @@ public final Errors errors; private final SLNodeFactory factory; -->declarations - public Parser(Scanner scanner, SLNodeFactory factory) { - this.scanner = scanner; - this.factory = factory; + public Parser(SLContext context, Source source) { + this.scanner = new Scanner(source.getInputStream()); + this.factory = new SLNodeFactory(context, source); errors = new Errors(); } @@ -132,28 +134,22 @@ -->initialization }; - public String ParseErrors() { - java.io.PrintStream oldStream = System.out; - - java.io.OutputStream out = new java.io.ByteArrayOutputStream(); - java.io.PrintStream newStream = new java.io.PrintStream(out); - - errors.errorStream = newStream; - - Parse(); - - String errorStream = out.toString(); - errors.errorStream = oldStream; - - return errorStream; - + public static void parseSL(SLContext context, Source source) { + Parser parser = new Parser(context, source); + parser.Parse(); + if (parser.errors.errors.size() > 0) { + StringBuilder msg = new StringBuilder("Error(s) parsing script:\n"); + for (String error : parser.errors.errors) { + msg.append(error).append("\n"); + } + throw new SLException(msg.toString()); + } } } // end Parser class Errors { - public int count = 0; // number of errors detected - public java.io.PrintStream errorStream = System.out; // error messages go to this stream + protected final List errors = new ArrayList<>(); public String errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text protected void printMsg(int line, int column, String msg) { @@ -171,7 +167,7 @@ pos = b.indexOf("{2}"); if (pos >= 0) b.replace(pos, pos + 3, msg); - errorStream.println(b.toString()); + errors.add(b.toString()); } public void SynErr(int line, int col, int n) { @@ -182,17 +178,14 @@ break; } printMsg(line, col, s); - count++; } public void SemErr(int line, int col, String s) { printMsg(line, col, s); - count++; } public void SemErr(String s) { - errorStream.println(s); - count++; + errors.add(s); } public void Warning(int line, int col, String s) { @@ -200,7 +193,7 @@ } public void Warning(String s) { - errorStream.println(s); + errors.add(s); } } // Errors diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -27,8 +27,10 @@ import java.util.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.runtime.*; // Checkstyle: stop // @formatter:off @@ -37,7 +39,7 @@ public static final int _identifier = 1; public static final int _stringLiteral = 2; public static final int _numericLiteral = 3; - public static final int maxT = 29; + public static final int maxT = 30; static final boolean T = true; static final boolean x = false; @@ -51,9 +53,9 @@ public final Errors errors; private final SLNodeFactory factory; - public Parser(Scanner scanner, SLNodeFactory factory) { - this.scanner = scanner; - this.factory = factory; + public Parser(SLContext context, Source source) { + this.scanner = new Scanner(source.getInputStream()); + this.factory = new SLNodeFactory(context, source); errors = new Errors(); } @@ -130,113 +132,146 @@ void Function() { Expect(4); - factory.startFunction(); Expect(1); - String name = t.val; - List parameterNames = new ArrayList<>(); - if (la.kind == 5) { + factory.startFunction(t); + Expect(5); + if (la.kind == 1) { Get(); - if (la.kind == 1) { - Get(); - parameterNames.add(t.val); - } + factory.addFormalParameter(t); while (la.kind == 6) { Get(); Expect(1); - parameterNames.add(t.val); + factory.addFormalParameter(t); } - Expect(7); } - StatementNode body = Block(); - factory.createFunction(body, name, parameterNames.toArray(new String[parameterNames.size()])); + Expect(7); + SLStatementNode body = Block(false); + factory.finishFunction(body); } - StatementNode Block() { - StatementNode result; - List statements = new ArrayList<>(); + SLStatementNode Block(boolean inLoop) { + SLStatementNode result; + factory.startBlock(); + List body = new ArrayList<>(); Expect(8); while (StartOf(1)) { - StatementNode statement = Statement(); - statements.add(statement); + SLStatementNode s = Statement(inLoop); + body.add(s); } Expect(9); - result = factory.createBlock(statements); + result = factory.finishBlock(body); return result; } - StatementNode Statement() { - StatementNode result; + SLStatementNode Statement(boolean inLoop) { + SLStatementNode result; result = null; - if (la.kind == 13) { + switch (la.kind) { + case 13: { result = WhileStatement(); - } else if (la.kind == 11) { - result = IfStatement(); - } else if (la.kind == 14) { + break; + } + case 10: { + Get(); + if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } + Expect(11); + break; + } + case 12: { + Get(); + if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } + Expect(11); + break; + } + case 14: { + result = IfStatement(inLoop); + break; + } + case 16: { result = ReturnStatement(); - } else if (StartOf(2)) { + break; + } + case 1: case 2: case 3: case 5: { result = Expression(); - Expect(10); - } else SynErr(30); + Expect(11); + break; + } + default: SynErr(31); break; + } return result; } - StatementNode WhileStatement() { - StatementNode result; + SLStatementNode WhileStatement() { + SLStatementNode result; Expect(13); Expect(5); - ConditionNode condition = Expression(); + Token whileToken = t; + SLExpressionNode condition = Expression(); Expect(7); - StatementNode body = Block(); - result = factory.createWhile(condition, body); + SLStatementNode body = Block(true); + result = factory.createWhile(whileToken, condition, body); return result; } - StatementNode IfStatement() { - StatementNode result; - Expect(11); + SLStatementNode IfStatement(boolean inLoop) { + SLStatementNode result; + Expect(14); Expect(5); - ConditionNode condition = Expression(); + Token ifToken = t; + SLExpressionNode condition = Expression(); Expect(7); - StatementNode thenNode = null; StatementNode elseNode = null; - thenNode = Block(); - if (la.kind == 12) { + SLStatementNode thenPart = Block(inLoop); + SLStatementNode elsePart = null; + if (la.kind == 15) { Get(); - elseNode = Block(); + elsePart = Block(inLoop); } - result = factory.createIf(condition, thenNode, elseNode); + result = factory.createIf(ifToken, condition, thenPart, elsePart); return result; } - StatementNode ReturnStatement() { - StatementNode result; - Expect(14); - TypedNode value = Expression(); - Expect(10); - result = factory.createReturn(value); + SLStatementNode ReturnStatement() { + SLStatementNode result; + Expect(16); + Token returnToken = t; + SLExpressionNode value = null; + if (StartOf(2)) { + value = Expression(); + } + result = factory.createReturn(returnToken, value); + Expect(11); return result; } - TypedNode Expression() { - TypedNode result; - result = ValueExpression(); + SLExpressionNode Expression() { + SLExpressionNode result; + result = LogicTerm(); + while (la.kind == 17) { + Get(); + Token op = t; + SLExpressionNode right = LogicTerm(); + result = factory.createBinary(op, result, right); + } + return result; + } + + SLExpressionNode LogicTerm() { + SLExpressionNode result; + result = LogicFactor(); + while (la.kind == 18) { + Get(); + Token op = t; + SLExpressionNode right = LogicFactor(); + result = factory.createBinary(op, result, right); + } + return result; + } + + SLExpressionNode LogicFactor() { + SLExpressionNode result; + result = Arithmetic(); if (StartOf(3)) { switch (la.kind) { - case 15: { - Get(); - break; - } - case 16: { - Get(); - break; - } - case 17: { - Get(); - break; - } - case 18: { - Get(); - break; - } case 19: { Get(); break; @@ -245,130 +280,101 @@ Get(); break; } + case 21: { + Get(); + break; } - String op = t.val; - TypedNode right = ValueExpression(); + case 22: { + Get(); + break; + } + case 23: { + Get(); + break; + } + case 24: { + Get(); + break; + } + } + Token op = t; + SLExpressionNode right = Arithmetic(); result = factory.createBinary(op, result, right); } return result; } - TypedNode ValueExpression() { - TypedNode result; + SLExpressionNode Arithmetic() { + SLExpressionNode result; result = Term(); - while (la.kind == 21 || la.kind == 22) { - if (la.kind == 21) { + while (la.kind == 25 || la.kind == 26) { + if (la.kind == 25) { Get(); } else { Get(); } - String op = t.val; - TypedNode right = Term(); - result = factory.createBinary(op, result, right); - } - return result; - } - - TypedNode Term() { - TypedNode result; - result = Factor(); - while (la.kind == 23 || la.kind == 24) { - if (la.kind == 23) { - Get(); - } else { - Get(); - } - String op = t.val; - TypedNode right = Factor(); + Token op = t; + SLExpressionNode right = Term(); result = factory.createBinary(op, result, right); } return result; } - TypedNode Factor() { - TypedNode result; - result = null; - if (la.kind == 1) { - result = VariableRefOrCall(); - } else if (la.kind == 2) { - result = StringLiteral(); - } else if (la.kind == 3) { - result = NumericLiteral(); - } else if (la.kind == 25) { - result = Ternary(); - } else if (la.kind == 5) { - Get(); - result = Expression(); - Expect(7); - } else SynErr(31); - return result; - } - - TypedNode VariableRefOrCall() { - TypedNode result; - result = VariableRef(); - if (la.kind == 5 || la.kind == 28) { - if (la.kind == 5) { - TypedNode[] parameters = Parameters(); - result = factory.createCall(result, parameters); + SLExpressionNode Term() { + SLExpressionNode result; + result = Factor(); + while (la.kind == 27 || la.kind == 28) { + if (la.kind == 27) { + Get(); } else { Get(); - TypedNode assignment = Expression(); - result = factory.createAssignment(result, assignment); } + Token op = t; + SLExpressionNode right = Factor(); + result = factory.createBinary(op, result, right); } return result; } - TypedNode StringLiteral() { - TypedNode result; - Expect(2); - result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); - return result; - } - - TypedNode NumericLiteral() { - TypedNode result; - Expect(3); - result = factory.createNumericLiteral(t.val); - return result; - } - - TypedNode Ternary() { - TypedNode result; - TypedNode condition, thenPart, elsePart; - Expect(25); - condition = Expression(); - Expect(26); - thenPart = Expression(); - Expect(27); - elsePart = Expression(); - result = factory.createTernary(condition, thenPart, elsePart); - return result; - } - - TypedNode VariableRef() { - TypedNode result; - Expect(1); - result = factory.createLocal(t.val); - return result; - } - - TypedNode[] Parameters() { - TypedNode[] result; - Expect(5); - List parameters = new ArrayList<>(); - if (StartOf(2)) { - TypedNode e1 = Expression(); - parameters.add(e1); - while (la.kind == 6) { + SLExpressionNode Factor() { + SLExpressionNode result; + result = null; + if (la.kind == 1) { + Get(); + Token nameToken = t; + if (la.kind == 5) { Get(); - TypedNode e2 = Expression(); - parameters.add(e2); - } - } - result = parameters.toArray(new TypedNode[parameters.size()]); - Expect(7); + List parameters = new ArrayList<>(); + SLExpressionNode parameter; + if (StartOf(2)) { + parameter = Expression(); + parameters.add(parameter); + while (la.kind == 6) { + Get(); + parameter = Expression(); + parameters.add(parameter); + } + } + result = factory.createCall(nameToken, parameters); + Expect(7); + } else if (la.kind == 29) { + Get(); + SLExpressionNode value = Expression(); + result = factory.createAssignment(nameToken, value); + } else if (StartOf(4)) { + result = factory.createRead(nameToken); + } else SynErr(32); + } else if (la.kind == 2) { + Get(); + result = factory.createStringLiteral(t); + } else if (la.kind == 3) { + Get(); + result = factory.createNumericLiteral(t); + } else if (la.kind == 5) { + Get(); + result = Expression(); + Expect(7); + } else SynErr(33); return result; } @@ -384,35 +390,30 @@ } private static final boolean[][] set = { - {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,T,T,T, x,T,x,x, x,x,x,T, x,T,T,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x}, - {x,T,T,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x}, - {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x} + {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}, + {x,T,T,T, x,T,x,x, x,x,T,x, T,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}, + {x,T,T,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}, + {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,x,x,x, x,x,x,x}, + {x,x,x,x, x,x,T,T, x,x,x,T, x,x,x,x, x,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x} }; - public String ParseErrors() { - java.io.PrintStream oldStream = System.out; - - java.io.OutputStream out = new java.io.ByteArrayOutputStream(); - java.io.PrintStream newStream = new java.io.PrintStream(out); - - errors.errorStream = newStream; - - Parse(); - - String errorStream = out.toString(); - errors.errorStream = oldStream; - - return errorStream; - + public static void parseSL(SLContext context, Source source) { + Parser parser = new Parser(context, source); + parser.Parse(); + if (parser.errors.errors.size() > 0) { + StringBuilder msg = new StringBuilder("Error(s) parsing script:\n"); + for (String error : parser.errors.errors) { + msg.append(error).append("\n"); + } + throw new SLException(msg.toString()); + } } } // end Parser class Errors { - public int count = 0; // number of errors detected - public java.io.PrintStream errorStream = System.out; // error messages go to this stream + protected final List errors = new ArrayList<>(); public String errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text protected void printMsg(int line, int column, String msg) { @@ -430,7 +431,7 @@ pos = b.indexOf("{2}"); if (pos >= 0) b.replace(pos, pos + 3, msg); - errorStream.println(b.toString()); + errors.add(b.toString()); } public void SynErr(int line, int col, int n) { @@ -446,44 +447,43 @@ case 7: s = "\")\" expected"; break; case 8: s = "\"{\" expected"; break; case 9: s = "\"}\" expected"; break; - case 10: s = "\";\" expected"; break; - case 11: s = "\"if\" expected"; break; - case 12: s = "\"else\" expected"; break; + case 10: s = "\"break\" expected"; break; + case 11: s = "\";\" expected"; break; + case 12: s = "\"continue\" expected"; break; case 13: s = "\"while\" expected"; break; - case 14: s = "\"return\" expected"; break; - case 15: s = "\"<\" expected"; break; - case 16: s = "\">\" expected"; break; - case 17: s = "\"<=\" expected"; break; - case 18: s = "\">=\" expected"; break; - case 19: s = "\"==\" expected"; break; - case 20: s = "\"!=\" expected"; break; - case 21: s = "\"+\" expected"; break; - case 22: s = "\"-\" expected"; break; - case 23: s = "\"*\" expected"; break; - case 24: s = "\"/\" expected"; break; - case 25: s = "\"#\" expected"; break; - case 26: s = "\"?\" expected"; break; - case 27: s = "\":\" expected"; break; - case 28: s = "\"=\" expected"; break; - case 29: s = "??? expected"; break; - case 30: s = "invalid Statement"; break; - case 31: s = "invalid Factor"; break; + case 14: s = "\"if\" expected"; break; + case 15: s = "\"else\" expected"; break; + case 16: s = "\"return\" expected"; break; + case 17: s = "\"||\" expected"; break; + case 18: s = "\"&&\" expected"; break; + case 19: s = "\"<\" expected"; break; + case 20: s = "\"<=\" expected"; break; + case 21: s = "\">\" expected"; break; + case 22: s = "\">=\" expected"; break; + case 23: s = "\"==\" expected"; break; + case 24: s = "\"!=\" expected"; break; + case 25: s = "\"+\" expected"; break; + case 26: s = "\"-\" expected"; break; + case 27: s = "\"*\" expected"; break; + case 28: s = "\"/\" expected"; break; + case 29: s = "\"=\" expected"; break; + case 30: s = "??? expected"; break; + case 31: s = "invalid Statement"; break; + case 32: s = "invalid Factor"; break; + case 33: s = "invalid Factor"; break; default: s = "error " + n; break; } printMsg(line, col, s); - count++; } public void SemErr(int line, int col, String s) { printMsg(line, col, s); - count++; } public void SemErr(String s) { - errorStream.println(s); - count++; + errors.add(s); } public void Warning(int line, int col, String s) { @@ -491,7 +491,7 @@ } public void Warning(String s) { - errorStream.println(s); + errors.add(s); } } // Errors diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/ParserUtils.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/ParserUtils.java Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.sl.parser; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.impl.*; - -public class ParserUtils { - - public static SourceSection createSourceSection(Source source, String identifier, Parser p) { - Token t = p.t; - if (t == null) { - t = p.la; - } - int startLine = -1; - int startColumn = -1; - int length = 0; - if (t != null) { - startLine = t.line; - startColumn = t.col; - length = t.val.length(); - } - return new DefaultSourceSection(source, identifier, startLine, startColumn, 0, length); - } -} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2012, 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.parser; + +import java.math.*; +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.nodes.call.*; +import com.oracle.truffle.sl.nodes.controlflow.*; +import com.oracle.truffle.sl.nodes.expression.*; +import com.oracle.truffle.sl.nodes.local.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * Helper class used by the SL {@link Parser} to create nodes. The code is factored out of the + * automatically generated parser to keep the attributed grammar of SL small. + */ +public class SLNodeFactory { + + /** + * Local variable names that are visible in the current block. Variables are not visible outside + * of their defining block, to prevent the usage of undefined variables. Because of that, we can + * decide during parsing if a name references a local variable or is a function name. + */ + static class LexicalScope { + protected final LexicalScope outer; + protected final Map locals; + + public LexicalScope(LexicalScope outer) { + this.outer = outer; + this.locals = new HashMap<>(); + if (outer != null) { + locals.putAll(outer.locals); + } + } + } + + /* State while parsing a source unit. */ + private final SLContext context; + private final Source source; + + /* State while parsing a function. */ + private String functionName; + private int parameterCount; + private FrameDescriptor frameDescriptor; + private List methodNodes; + + /* State while parsing a block. */ + private LexicalScope lexicalScope; + + public SLNodeFactory(SLContext context, Source source) { + this.context = context; + this.source = source; + } + + public void startFunction(Token nameToken) { + assert functionName == null; + assert parameterCount == 0; + assert frameDescriptor == null; + assert lexicalScope == null; + + functionName = nameToken.val; + frameDescriptor = new FrameDescriptor(); + methodNodes = new ArrayList<>(); + startBlock(); + } + + public void addFormalParameter(Token nameToken) { + /* + * Method parameters are assigned to local variables at the beginning of the method. This + * ensures that accesses to parameters are specialized the same way as local variables are + * specialized. + */ + SLReadArgumentNode readArg = assignSource(nameToken, new SLReadArgumentNode(parameterCount)); + methodNodes.add(createAssignment(nameToken, readArg)); + parameterCount++; + } + + public void finishFunction(SLStatementNode bodyNode) { + methodNodes.add(bodyNode); + SLStatementNode methodBlock = finishBlock(methodNodes); + assert lexicalScope == null : "Wrong scoping of blocks in parser"; + + SLFunctionBodyNode functionBodyNode = new SLFunctionBodyNode(methodBlock); + SLRootNode rootNode = new SLRootNode(frameDescriptor, functionBodyNode, functionName); + + context.getFunctionRegistry().register(functionName, rootNode); + + functionName = null; + parameterCount = 0; + frameDescriptor = null; + lexicalScope = null; + } + + public void startBlock() { + lexicalScope = new LexicalScope(lexicalScope); + } + + public SLStatementNode finishBlock(List bodyNodes) { + lexicalScope = lexicalScope.outer; + + List flattenedNodes = new ArrayList<>(bodyNodes.size()); + flattenBlocks(bodyNodes, flattenedNodes); + if (flattenedNodes.size() == 1) { + /* A block containing one other node is unnecessary, we can just that other node. */ + return flattenedNodes.get(0); + } else { + return new SLBlockNode(flattenedNodes.toArray(new SLStatementNode[flattenedNodes.size()])); + } + } + + private void flattenBlocks(Iterable bodyNodes, List flattenedNodes) { + for (Node n : bodyNodes) { + if (n instanceof SLBlockNode) { + flattenBlocks(n.getChildren(), flattenedNodes); + } else { + flattenedNodes.add((SLStatementNode) n); + } + } + } + + public SLStatementNode createBreak(Token t) { + return assignSource(t, new SLBreakNode()); + } + + public SLStatementNode createContinue(Token t) { + return assignSource(t, new SLContinueNode()); + } + + public SLStatementNode createWhile(Token t, SLExpressionNode conditionNode, SLStatementNode bodyNode) { + return assignSource(t, new SLWhileNode(conditionNode, bodyNode)); + } + + public SLStatementNode createIf(Token t, SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) { + return assignSource(t, new SLIfNode(conditionNode, thenPartNode, elsePartNode)); + } + + public SLStatementNode createReturn(Token t, SLExpressionNode valueNode) { + return assignSource(t, new SLReturnNode(valueNode)); + } + + public SLExpressionNode createBinary(Token opToken, SLExpressionNode leftNode, SLExpressionNode rightNode) { + switch (opToken.val) { + case "+": + return assignSource(opToken, SLAddNodeFactory.create(leftNode, rightNode)); + case "*": + return assignSource(opToken, SLMulNodeFactory.create(leftNode, rightNode)); + case "/": + return assignSource(opToken, SLDivNodeFactory.create(leftNode, rightNode)); + case "-": + return assignSource(opToken, SLSubNodeFactory.create(leftNode, rightNode)); + case "<": + return assignSource(opToken, SLLessThanNodeFactory.create(leftNode, rightNode)); + case "<=": + return assignSource(opToken, SLLessOrEqualNodeFactory.create(leftNode, rightNode)); + case ">": + return assignSource(opToken, SLLogicalNotNodeFactory.create(assignSource(opToken, SLLessOrEqualNodeFactory.create(leftNode, rightNode)))); + case ">=": + return assignSource(opToken, SLLogicalNotNodeFactory.create(assignSource(opToken, SLLessThanNodeFactory.create(leftNode, rightNode)))); + case "==": + return assignSource(opToken, SLEqualNodeFactory.create(leftNode, rightNode)); + case "!=": + return assignSource(opToken, SLLogicalNotNodeFactory.create(assignSource(opToken, SLEqualNodeFactory.create(leftNode, rightNode)))); + case "&&": + return assignSource(opToken, SLLogicalAndNodeFactory.create(leftNode, rightNode)); + case "||": + return assignSource(opToken, SLLogicalOrNodeFactory.create(leftNode, rightNode)); + default: + throw new RuntimeException("unexpected operation: " + opToken.val); + } + } + + public SLExpressionNode createCall(Token nameToken, List parameterNodes) { + SLExpressionNode functionNode = createRead(nameToken); + return assignSource(nameToken, SLInvokeNode.create(functionNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()]))); + } + + public SLExpressionNode createAssignment(Token nameToken, SLExpressionNode valueNode) { + FrameSlot frameSlot = frameDescriptor.findOrAddFrameSlot(nameToken.val); + lexicalScope.locals.put(nameToken.val, frameSlot); + return assignSource(nameToken, SLWriteLocalVariableNodeFactory.create(valueNode, frameSlot)); + } + + public SLExpressionNode createRead(Token nameToken) { + FrameSlot frameSlot = lexicalScope.locals.get(nameToken.val); + if (frameSlot != null) { + /* Read of a local variable. */ + return assignSource(nameToken, SLReadLocalVariableNodeFactory.create(frameSlot)); + } else { + /* Read of a global name. In our language, the only global names are functions. */ + return assignSource(nameToken, new SLFunctionLiteralNode(context.getFunctionRegistry().lookup(nameToken.val))); + } + } + + public SLExpressionNode createStringLiteral(Token literalToken) { + /* Remove the trailing and ending " */ + String literal = literalToken.val; + assert literal.length() >= 2 && literal.startsWith("\"") && literal.endsWith("\""); + literal = literal.substring(1, literal.length() - 1); + + return assignSource(literalToken, new SLStringLiteralNode(literal)); + } + + public SLExpressionNode createNumericLiteral(Token literalToken) { + try { + /* Try if the literal is small enough to fit into a long value. */ + return assignSource(literalToken, new SLLongLiteralNode(Long.parseLong(literalToken.val))); + } catch (NumberFormatException ex) { + /* Overflow of long value, so fall back to BigInteger. */ + return assignSource(literalToken, new SLBigIntegerLiteralNode(new BigInteger(literalToken.val))); + } + } + + private T assignSource(Token t, T node) { + assert functionName != null; + assert t != null; + + int startLine = t.line; + int startColumn = t.col; + int charLength = t.val.length(); + SourceSection sourceSection = new DefaultSourceSection(source, functionName, startLine, startColumn, 0, charLength); + + node.assignSourceSection(sourceSection); + return node; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -311,8 +311,8 @@ static final char EOL = '\n'; static final int eofSym = 0; - static final int maxT = 29; - static final int noSym = 29; + static final int maxT = 30; + static final int noSym = 30; public Buffer buffer; // scanner buffer @@ -347,23 +347,24 @@ start.set(123, 9); start.set(125, 10); start.set(59, 11); - start.set(60, 24); - start.set(62, 25); - start.set(61, 26); - start.set(33, 15); - start.set(43, 17); - start.set(45, 18); - start.set(42, 19); - start.set(47, 20); - start.set(35, 21); - start.set(63, 22); - start.set(58, 23); + start.set(124, 12); + start.set(38, 14); + start.set(60, 25); + start.set(62, 26); + start.set(61, 27); + start.set(33, 19); + start.set(43, 21); + start.set(45, 22); + start.set(42, 23); + start.set(47, 24); start.set(Buffer.EOF, -1); literals.put("function", new Integer(4)); - literals.put("if", new Integer(11)); - literals.put("else", new Integer(12)); + literals.put("break", new Integer(10)); + literals.put("continue", new Integer(12)); literals.put("while", new Integer(13)); - literals.put("return", new Integer(14)); + literals.put("if", new Integer(14)); + literals.put("else", new Integer(15)); + literals.put("return", new Integer(16)); } @@ -519,69 +520,73 @@ } // NextCh already done case 1: recEnd = pos; recKind = 1; - if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} + if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;} case 2: - if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;} - else if (ch == '"') {AddCh(); state = 3; break;} + if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;} + else if (ch == '"') {AddCh(); state = 3; break;} else {state = 0; break;} - case 3: + case 3: {t.kind = 2; break loop;} case 4: recEnd = pos; recKind = 3; - if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;} + if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;} else {t.kind = 3; break loop;} - case 5: + case 5: {t.kind = 3; break loop;} - case 6: + case 6: {t.kind = 5; break loop;} - case 7: + case 7: {t.kind = 6; break loop;} - case 8: + case 8: {t.kind = 7; break loop;} - case 9: + case 9: {t.kind = 8; break loop;} - case 10: + case 10: {t.kind = 9; break loop;} - case 11: - {t.kind = 10; break loop;} - case 12: + case 11: + {t.kind = 11; break loop;} + case 12: + if (ch == '|') {AddCh(); state = 13; break;} + else {state = 0; break;} + case 13: {t.kind = 17; break loop;} - case 13: + case 14: + if (ch == '&') {AddCh(); state = 15; break;} + else {state = 0; break;} + case 15: {t.kind = 18; break loop;} - case 14: - {t.kind = 19; break loop;} - case 15: - if (ch == '=') {AddCh(); state = 16; break;} - else {state = 0; break;} - case 16: + case 16: {t.kind = 20; break loop;} - case 17: - {t.kind = 21; break loop;} - case 18: + case 17: {t.kind = 22; break loop;} - case 19: + case 18: {t.kind = 23; break loop;} - case 20: + case 19: + if (ch == '=') {AddCh(); state = 20; break;} + else {state = 0; break;} + case 20: {t.kind = 24; break loop;} - case 21: + case 21: {t.kind = 25; break loop;} - case 22: + case 22: {t.kind = 26; break loop;} - case 23: + case 23: {t.kind = 27; break loop;} case 24: - recEnd = pos; recKind = 15; - if (ch == '=') {AddCh(); state = 12; break;} - else {t.kind = 15; break loop;} + {t.kind = 28; break loop;} case 25: - recEnd = pos; recKind = 16; - if (ch == '=') {AddCh(); state = 13; break;} - else {t.kind = 16; break loop;} + recEnd = pos; recKind = 19; + if (ch == '=') {AddCh(); state = 16; break;} + else {t.kind = 19; break loop;} case 26: - recEnd = pos; recKind = 28; - if (ch == '=') {AddCh(); state = 14; break;} - else {t.kind = 28; break loop;} + recEnd = pos; recKind = 21; + if (ch == '=') {AddCh(); state = 17; break;} + else {t.kind = 21; break loop;} + case 27: + recEnd = pos; recKind = 29; + if (ch == '=') {AddCh(); state = 18; break;} + else {t.kind = 29; break loop;} } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg Wed Mar 05 19:40:15 2014 -0800 @@ -1,3 +1,32 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * This is the grammar of SL that is used to automatically generate the Parser.java and Scanner.java + * files. You can download the parser generator Coco/R from http://ssw.jku.at/coco/. Then run + * "java -jar Coco.jar SimpleLanguage.atg" + */ + COMPILER SimpleLanguage CHARACTERS @@ -24,6 +53,7 @@ PRODUCTIONS + SimpleLanguage = Function @@ -32,32 +62,48 @@ } . + Function = -"function" (. factory.startFunction(); .) -identifier (. String name = t.val; - List parameterNames = new ArrayList<>(); .) -["(" [identifier (. parameterNames.add(t.val); .) -] {"," identifier (. parameterNames.add(t.val); .) -} ")"] -Block (. factory.createFunction(body, name, parameterNames.toArray(new String[parameterNames.size()])); .) +"function" +identifier (. factory.startFunction(t); .) +"(" +[ + identifier (. factory.addFormalParameter(t); .) + { + "," + identifier (. factory.addFormalParameter(t); .) + } +] +")" +Block (. factory.finishFunction(body); .) . -Block -= (. List statements = new ArrayList<>(); .) + + +Block += (. factory.startBlock(); + List body = new ArrayList<>(); .) "{" { - Statement (. statements.add(statement); .) + Statement (. body.add(s); .) } -"}" (. result = factory.createBlock(statements); .) +"}" (. result = factory.finishBlock(body); .) . -Statement + +Statement = (. result = null; .) ( WhileStatement +| + "break" (. if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } .) + ";" +| + "continue" (. if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } .) + ";" | - IfStatement + IfStatement | ReturnStatement | @@ -65,109 +111,121 @@ ) . -IfStatement + +WhileStatement = -"if" "(" Expression ")" (. StatementNode thenNode = null; StatementNode elseNode = null; .) -Block -["else" Block] (. result = factory.createIf(condition, thenNode, elseNode); .) +"while" +"(" (. Token whileToken = t; .) +Expression +")" +Block (. result = factory.createWhile(whileToken, condition, body); .) +. + + +IfStatement += +"if" +"(" (. Token ifToken = t; .) +Expression +")" +Block (. SLStatementNode elsePart = null; .) +[ + "else" + Block +] (. result = factory.createIf(ifToken, condition, thenPart, elsePart); .) . -WhileStatement + +ReturnStatement += +"return" (. Token returnToken = t; + SLExpressionNode value = null; .) +[ + Expression +] (. result = factory.createReturn(returnToken, value); .) +";" +. + + +Expression = -"while" -"(" -Expression -")" -Block (. result = factory.createWhile(condition, body); .) +LogicTerm +{ + "||" (. Token op = t; .) + LogicTerm (. result = factory.createBinary(op, result, right); .) +} +. + + +LogicTerm += +LogicFactor +{ + "&&" (. Token op = t; .) + LogicFactor (. result = factory.createBinary(op, result, right); .) +} . -ReturnStatement +LogicFactor = -"return" -Expression ";" (. result = factory.createReturn(value); .) -. - -Expression -= -ValueExpression +Arithmetic [ - ("<" | ">" | "<=" | ">=" | "==" | "!=" ) (. String op = t.val; .) - ValueExpression (. result = factory.createBinary(op, result, right); .) + ("<" | "<=" | ">" | ">=" | "==" | "!=" ) (. Token op = t; .) + Arithmetic (. result = factory.createBinary(op, result, right); .) ] . -ValueExpression + +Arithmetic = Term { - ("+" | "-") (. String op = t.val; .) - Term (. result = factory.createBinary(op, result, right); .) + ("+" | "-") (. Token op = t; .) + Term (. result = factory.createBinary(op, result, right); .) } . -Term + +Term = Factor { - ("*" | "/") (. String op = t.val; .) - Factor (. result = factory.createBinary(op, result, right); .) + ("*" | "/") (. Token op = t; .) + Factor (. result = factory.createBinary(op, result, right); .) } . -Factor + +Factor = (. result = null; .) ( - VariableRefOrCall -| - StringLiteral + identifier (. Token nameToken = t; .) + ( + "(" (. List parameters = new ArrayList<>(); + SLExpressionNode parameter; .) + [ + Expression (. parameters.add(parameter); .) + { + "," + Expression (. parameters.add(parameter); .) + } + ] (. result = factory.createCall(nameToken, parameters); .) + ")" + | + "=" + Expression (. result = factory.createAssignment(nameToken, value); .) + | + (. result = factory.createRead(nameToken); .) + ) | - NumericLiteral + stringLiteral (. result = factory.createStringLiteral(t); .) | - Ternary + numericLiteral (. result = factory.createNumericLiteral(t); .) | "(" Expression ")" ) . -Ternary (. TypedNode condition, thenPart, elsePart; .) -= -"#" Expression "?" Expression ":" Expression - (. result = factory.createTernary(condition, thenPart, elsePart); .) -. - -VariableRefOrCall -= -VariableRef -[ - (Parameters) (. result = factory.createCall(result, parameters); .) -| ("=" Expression) (. result = factory.createAssignment(result, assignment); .) -] -. - -Parameters -= -"(" (. List parameters = new ArrayList<>(); .) -[Expression (. parameters.add(e1); .) -{"," Expression (. parameters.add(e2); .) -} -] (. result = parameters.toArray(new TypedNode[parameters.size()]); .) -")" -. - -VariableRef -= -identifier (. result = factory.createLocal(t.val); .) -. - -StringLiteral -= -stringLiteral (. result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); .) -. - -NumericLiteral -= -numericLiteral (. result = factory.createNumericLiteral(t.val); .) -. END SimpleLanguage. diff -r d0e82d536325 -r a124cc76cde9 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 Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -24,16 +24,28 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.sl.nodes.call.*; +import com.oracle.truffle.sl.nodes.local.*; +/** + * Encapsulation of SL function arguments, as required by the Truffle API. An instance of this class + * is allocated by the caller, and read by the callee. + */ public final class SLArguments extends Arguments { - public final Object[] arguments; + private final Object[] argumentValues; + /** + * Used by the caller, i.e., the {@link SLInvokeNode node that performs a function call}. + */ public SLArguments(Object[] arguments) { - this.arguments = arguments; + this.argumentValues = arguments; } - public static SLArguments get(VirtualFrame frame) { - return frame.getArguments(SLArguments.class); + /** + * Used by the callee, i.e., the {@link SLReadArgumentNode note that reads a function argument}. + */ + public static Object[] getFromFrame(VirtualFrame frame) { + return frame.getArguments(SLArguments.class).argumentValues; } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -24,32 +24,105 @@ import java.io.*; +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.sl.builtins.*; - -public final class SLContext { +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.nodes.local.*; +import com.oracle.truffle.sl.parser.*; - private final PrintStream printOutput; - private final SLFunctionRegistry functionRegistry; +/** + * The run-time state of SL during execution. One context is instantiated before any source code is + * parsed, and this context is passed around to all methods that need access to it. For example, the + * context is used during {@link SLNodeFactory parsing} and by {@link SLBuiltinNode#getContext() + * builtin functions}. + *

+ * It would be an error to have two different context instances during the execution of one script. + * However, if two separate scripts run in one Java VM at the same time, they have a different + * context. Therefore, the context is not a singleton. + */ +public final class SLContext { private final SourceManager sourceManager; + private final BufferedReader input; + private final PrintStream output; + private final SLFunctionRegistry functionRegistry; - public SLContext(PrintStream print) { - this.printOutput = print; + public SLContext(SourceManager sourceManager, BufferedReader input, PrintStream output) { + this.sourceManager = sourceManager; + this.input = input; + this.output = output; this.functionRegistry = new SLFunctionRegistry(); - DefaultBuiltins.install(this); - this.sourceManager = new SourceManager(); + + installBuiltins(); } - public PrintStream getPrintOutput() { - return printOutput; + /** + * Returns the source manger that controls all SL source code that is executed. + */ + public SourceManager getSourceManager() { + return sourceManager; } + /** + * Returns the default input, i.e., the source for the {@link SLReadlnBuiltin}. To allow unit + * testing, we do not use {@link System#in} directly. + */ + public BufferedReader getInput() { + return input; + } + + /** + * The default default, i.e., the output for the {@link SLPrintlnBuiltin}. To allow unit + * testing, we do not use {@link System#out} directly. + */ + public PrintStream getOutput() { + return output; + } + + /** + * Returns the registry of all functions that are currently defined. + */ public SLFunctionRegistry getFunctionRegistry() { return functionRegistry; } - public SourceManager getSourceManager() { - return sourceManager; + /** + * Adds all builtin functions to the {@link SLFunctionRegistry}. This method lists all + * {@link SLBuiltinNode builtin implementation classes}. + */ + private void installBuiltins() { + installBuiltin(SLReadlnBuiltinFactory.getInstance()); + installBuiltin(SLPrintlnBuiltinFactory.getInstance()); + installBuiltin(SLNanoTimeBuiltinFactory.getInstance()); + installBuiltin(SLDefineFunctionBuiltinFactory.getInstance()); } + private void installBuiltin(NodeFactory factory) { + /* + * The builtin node factory is a class that is automatically generated by the Truffle DSL. + * The signature returned by the factory reflects the signature of the @Specialization + * methods in the builtin classes. + */ + int argumentCount = factory.getExecutionSignature().size(); + SLExpressionNode[] argumentNodes = new SLExpressionNode[argumentCount]; + /* + * Builtin functions are like normal functions, i.e., the arguments are passed in as an + * Object[] array encapsulated in SLArguments. A SLReadArgumentNode extracts a parameter + * from this array. + */ + for (int i = 0; i < argumentCount; i++) { + argumentNodes[i] = new SLReadArgumentNode(i); + } + /* Instantiate the builtin node. This node performs the actual functionality. */ + SLBuiltinNode builtinBodyNode = factory.createNode(argumentNodes, this); + /* The name of the builtin function is specified via an annotation on the node class. */ + String name = builtinBodyNode.getClass().getAnnotation(NodeInfo.class).shortName(); + /* Wrap the builtin in a RootNode. Truffle requires all AST to start with a RootNode. */ + SLRootNode rootNode = new SLRootNode(new FrameDescriptor(), builtinBodyNode, name); + + /* Register the builtin function in our function registry. */ + getFunctionRegistry().register(name, rootNode); + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,93 @@ +/* + * 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.truffle.sl.runtime; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.utilities.*; + +/** + * Represents a SL function. On the Truffle level, a callable element is represented by a + * {@link RootCallTarget call target}. This class encapsulates a call target, and adds version + * support: functions in SL can be redefined, i.e. changed at run time. When a function is + * redefined, the call target managed by this function object is changed (and {@link #callTarget} is + * therefore not a final field). + *

+ * Function redefinition is expected to be rare, therefore optimized call nodes want to speculate + * that the call target is stable. This is possible with the help of a Truffle {@link Assumption}: a + * call node can keep the call target returned by {@link #getCallTarget()} cached until the + * assumption returned by {@link #getCallTargetStable()} is valid. + *

+ * The {@link #callTarget} can be {@code null}. To ensure that only one {@link SLFunction} instance + * per name exists, the {@link SLFunctionRegistry} creates an instance also when performing name + * lookup. A function that has been looked up, i.e., used, but not defined, has no call target. + */ +public final class SLFunction { + + /** The name of the function. */ + private final String name; + + /** The current implementation of this function. */ + private RootCallTarget callTarget; + + /** + * Manages the assumption that the {@link #callTarget} is stable. We use the utility class + * {@link CyclicAssumption}, which automatically creates a new {@link Assumption} when the old + * one gets invalidated. + */ + private final CyclicAssumption callTargetStable; + + protected SLFunction(String name) { + this.name = name; + this.callTargetStable = new CyclicAssumption(name); + } + + public String getName() { + return name; + } + + protected void setCallTarget(RootCallTarget callTarget) { + this.callTarget = callTarget; + /* + * We have a new call target. Invalidate all code that speculated that the old call target + * was stable. + */ + callTargetStable.invalidate(); + } + + public RootCallTarget getCallTarget() { + return callTarget; + } + + public Assumption getCallTargetStable() { + return callTargetStable.getAssumption(); + } + + /** + * This method is, e.g., called when using a function literal in a string concatenation. So + * changing it has an effect on SL programs. + */ + @Override + public String toString() { + return name; + } +} diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionRegistry.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionRegistry.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionRegistry.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,20 +25,49 @@ import java.util.*; import com.oracle.truffle.api.*; +import com.oracle.truffle.sl.nodes.*; +/** + * Manages the mapping from function names to {@link SLFunction function objects}. + */ public final class SLFunctionRegistry { - private Map map = new HashMap<>(); + private final Map functions = new HashMap<>(); - public void register(String name, CallTarget target) { - if (map.containsKey(name)) { - throw new IllegalArgumentException(String.format("Function with name '%s' already exists.", name)); + /** + * Returns the canonical {@link SLFunction} object for the given name. If it does not exist yet, + * it is created. + */ + public SLFunction lookup(String name) { + SLFunction result = functions.get(name); + if (result == null) { + result = new SLFunction(name); + functions.put(name, result); } - map.put(name, target); + return result; } - public CallTarget lookup(String name) { - return map.get(name); + /** + * Associates the {@link SLFunction} with the given name with the given implementation root + * node. If the function did not exist before, it defines the function. If the function existed + * before, it redefines the function and the old implementation is discarded. + */ + public void register(String name, SLRootNode rootNode) { + SLFunction function = lookup(name); + RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); + function.setCallTarget(callTarget); } + /** + * Returns the sorted list of all functions, for printing purposes only. + */ + public List getFunctions() { + List result = new ArrayList<>(functions.values()); + Collections.sort(result, new Comparator() { + public int compare(SLFunction f1, SLFunction f2) { + return f1.toString().compareTo(f2.toString()); + } + }); + return result; + } } diff -r d0e82d536325 -r a124cc76cde9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Sun Feb 23 17:00:35 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Wed Mar 05 19:40:15 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -22,11 +22,34 @@ */ package com.oracle.truffle.sl.runtime; +/** + * The SL type for a {@code null} (i.e., undefined) value. In Truffle, it is generally discouraged + * to use the Java {@code null} value to represent the guest language {@code null} value. It is not + * possible to specialize on Java {@code null} (since you cannot ask it for the Java class), and + * there is always the danger of a spurious {@link NullPointerException}. Representing the guest + * language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended + * practice. + * */ public final class SLNull { - public static final SLNull INSTANCE = new SLNull(); + /** + * The canonical value to represent {@code null} in SL. + */ + public static final SLNull SINGLETON = new SLNull(); + /** + * Disallow instantiation from outside to ensure that the {@link #SINGLETON} is the only + * instance. + */ private SLNull() { } + /** + * This method is, e.g., called when using the {@code null} value in a string concatenation. So + * changing it has an effect on SL programs. + */ + @Override + public String toString() { + return "null"; + } } diff -r d0e82d536325 -r a124cc76cde9 hotspot/.project --- a/hotspot/.project Sun Feb 23 17:00:35 2014 -0800 +++ b/hotspot/.project Wed Mar 05 19:40:15 2014 -0800 @@ -86,41 +86,6 @@ - ptx - 2 - PARENT-1-PROJECT_LOC/src/gpu/ptx - - - x86 - 2 - PARENT-1-PROJECT_LOC/src/cpu/x86/vm - - - ptx - 2 - PARENT-1-PROJECT_LOC/src/gpu/ptx/vm - - - hsail - 2 - PARENT-1-PROJECT_LOC/src/gpu/hsail/vm - - - sparc - 2 - PARENT-1-PROJECT_LOC/src/cpu/sparc/vm - - - generated - 2 - PARENT-1-PROJECT_LOC/build/linux/linux_amd64_graal/generated - - - make - 2 - WORKSPACE_LOC/make - - bsd 2 PARENT-1-PROJECT_LOC/src/os/bsd/vm @@ -131,9 +96,49 @@ PARENT-1-PROJECT_LOC/src/os_cpu/bsd_x86/vm - bsd_ptx + generated + 2 + PARENT-1-PROJECT_LOC/build/linux/linux_amd64_graal/generated + + + hsail + 2 + PARENT-1-PROJECT_LOC/src/gpu/hsail/vm + + + linux + 2 + PARENT-1-PROJECT_LOC/src/os/linux/vm + + + linux_sparc + 2 + PARENT-1-PROJECT_LOC/src/os_cpu/linux_sparc/vm + + + linux_x86 2 - PARENT-1-PROJECT_LOC/src/os_gpu/bsd_ptx/vm + PARENT-1-PROJECT_LOC/src/os_cpu/linux_x86/vm + + + make + 2 + WORKSPACE_LOC/make + + + ptx + 2 + PARENT-1-PROJECT_LOC/src/gpu/ptx/vm + + + sparc + 2 + PARENT-1-PROJECT_LOC/src/cpu/sparc/vm + + + vm + 2 + PARENT-1-PROJECT_LOC/src/share/vm windows @@ -146,34 +151,9 @@ PARENT-1-PROJECT_LOC/src/os_cpu/windows_x86/vm - linux - 2 - PARENT-1-PROJECT_LOC/src/os/linux/vm - - - linux_x86 - 2 - PARENT-1-PROJECT_LOC/src/os_cpu/linux_x86/vm - - - windows_hsail + x86 2 - PARENT-1-PROJECT_LOC/src/os_gpu/windows_hsail/vm - - - linux_ptx - 2 - PARENT-1-PROJECT_LOC/src/os_gpu/linux_ptx/vm - - - linux_sparc - 2 - PARENT-1-PROJECT_LOC/src/os_cpu/linux_sparc/vm - - - vm - 2 - PARENT-1-PROJECT_LOC/src/share/vm + PARENT-1-PROJECT_LOC/src/cpu/x86/vm diff -r d0e82d536325 -r a124cc76cde9 make/bsd/makefiles/buildtree.make --- a/make/bsd/makefiles/buildtree.make Sun Feb 23 17:00:35 2014 -0800 +++ b/make/bsd/makefiles/buildtree.make Wed Mar 05 19:40:15 2014 -0800 @@ -239,8 +239,6 @@ echo "$(call gamma-path,commonsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ - echo "$(call gamma-path,altsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \ @@ -261,8 +259,6 @@ echo "$(call gamma-path,commonsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ - echo "$(call gamma-path,altsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \ diff -r d0e82d536325 -r a124cc76cde9 make/bsd/makefiles/vm.make --- a/make/bsd/makefiles/vm.make Sun Feb 23 17:00:35 2014 -0800 +++ b/make/bsd/makefiles/vm.make Wed Mar 05 19:40:15 2014 -0800 @@ -178,7 +178,6 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/ptx/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/hsail/vm -SOURCE_PATHS+=$(HS_COMMON_SRC)/os_gpu/bsd_ptx/vm CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles diff -r d0e82d536325 -r a124cc76cde9 make/linux/makefiles/buildtree.make --- a/make/linux/makefiles/buildtree.make Sun Feb 23 17:00:35 2014 -0800 +++ b/make/linux/makefiles/buildtree.make Wed Mar 05 19:40:15 2014 -0800 @@ -235,8 +235,6 @@ echo "$(call gamma-path,commonsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ - echo "$(call gamma-path,altsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \ @@ -257,8 +255,6 @@ echo "$(call gamma-path,commonsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ - echo "$(call gamma-path,altsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os_gpu/$(OS_FAMILY)_ptx/vm) \\"; \ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \ diff -r d0e82d536325 -r a124cc76cde9 make/linux/makefiles/vm.make --- a/make/linux/makefiles/vm.make Sun Feb 23 17:00:35 2014 -0800 +++ b/make/linux/makefiles/vm.make Wed Mar 05 19:40:15 2014 -0800 @@ -158,7 +158,6 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/ptx/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/hsail/vm -SOURCE_PATHS+=$(HS_COMMON_SRC)/os_gpu/linux_ptx/vm CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path)) CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles diff -r d0e82d536325 -r a124cc76cde9 make/windows/makefiles/projectcreator.make --- a/make/windows/makefiles/projectcreator.make Sun Feb 23 17:00:35 2014 -0800 +++ b/make/windows/makefiles/projectcreator.make Wed Mar 05 19:40:15 2014 -0800 @@ -56,7 +56,6 @@ -relativeInclude src\os\windows\vm \ -relativeInclude src\os_cpu\windows_$(Platform_arch)\vm \ -relativeInclude src\cpu\$(Platform_arch)\vm \ - -relativeInclude src\os_gpu\windows_hsail\vm \ -relativeInclude src\gpu \ -absoluteInclude $(HOTSPOTBUILDSPACE)/%f/generated \ -relativeSrcInclude src \ diff -r d0e82d536325 -r a124cc76cde9 make/windows/makefiles/vm.make --- a/make/windows/makefiles/vm.make Sun Feb 23 17:00:35 2014 -0800 +++ b/make/windows/makefiles/vm.make Wed Mar 05 19:40:15 2014 -0800 @@ -126,7 +126,6 @@ /I "$(COMMONSRC)\share\vm\prims" \ /I "$(COMMONSRC)\os\windows\vm" \ /I "$(COMMONSRC)\os_cpu\windows_$(Platform_arch)\vm" \ - /I "$(COMMONSRC)\os_gpu\windows_hsail\vm" \ /I "$(COMMONSRC)\cpu\$(Platform_arch)\vm" CXX_DONT_USE_PCH=/D DONT_USE_PRECOMPILED_HEADER @@ -171,7 +170,6 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/libadt VM_PATH=$(VM_PATH);$(WorkSpace)/src/os/windows/vm VM_PATH=$(VM_PATH);$(WorkSpace)/src/os_cpu/windows_$(Platform_arch)/vm -VM_PATH=$(VM_PATH);$(WorkSpace)/src/os_gpu/windows_hsail/vm VM_PATH=$(VM_PATH);$(WorkSpace)/src/cpu/$(Platform_arch)/vm VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/opto diff -r d0e82d536325 -r a124cc76cde9 mx/eclipse-settings/org.eclipse.core.resources.prefs --- a/mx/eclipse-settings/org.eclipse.core.resources.prefs Sun Feb 23 17:00:35 2014 -0800 +++ b/mx/eclipse-settings/org.eclipse.core.resources.prefs Wed Mar 05 19:40:15 2014 -0800 @@ -1,2 +1,2 @@ eclipse.preferences.version=1 -encoding/=US-ASCII \ No newline at end of file +encoding/=UTF-8 diff -r d0e82d536325 -r a124cc76cde9 mx/eclipse-settings/org.eclipse.jdt.core.prefs --- a/mx/eclipse-settings/org.eclipse.jdt.core.prefs Sun Feb 23 17:00:35 2014 -0800 +++ b/mx/eclipse-settings/org.eclipse.jdt.core.prefs Wed Mar 05 19:40:15 2014 -0800 @@ -100,6 +100,7 @@ org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.tasks=ignore org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=ignore diff -r d0e82d536325 -r a124cc76cde9 mx/mx_graal.py --- a/mx/mx_graal.py Sun Feb 23 17:00:35 2014 -0800 +++ b/mx/mx_graal.py Wed Mar 05 19:40:15 2014 -0800 @@ -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) @@ -607,7 +611,7 @@ project_config = variant + '_' + build _runInDebugShell('msbuild ' + _graal_home + r'\build\vs-amd64\jvm.vcproj /p:Configuration=' + project_config + ' /target:clean', _graal_home) winCompileCmd = r'set HotSpotMksHome=' + mksHome + r'& set OUT_DIR=' + jdk + r'& set JAVA_HOME=' + jdk + r'& set path=%JAVA_HOME%\bin;%path%;%HotSpotMksHome%& cd /D "' + _graal_home + r'\make\windows"& call create.bat ' + _graal_home - print(winCompileCmd) + print winCompileCmd winCompileSuccess = re.compile(r"^Writing \.vcxproj file:") if not _runInDebugShell(winCompileCmd, _graal_home, compilelogfile, winCompileSuccess): mx.log('Error executing create command') @@ -631,6 +635,13 @@ env.setdefault('LANG', 'C') env.setdefault('HOTSPOT_BUILD_JOBS', str(cpus)) env.setdefault('ALT_BOOTDIR', mx.java().jdk) + + # extract latest release tag for graal + tags = [x.split(' ')[0] for x in subprocess.check_output(['hg', 'tags']).split('\n') if x.startswith("graal-")] + if tags: + # extract the most recent tag + tag = sorted(tags, key=lambda e: [int(x) for x in e[len("graal-"):].split('.')], reverse=True)[0] + env.setdefault('USER_RELEASE_SUFFIX', tag) if not mx._opts.verbose: runCmd.append('MAKE_VERBOSE=') env['JAVA_HOME'] = jdk @@ -640,10 +651,10 @@ else: env['INCLUDE_GRAAL'] = 'true' env.setdefault('INSTALL', 'y') - if mx.get_os() == 'solaris' : + if mx.get_os() == 'solaris': # If using sparcWorks, setup flags to avoid make complaining about CC version cCompilerVersion = subprocess.Popen('CC -V', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stderr.readlines()[0] - if cCompilerVersion.startswith('CC: Sun C++') : + if cCompilerVersion.startswith('CC: Sun C++'): compilerRev = cCompilerVersion.split(' ')[3] env.setdefault('ENFORCE_COMPILER_REV', compilerRev) env.setdefault('ENFORCE_CC_COMPILER_REV', compilerRev) @@ -678,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): @@ -701,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: @@ -718,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 @@ -739,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 [] @@ -750,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): """ @@ -759,7 +768,7 @@ source file matched in a list. """ - matches = lambda line : len([a for a in annotations if line == a or line.startswith(a + '(')]) != 0 + matches = lambda line: len([a for a in annotations if line == a or line.startswith(a + '(')]) != 0 return p.find_classes_with_matching_source_line(pkgRoot, matches, includeInnerClasses) def _extract_VM_args(args, allowClasspath=False, useDoubleDash=False): @@ -1060,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: @@ -1087,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') @@ -1189,7 +1207,7 @@ results = {} benchmarks = [] # DaCapo - if ('dacapo' in args or 'all' in args): + if 'dacapo' in args or 'all' in args: benchmarks += sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Benchmark) else: dacapos = benchmarks_in_group('dacapo') @@ -1197,10 +1215,10 @@ if dacapo not in sanitycheck.dacapoSanityWarmup.keys(): mx.abort('Unknown DaCapo : ' + dacapo) iterations = sanitycheck.dacapoSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark] - if (iterations > 0): + if iterations > 0: benchmarks += [sanitycheck.getDacapo(dacapo, iterations)] - if ('scaladacapo' in args or 'all' in args): + if 'scaladacapo' in args or 'all' in args: benchmarks += sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Benchmark) else: scaladacapos = benchmarks_in_group('scaladacapo') @@ -1208,31 +1226,31 @@ if scaladacapo not in sanitycheck.dacapoScalaSanityWarmup.keys(): mx.abort('Unknown Scala DaCapo : ' + scaladacapo) iterations = sanitycheck.dacapoScalaSanityWarmup[scaladacapo][sanitycheck.SanityCheckLevel.Benchmark] - if (iterations > 0): + if iterations > 0: benchmarks += [sanitycheck.getScalaDacapo(scaladacapo, ['-n', str(iterations)])] # Bootstrap - if ('bootstrap' in args or 'all' in args): + if 'bootstrap' in args or 'all' in args: benchmarks += sanitycheck.getBootstraps() # SPECjvm2008 - if ('specjvm2008' in args or 'all' in args): + if 'specjvm2008' in args or 'all' in args: benchmarks += [sanitycheck.getSPECjvm2008(['-ikv', '-wt', '120', '-it', '120'])] else: specjvms = benchmarks_in_group('specjvm2008') for specjvm in specjvms: benchmarks += [sanitycheck.getSPECjvm2008(['-ikv', '-wt', '120', '-it', '120', specjvm])] - if ('specjbb2005' in args or 'all' in args): + if 'specjbb2005' in args or 'all' in args: benchmarks += [sanitycheck.getSPECjbb2005()] - if ('specjbb2013' in args): # or 'all' in args //currently not in default set + if 'specjbb2013' in args: # or 'all' in args //currently not in default set benchmarks += [sanitycheck.getSPECjbb2013()] - if ('ctw-full' in args): + if 'ctw-full' in args: benchmarks.append(sanitycheck.getCTW(vm, sanitycheck.CTWMode.Full)) - if ('ctw-noinline' in args): + if 'ctw-noinline' in args: benchmarks.append(sanitycheck.getCTW(vm, sanitycheck.CTWMode.NoInline)) - if ('ctw-nocomplex' in args): + if 'ctw-nocomplex' in args: benchmarks.append(sanitycheck.getCTW(vm, sanitycheck.CTWMode.NoComplex)) for test in benchmarks: @@ -1244,6 +1262,77 @@ 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", + "-v", "EXTRA" if mx._opts.verbose else "NORMAL", + "-i", "10", "-wi", "10", + "--jvm", exe, + "--jvmArgs", " ".join(["-" + vm] + forkedVmArgs)] + regex, + addDefaultArgs=False, + cwd=jmhPath) + + def specjvm2008(args): """run one or more SPECjvm2008 benchmarks""" @@ -1358,7 +1447,7 @@ def sl(args): """run an SL program""" vmArgs, slArgs = _extract_VM_args(args) - vm(vmArgs + ['-cp', mx.classpath("com.oracle.truffle.sl"), "com.oracle.truffle.sl.SimpleLanguage"] + slArgs) + vm(vmArgs + ['-cp', mx.classpath("com.oracle.truffle.sl"), "com.oracle.truffle.sl.SLMain"] + slArgs) def trufflejar(args=None): """make truffle.jar""" @@ -1377,17 +1466,6 @@ def isGraalEnabled(vm): return vm != 'original' and not vm.endswith('nograal') -def rubyShellCp(): - return mx.classpath("com.oracle.truffle.ruby.shell") - -def rubyShellClass(): - return "com.oracle.truffle.ruby.shell.Shell" - -def ruby(args): - """run a Ruby program or shell""" - vmArgs, rubyArgs = _extract_VM_args(args, useDoubleDash=True) - vm(vmArgs + ['-cp', rubyShellCp(), rubyShellClass()] + rubyArgs) - def site(args): """create a website containing javadoc and the project dependency graph""" @@ -1528,6 +1606,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]'], @@ -1546,8 +1625,7 @@ 'deoptalot' : [deoptalot, '[n]'], 'longtests' : [longtests, ''], 'sl' : [sl, '[SL args|@VM options]'], - 'trufflejar' : [trufflejar, ''], - 'ruby' : [ruby, '[Ruby args|@VM options]'] + 'trufflejar' : [trufflejar, ''] } mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append']) @@ -1556,7 +1634,7 @@ 'The VM selected by --vm and --vmbuild options is under this directory (i.e., ' + join('', '', '', 'jre', 'lib', '', mx.add_lib_prefix(mx.add_lib_suffix('jvm'))) + ')', default=None, metavar='') - if (_vmSourcesAvailable): + if _vmSourcesAvailable: mx.add_argument('--vm', action='store', dest='vm', choices=_vmChoices.keys(), help='the VM type to build/run') mx.add_argument('--vmbuild', action='store', dest='vmbuild', choices=_vmbuildChoices, help='the VM build to build/run (default: ' + _vmbuildChoices[0] + ')') mx.add_argument('--ecl', action='store_true', dest='make_eclipse_launch', help='create launch configuration for running VM execution(s) in Eclipse') @@ -1571,10 +1649,10 @@ def mx_post_parse_cmd_line(opts): # # TODO _minVersion check could probably be part of a Suite in mx? - if (mx.java().version < _minVersion) : + if mx.java().version < _minVersion: mx.abort('Requires Java version ' + str(_minVersion) + ' or greater, got version ' + str(mx.java().version)) - if (_vmSourcesAvailable): + if _vmSourcesAvailable: if hasattr(opts, 'vm') and opts.vm is not None: global _vm _vm = opts.vm diff -r d0e82d536325 -r a124cc76cde9 mx/projects --- a/mx/projects Sun Feb 23 17:00:35 2014 -0800 +++ b/mx/projects Wed Mar 05 19:40:15 2014 -0800 @@ -24,51 +24,15 @@ library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0-20120216.jar library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar -library@OKRA@path=lib/okra-1.2.jar -library@OKRA@sourcePath=lib/okra-1.2.jar -library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.2.jar - -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@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_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_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@OKRA@path=lib/okra-1.8.jar +library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8.jar +library@OKRA@sourcePath=lib/okra-1.8-src.jar +library@OKRA@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-src.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_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@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 - -library@ASM@path=lib/asm-4.0.jar -library@ASM@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm/4.0/asm-4.0.jar - -library@ASM_ANALYSIS@path=lib/asm-analysis-4.0.jar -library@ASM_ANALYSIS@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-analysis/4.0/asm-analysis-4.0.jar - -library@ASM_COMMONS@path=lib/asm-commons-4.0.jar -library@ASM_COMMONS@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-commons/4.0/asm-commons-4.0.jar - -library@ASM_TREE@path=lib/asm-tree-4.0.jar -library@ASM_TREE@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-tree/4.0/asm-tree-4.0.jar - -library@ASM_UTIL@path=lib/asm-util-4.0.jar -library@ASM_UTIL@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-util/4.0/asm-util-4.0.jar +library@OKRA_WITH_SIM@path=lib/okra-1.8-with-sim.jar +library@OKRA_WITH_SIM@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim.jar +library@OKRA_WITH_SIM@sourcePath=lib/okra-1.8-with-sim-src.jar +library@OKRA_WITH_SIM@sourceUrls=http://cr.openjdk.java.net/~tdeneau/okra-1.8-with-sim-src.jar distribution@GRAAL@path=graal.jar distribution@GRAAL@dependencies=\ @@ -178,7 +142,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.hotspot,com.oracle.graal.compiler.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 @@ -507,6 +471,14 @@ project@com.oracle.graal.java@javaCompliance=1.7 project@com.oracle.graal.java@workingSets=Graal,Java +# graal.baseline +project@com.oracle.graal.baseline@subDir=graal +project@com.oracle.graal.baseline@sourceDirs=src +project@com.oracle.graal.baseline@dependencies=com.oracle.graal.java,com.oracle.graal.lir +project@com.oracle.graal.baseline@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.baseline@javaCompliance=1.7 +project@com.oracle.graal.baseline@workingSets=Graal,Java + # graal.java.decompiler project@com.oracle.graal.java.decompiler@subDir=graal project@com.oracle.graal.java.decompiler@sourceDirs=src @@ -542,7 +514,7 @@ # graal.compiler.test project@com.oracle.graal.compiler.test@subDir=graal project@com.oracle.graal.compiler.test@sourceDirs=src -project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.printer,com.oracle.graal.runtime +project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.printer,com.oracle.graal.runtime,com.oracle.graal.baseline project@com.oracle.graal.compiler.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler.test@javaCompliance=1.7 project@com.oracle.graal.compiler.test@workingSets=Graal,Test @@ -611,7 +583,7 @@ # graal.compiler.hsail.test.infra - HSAIL compiler test infrastructure project@com.oracle.graal.compiler.hsail.test.infra@subDir=graal project@com.oracle.graal.compiler.hsail.test.infra@sourceDirs=src -project@com.oracle.graal.compiler.hsail.test.infra@dependencies=com.oracle.graal.hotspot.hsail,JUNIT +project@com.oracle.graal.compiler.hsail.test.infra@dependencies=com.oracle.graal.hotspot.hsail,JUNIT,OKRA_WITH_SIM project@com.oracle.graal.compiler.hsail.test.infra@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler.hsail.test.infra@javaCompliance=1.7 @@ -735,43 +707,3 @@ project@com.oracle.graal.truffle.hotspot.amd64@javaCompliance=1.7 project@com.oracle.graal.truffle.hotspot.amd64@annotationProcessors=com.oracle.graal.service.processor project@com.oracle.graal.truffle.hotspot.amd64@workingSets=Graal,Truffle - -# truffle.ruby.runtime -project@com.oracle.truffle.ruby.runtime@subDir=graal -project@com.oracle.truffle.ruby.runtime@sourceDirs=src -project@com.oracle.truffle.ruby.runtime@dependencies=JRUBYSTDLIB,JNR_POSIX,JNR_CONSTANTS,JNR_FFI,JFFI,JFFI_NATIVE,JNR_X86ASM,ASM,ASM_ANALYSIS,ASM_COMMONS,ASM_TREE,ASM_UTIL,com.oracle.truffle.api -project@com.oracle.truffle.ruby.runtime@javaCompliance=1.7 -project@com.oracle.truffle.ruby.runtime@workingSets=Truffle,Ruby - -# truffle.ruby.nodes -project@com.oracle.truffle.ruby.nodes@subDir=graal -project@com.oracle.truffle.ruby.nodes@sourceDirs=src -project@com.oracle.truffle.ruby.nodes@dependencies=com.oracle.truffle.ruby.runtime,com.oracle.truffle.api.dsl -project@com.oracle.truffle.ruby.nodes@checkstyle=com.oracle.truffle.ruby.runtime -project@com.oracle.truffle.ruby.nodes@javaCompliance=1.7 -project@com.oracle.truffle.ruby.nodes@annotationProcessors=com.oracle.truffle.dsl.processor -project@com.oracle.truffle.ruby.nodes@workingSets=Truffle,Ruby - -# truffle.ruby.parser -project@com.oracle.truffle.ruby.parser@subDir=graal -project@com.oracle.truffle.ruby.parser@sourceDirs=src -project@com.oracle.truffle.ruby.parser@dependencies=JRUBYPARSER,com.oracle.truffle.ruby.nodes -project@com.oracle.truffle.ruby.parser@checkstyle=com.oracle.truffle.ruby.runtime -project@com.oracle.truffle.ruby.parser@javaCompliance=1.7 -project@com.oracle.truffle.ruby.parser@workingSets=Truffle,Ruby - -# truffle.ruby.shell -project@com.oracle.truffle.ruby.shell@subDir=graal -project@com.oracle.truffle.ruby.shell@sourceDirs=src -project@com.oracle.truffle.ruby.shell@dependencies=JLINE,com.oracle.truffle.ruby.parser -project@com.oracle.truffle.ruby.shell@checkstyle=com.oracle.truffle.ruby.runtime -project@com.oracle.truffle.ruby.shell@javaCompliance=1.7 -project@com.oracle.truffle.ruby.shell@workingSets=Truffle,Ruby - -# truffle.ruby.test -project@com.oracle.truffle.ruby.test@subDir=graal -project@com.oracle.truffle.ruby.test@sourceDirs=src -project@com.oracle.truffle.ruby.test@dependencies=com.oracle.truffle.ruby.parser,JUNIT -project@com.oracle.truffle.ruby.test@checkstyle=com.oracle.truffle.ruby.runtime -project@com.oracle.truffle.ruby.test@javaCompliance=1.7 -project@com.oracle.truffle.ruby.test@workingSets=Truffle,Ruby,Test diff -r d0e82d536325 -r a124cc76cde9 mx/sanitycheck.py --- a/mx/sanitycheck.py Sun Feb 23 17:00:35 2014 -0800 +++ b/mx/sanitycheck.py Wed Mar 05 19:40:15 2014 -0800 @@ -68,17 +68,17 @@ 'avrora': ['product', 'fastdebug', 'debug'], 'batik': ['product', 'fastdebug', 'debug'], 'eclipse': ['product'], - 'fop': [ 'fastdebug', 'debug'], + 'fop': ['fastdebug', 'debug'], 'h2': ['product', 'fastdebug', 'debug'], 'jython': ['product', 'fastdebug', 'debug'], 'luindex': ['product', 'fastdebug', 'debug'], 'lusearch': ['product'], 'pmd': ['product', 'fastdebug', 'debug'], - 'sunflow': [ 'fastdebug', 'debug'], + 'sunflow': ['fastdebug', 'debug'], 'tomcat': ['product', 'fastdebug', 'debug'], 'tradebeans': ['product', 'fastdebug', 'debug'], # tradesoap is too unreliable for the gate, often crashing with "java.net.BindException: Address already in use" - 'tradesoap': [ ], + 'tradesoap': [], 'xalan': ['product', 'fastdebug', 'debug'], } @@ -323,7 +323,7 @@ """ Run this program as a sanity test. """ - if (vm in self.ignoredVMs): + if vm in self.ignoredVMs: return True if cwd is None: cwd = self.defaultCwd @@ -368,7 +368,7 @@ """ Run this program as a benchmark. """ - if (vm in self.ignoredVMs): + if vm in self.ignoredVMs: return {} if cwd is None: cwd = self.defaultCwd diff -r d0e82d536325 -r a124cc76cde9 mxtool/mx.py --- a/mxtool/mx.py Sun Feb 23 17:00:35 2014 -0800 +++ b/mxtool/mx.py Wed Mar 05 19:40:15 2014 -0800 @@ -28,6 +28,8 @@ r""" mx is a command line tool for managing the development of Java code organized as suites of projects. +Version 1.x supports a single suite of projects. + Full documentation can be found at https://wiki.openjdk.java.net/display/Graal/The+mx+Tool """ @@ -36,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 @@ -48,14 +51,9 @@ _annotationProcessors = None _primary_suite_path = None _primary_suite = None -_src_suitemodel = None -_dst_suitemodel = None _opts = None _java = None -_check_global_structures = True # can be set False to allow suites with duplicate definitions to load without aborting _warn = False -_hg = None - """ A distribution is a jar or zip file containing the output from one or more Java projects. @@ -382,7 +380,7 @@ return None if resolve and self.mustExist and not exists(path): assert not len(self.urls) == 0, 'cannot find required library ' + self.name + ' ' + path - print('Downloading ' + self.name + ' from ' + str(self.urls)) + print 'Downloading ' + self.name + ' from ' + str(self.urls) download(path, self.urls) return path @@ -393,7 +391,7 @@ if not isabs(path): path = join(self.suite.dir, path) if resolve and len(self.sourceUrls) != 0 and not exists(path): - print('Downloading sources for ' + self.name + ' from ' + str(self.sourceUrls)) + print 'Downloading sources for ' + self.name + ' from ' + str(self.sourceUrls) download(path, self.sourceUrls) return path @@ -442,229 +440,6 @@ else: return None - def can_push(self, s, strict=True): - try: - output = subprocess.check_output(['hg', '-R', s.dir, 'status']) - # super strict - return output == '' - except OSError: - warn(self.missing) - except subprocess.CalledProcessError: - return False - - def default_push(self, sdir): - with open(join(sdir, '.hg', 'hgrc')) as f: - for line in f: - line = line.rstrip() - if line.startswith('default = '): - return line[len('default = '):] - return None - -class SuiteModel: - """ - Defines how to locate a URL/path for a suite, including imported suites. - Conceptually a SuiteModel is defined by a primary suite URL/path and a - map from suite name to URL/path for imported suites. - Subclasses define a specfic implementation. - """ - def __init__(self): - self.primaryDir = None - self.suitenamemap = {} - - def find_suite_dir(self, suitename): - """locates the URL/path for suitename or None if not found""" - abort('find_suite_dir not implemented') - - def set_primary_dir(self, d): - """informs that d is the primary suite directory""" - self._primaryDir = d - - def importee_dir(self, importer_dir, suitename): - """returns the directory path for an import of suitename, given importer_dir""" - abort('importee_dir not implemented') - - def nestedsuites_dirname(self): - """Returns the dirname that contains any nested suites if the model supports that""" - return None - - def _mxDirName(self, name): - # temporary workaround until mx.graal exists - if name == 'graal': - return 'mx' - else: - return 'mx.' + name - - def _search_dir(self, searchDir, mxDirName): - for dd in os.listdir(searchDir): - sd = _is_suite_dir(join(searchDir, dd), mxDirName) - if sd is not None: - return sd - - def _create_suitenamemap(self, optionspec, suitemap): - """Three ways to specify a suite name mapping, in order of precedence: - 1. Explicitly in optionspec. - 2. In suitemap. - 3. in MXSUITEMAP environment variable. - """ - if optionspec != '': - spec = optionspec - elif suitemap is not None: - spec = suitemap - elif get_env('MXSUITEMAP') is not None: - spec = get_env('MXSUITEMAP') - else: - return - pairs = spec.split(',') - for pair in pairs: - mappair = pair.split('=') - self.suitenamemap[mappair[0]] = mappair[1] - - @staticmethod - def set_suitemodel(option, suitemap): - if option.startswith('sibling'): - return SiblingSuiteModel(os.getcwd(), option, suitemap) - elif option.startswith('nested'): - return NestedImportsSuiteModel(os.getcwd(), option, suitemap) - elif option.startswith('path'): - return PathSuiteModel(option[len('path:'):]) - else: - abort('unknown suitemodel type: ' + option) - - @staticmethod - def parse_options(): - # suite-specific args may match the known args so there is no way at this early stage - # to use ArgParser to handle the suite model global arguments, so we just do it manually. - def _get_argvalue(arg, args, i): - if i < len(args): - return args[i] - else: - abort('value expected with ' + arg) - - args = sys.argv[1:] - src_suitemodel_arg = dst_suitemodel_arg = 'sibling' - suitemap_arg = None - - i = 0 - while i < len(args): - arg = args[i] - if arg == '--src-suitemodel': - src_suitemodel_arg = _get_argvalue(arg, args, i + 1) - elif arg == '--dst-suitemodel': - dst_suitemodel_arg = _get_argvalue(arg, args, i + 1) - elif arg == '--suitemap': - suitemap_arg = _get_argvalue(arg, args, i + 1) - elif arg == '-w': - # to get warnings on suite loading issues before command line is parsed - global _warn - _warn = True - elif arg == '-p' or arg == '--primary-suite-path': - global _primary_suite_path - _primary_suite_path = os.path.abspath(_get_argvalue(arg, args, i + 1)) - i = i + 1 - - global _src_suitemodel - _src_suitemodel = SuiteModel.set_suitemodel(src_suitemodel_arg, suitemap_arg) - global _dst_suitemodel - _dst_suitemodel = SuiteModel.set_suitemodel(dst_suitemodel_arg, suitemap_arg) - - -class SiblingSuiteModel(SuiteModel): - """All suites are siblings in the same parent directory, recorded as _suiteRootDir""" - def __init__(self, suiteRootDir, option, suitemap): - SuiteModel.__init__(self) - self._suiteRootDir = suiteRootDir - self._create_suitenamemap(option[len('sibling:'):], suitemap) - - def find_suite_dir(self, name): - return self._search_dir(self._suiteRootDir, self._mxDirName(name)) - - def set_primary_dir(self, d): - SuiteModel.set_primary_dir(self, d) - self._suiteRootDir = dirname(d) - - def importee_dir(self, importer_dir, suitename): - if self.suitenamemap.has_key(suitename): - suitename = self.suitenamemap[suitename] - return join(dirname(importer_dir), suitename) - -class NestedImportsSuiteModel(SuiteModel): - """Imported suites are all siblings in an 'imported_suites' directory of the primary suite""" - def _imported_suites_dirname(self): - return "imported_suites" - - def __init__(self, primaryDir, option, suitemap): - SuiteModel.__init__(self) - self._primaryDir = primaryDir - self._create_suitenamemap(option[len('nested:'):], suitemap) - - def find_suite_dir(self, name): - return self._search_dir(join(self._primaryDir, self._imported_suites_dirname()), self._mxDirName(name)) - - def importee_dir(self, importer_dir, suitename): - if self.suitenamemap.has_key(suitename): - suitename = self.suitenamemap[suitename] - if basename(importer_dir) == basename(self._primaryDir): - # primary is importer - this_imported_suites_dirname = join(importer_dir, self._imported_suites_dirname()) - if not exists(this_imported_suites_dirname): - os.mkdir(this_imported_suites_dirname) - return join(this_imported_suites_dirname, suitename) - else: - return join(dirname(importer_dir), suitename) - - def nestedsuites_dirname(self): - return self._imported_suites_dirname() - -class PathSuiteModel(SuiteModel): - """The most general model. Uses a map from suitename to URL/path provided by the user""" - def __init__(self, path): - SuiteModel.__init__(self) - paths = path.split(',') - self.suit_to_url = {} - for path in paths: - pair = path.split('=') - if len(pair) > 1: - suitename = pair[0] - suiteurl = pair[1] - else: - suitename = basename(pair[0]) - suiteurl = pair[0] - self.suit_to_url[suitename] = suiteurl - - def find_suite_dir(self, suitename): - if self.suit_to_url.has_key(suitename): - return self.suit_to_url[suitename] - else: - return None - - def importee_dir(self, importer_dir, suitename): - if suitename in self.suit_to_url: - return self.suit_to_url[suitename] - else: - abort('suite ' + suitename + ' not found') - -class SuiteImport: - def __init__(self, name, version): - self.name = name - self.version = version - - @staticmethod - def parse_specification(specification): - pair = specification.split(',') - name = pair[0] - if len(pair) > 1: - version = pair[1] - else: - version = None - return SuiteImport(name, version) - - @staticmethod - def tostring(name, version): - return name + ',' + version - - def __str__(self): - return self.name + ',' + self.version - class Suite: def __init__(self, mxDir, primary, load=True): self.dir = dirname(mxDir) @@ -672,13 +447,12 @@ self.projects = [] self.libs = [] self.dists = [] - self.imports = [] self.commands = None self.primary = primary self.requiredMxVersion = None self.name = _suitename(mxDir) # validated in _load_projects if load: - # load suites bottom up to make sure command overriding works properly + # just check that there are no imports self._load_imports() self._load_env() self._load_commands() @@ -687,10 +461,6 @@ def __str__(self): return self.name - def version(self, abortOnError=True): - # we do not cache the version - return _hg.tip(self.dir, abortOnError) - def _load_projects(self): libsMap = dict() projsMap = dict() @@ -838,56 +608,9 @@ mod.mx_init(self) self.commands = mod - def _imports_file(self): - return join(self.mxDir, 'imports') - - def import_timestamp(self): - return TimeStampFile(self._imports_file()) - - def visit_imports(self, visitor, **extra_args): - """ - Visitor support for the imports file. - For each line of the imports file that specifies an import, the visitor function is - called with this suite, a SuiteImport instance created from the line and any extra args - passed to this call. In addition, if extra_args contains a key 'update_versions' that is True, - a StringIO value is added to extra_args with key 'updated_imports', and the visitor is responsible - for writing a (possibly) updated import line to the file, and the file is (possibly) updated after - all imports are processed. - N.B. There is no built-in support for avoiding visiting the same suite multiple times, - as this function only visits the imports of a single suite. If a (recursive) visitor function - wishes to visit a suite exactly once, it must manage that through extra_args. - """ - importsFile = self._imports_file() - if exists(importsFile): - update_versions = extra_args.has_key('update_versions') and extra_args['update_versions'] - out = StringIO.StringIO() if update_versions else None - extra_args['updated_imports'] = out - with open(importsFile) as f: - for line in f: - sline = line.strip() - if len(sline) == 0 or sline.startswith('#'): - if out is not None: - out.write(sline + '\n') - continue - suite_import = SuiteImport.parse_specification(line.strip()) - visitor(self, suite_import, **extra_args) - - if out is not None: - update_file(importsFile, out.getvalue()) - - @staticmethod - def _find_and_loadsuite(importing_suite, suite_import, **extra_args): - """visitor for the initial suite load""" - importMxDir = _src_suitemodel.find_suite_dir(suite_import.name) - if importMxDir is None: - abort('import ' + suite_import.name + ' not found') - importing_suite.imports.append(suite_import) - _loadSuite(importMxDir, False) - # we do not check at this stage whether the tip version of imported_suite - # matches that of the import, since during development, this can and will change - def _load_imports(self): - self.visit_imports(self._find_and_loadsuite) + if exists(join(self.mxDir, 'imports')): + abort('multiple suites are not supported in this version of mx') def _load_env(self): e = join(self.mxDir, 'env') @@ -908,23 +631,23 @@ if self.requiredMxVersion is None: warn("This suite does not express any required mx version. Consider adding 'mxversion=' to your projects file.") elif self.requiredMxVersion > version: - abort("This suite requires mx version " + str(self.requiredMxVersion) + " while your current mx verion is " + str(version) + ". Please update mx.") + abort("This suite requires mx version " + str(self.requiredMxVersion) + " while your current mx version is " + str(version) + ". Please update mx.") # set the global data structures, checking for conflicts unless _check_global_structures is False for p in self.projects: existing = _projects.get(p.name) - if existing is not None and _check_global_structures: + if existing is not None: abort('cannot override project ' + p.name + ' in ' + p.dir + " with project of the same name in " + existing.dir) if not p.name in _opts.ignored_projects: _projects[p.name] = p for l in self.libs: existing = _libs.get(l.name) # Check that suites that define same library are consistent - if existing is not None and existing != l and _check_global_structures: + if existing is not None and existing != l: abort('inconsistent library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir) _libs[l.name] = l for d in self.dists: existing = _dists.get(d.name) - if existing is not None and _check_global_structures: + if existing is not None: # allow redefinition, so use path from existing # abort('cannot redefine distribution ' + d.name) warn('distribution ' + d.name + ' redefined') @@ -1003,7 +726,7 @@ assert self.current == self result = self.toprettyxml(indent, newl, encoding="UTF-8") if escape: - entities = { '"': """, "'": "'", '\n': ' ' } + entities = {'"': """, "'": "'", '\n': ' '} result = xml.sax.saxutils.escape(result, entities) if standalone is not None: result = result.replace('encoding="UTF-8"?>', 'encoding="UTF-8" standalone="' + str(standalone) + '"?>') @@ -1039,14 +762,7 @@ """ Get the list of all loaded suites. """ - if opt_limit_to_suite and _opts.specific_suites: - result = [] - for s in _suites.values(): - if s.name in _opts.specific_suites: - result.append(s) - return result - else: - return _suites.values() + return _suites.values() def suite(name, fatalIfMissing=True): """ @@ -1084,15 +800,7 @@ return projects(True) def _projects_opt_limit_to_suites(projects): - if not _opts.specific_suites: - return projects - else: - result = [] - for p in projects: - s = p.suite - if s.name in _opts.specific_suites: - result.append(p) - return result + return projects def annotation_processors(): """ @@ -1282,16 +990,12 @@ 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('~')) self.add_argument('--java-home', help='bootstrap JDK installation directory (must be JDK 6 or later)', metavar='') self.add_argument('--ignore-project', action='append', dest='ignored_projects', help='name of project to ignore', metavar='', default=[]) - self.add_argument('--suite', action='append', dest='specific_suites', help='limit command to given suite', default=[]) - self.add_argument('--src-suitemodel', help='mechanism for locating imported suites', metavar='', default='sibling') - self.add_argument('--dst-suitemodel', help='mechanism for placing cloned/pushed suites', metavar='', default='sibling') - self.add_argument('--suitemap', help='explicit remapping of suite names', metavar='') if get_os() != 'windows': # Time outs are (currently) implemented with Unix specific functionality self.add_argument('--timeout', help='timeout (in seconds) for command', type=int, default=0, metavar='') @@ -1349,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) @@ -1394,7 +1098,7 @@ # Makes the current subprocess accessible to the abort() function # This is a tuple of the Popen object and args. -_currentSubprocess = None +_currentSubprocess = (None, None) def waitOn(p): if get_os() == 'windows': @@ -1428,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 @@ -1475,7 +1179,7 @@ except KeyboardInterrupt: abort(1) finally: - _currentSubprocess = None + _currentSubprocess = (None, None) if retcode and nonZeroIsFatal: if _opts.verbose: @@ -1556,15 +1260,18 @@ assert m is not None, 'not a recognized version string: ' + ver self.value = int(m.group(1)) - def __str__ (self): + def __str__(self): return '1.' + str(self.value) - def __cmp__ (self, other): + def __cmp__(self, other): if isinstance(other, types.StringType): other = JavaCompliance(other) return cmp(self.value, other.value) + def __hash__(self): + return self.value.__hash__() + """ A version specification as defined in JSR-56 """ @@ -1603,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), []) @@ -1626,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: @@ -1725,9 +1438,8 @@ # import traceback # traceback.print_stack() - currentSubprocess = _currentSubprocess - if currentSubprocess is not None: - p, _ = currentSubprocess + p, _ = _currentSubprocess + if p is not None: if get_os() == 'windows': p.kill() else: @@ -1758,13 +1470,13 @@ def url_open(url): userAgent = 'Mozilla/5.0 (compatible)' - headers = { 'User-Agent' : userAgent } + headers = {'User-Agent' : userAgent} req = urllib2.Request(url, headers=headers) return urllib2.urlopen(req) for url in urls: try: - if (verbose): + if verbose: log('Downloading ' + url + ' to ' + path) if url.startswith('zip:') or url.startswith('jar:'): i = url.find('!/') @@ -1851,6 +1563,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') @@ -1860,12 +1573,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() @@ -2047,7 +1764,7 @@ if java().debug_port is not None: jdtArgs += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(java().debug_port)] - jdtArgs += [ '-jar', jdtJar, + jdtArgs += ['-jar', jdtJar, '-' + compliance, '-cp', cp, '-g', '-enableJavadoc', '-d', outputDir] @@ -2491,7 +2208,7 @@ dotCheckstyle = join(p.dir, '.checkstyle') if not exists(dotCheckstyle): - continue + abort('ERROR: .checkstyle for Project {0} is missing'.format(p.name)) # skip checking this Java project if its Java compliance level is "higher" than the configured JDK if java().javaCompliance < p.javaCompliance: @@ -2566,7 +2283,7 @@ size = 0 while i < len(javafilelist): s = len(javafilelist[i]) + 1 - if (size + s < 30000): + if size + s < 30000: size += s i += 1 else: @@ -2742,10 +2459,7 @@ slm.open('sourceLookupDirector') slm.open('sourceContainers', {'duplicates' : 'false'}) - # Every Java program depends on the JRE - memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml(standalone='no') - slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) - + javaCompliance = None for dep in deps: if dep.isLibrary(): if hasattr(dep, 'eclipse.container'): @@ -2757,6 +2471,15 @@ else: memento = XMLDoc().element('javaProject', {'name' : dep.name}).xml(standalone='no') slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'}) + if javaCompliance is None or dep.javaCompliance < javaCompliance: + javaCompliance = dep.javaCompliance + + if javaCompliance: + memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-' + str(javaCompliance)}).xml(standalone='no') + slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) + else: + memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml(standalone='no') + slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) slm.close('sourceContainers') slm.close('sourceLookupDirector') @@ -2870,12 +2593,10 @@ generate_eclipse_workingsets() def _check_ide_timestamp(suite, configZip, ide): - """return True if and only if the projects file, imports file, eclipse-settings files, and mx itself are all older than configZip""" + """return True if and only if the projects file, eclipse-settings files, and mx itself are all older than configZip""" projectsFile = join(suite.mxDir, 'projects') if configZip.isOlderThan(projectsFile): return False - if configZip.isOlderThan(suite.import_timestamp()): - return False # Assume that any mx change might imply changes to the generated IDE files if configZip.isOlderThan(__file__): return False @@ -2933,7 +2654,7 @@ out.element('classpathentry', {'kind' : 'src', 'path' : 'src_gen'}) files.append(genDir) - # Every Java program depends on the JRE + # Every Java program depends on a JRE out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-' + str(p.javaCompliance)}) if exists(join(p.dir, 'plugin.xml')): # eclipse plugin project @@ -3135,7 +2856,7 @@ launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'}) launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn}) launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'}) - launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java().jdk}) + launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java().jdk}) launchOut.close('mapAttribute') if refresh: @@ -3258,9 +2979,6 @@ else: return _find_eclipse_wsroot(split[0]) -def _foobar(val): - print(val) - def _make_workingset_xml(workingSets): wsdoc = XMLDoc() wsdoc.open('workingSetManager') @@ -3286,30 +3004,46 @@ self.current_ws = None self.seen_ws = list() self.seen_projects = list() + self.aggregate_ws = False + self.nested_ws = False ps = ParserState() # parsing logic def _ws_start(name, attributes): if name == 'workingSet': - ps.current_ws_name = attributes['name'] - if workingSets.has_key(ps.current_ws_name): - ps.current_ws = workingSets[ps.current_ws_name] - ps.seen_ws.append(ps.current_ws_name) - ps.seen_projects = list() - else: - ps.current_ws = None + if attributes.has_key('name'): + ps.current_ws_name = attributes['name'] + if attributes.has_key('aggregate') and attributes['aggregate'] == 'true': + ps.aggregate_ws = True + ps.current_ws = None + elif workingSets.has_key(ps.current_ws_name): + ps.current_ws = workingSets[ps.current_ws_name] + ps.seen_ws.append(ps.current_ws_name) + ps.seen_projects = list() + else: + ps.current_ws = None target.open(name, attributes) parser.StartElementHandler = _ws_item def _ws_end(name): + closeAndResetHandler = False if name == 'workingSet': - if not ps.current_ws is None: - for p in ps.current_ws: - if not p in ps.seen_projects: - _workingset_element(target, p) - target.close('workingSet') - parser.StartElementHandler = _ws_start + if ps.aggregate_ws: + if ps.nested_ws: + ps.nested_ws = False + else: + ps.aggregate_ws = False + closeAndResetHandler = True + else: + if not ps.current_ws is None: + for p in ps.current_ws: + if not p in ps.seen_projects: + _workingset_element(target, p) + closeAndResetHandler = True + if closeAndResetHandler: + target.close('workingSet') + parser.StartElementHandler = _ws_start elif name == 'workingSetManager': # process all working sets that are new to the file for w in sorted(workingSets.keys()): @@ -3323,10 +3057,17 @@ if name == 'item': if ps.current_ws is None: target.element(name, attributes) + elif not attributes.has_key('elementID') and attributes.has_key('factoryID') and attributes.has_key('path') and attributes.has_key('type'): + target.element(name, attributes) + p_name = attributes['path'][1:] # strip off the leading '/' + ps.seen_projects.append(p_name) else: p_name = attributes['elementID'][1:] # strip off the leading '=' _workingset_element(target, p_name) ps.seen_projects.append(p_name) + elif name == 'workingSet': + ps.nested_ws = True + target.element(name, attributes) # process document parser.StartElementHandler = _ws_start @@ -3377,7 +3118,7 @@ out.element('description', data='Builds, tests, and runs the project ' + p.name + '.') out.element('import', {'file' : 'nbproject/build-impl.xml'}) out.open('target', {'name' : '-post-compile'}) - out.open('exec', { 'executable' : sys.executable}) + out.open('exec', {'executable' : sys.executable}) out.element('env', {'key' : 'JAVA_HOME', 'value' : java().jdk}) out.element('arg', {'value' : os.path.abspath(__file__)}) out.element('arg', {'value' : 'archive'}) @@ -3626,9 +3367,6 @@ # no point in traversing .hg if '.hg' in dirnames: dirnames.remove('.hg') - # if there are nested suites must not scan those now, as they are not in projectDirs - if _src_suitemodel.nestedsuites_dirname() in dirnames: - dirnames.remove(_src_suitemodel.nestedsuites_dirname()) elif dirpath in projectDirs: # don't traverse subdirs of an existing project in this suite dirnames[:] = [] @@ -4047,266 +3785,6 @@ return kwargs.pop(0) return None -def sclone(args): - """clone a suite repository, and its imported suites""" - _hg.check() - parser = ArgumentParser(prog='mx sclone') - parser.add_argument('--source', help='url/path of repo containing suite', metavar='') - parser.add_argument('--dest', help='destination directory (default basename of source)', metavar='') - parser.add_argument("--no-imports", action='store_true', help='do not clone imported suites') - parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...') - args = parser.parse_args(args) - # check for non keyword args - if args.source is None: - args.source = _kwArg(args.nonKWArgs) - if args.dest is None: - args.dest = _kwArg(args.nonKWArgs) - if len(args.nonKWArgs) > 0: - abort('unrecognized args: ' + ' '.join(args.nonKWArgs)) - - if args.source is None: - # must be primary suite and dest is required - if _primary_suite is None: - abort('--source missing and no primary suite found') - if args.dest is None: - abort('--dest required when --source is not given') - source = _primary_suite.dir - else: - source = args.source - - if args.dest is not None: - dest = args.dest - else: - dest = basename(source) - - dest = os.path.abspath(dest) - # We can now set the primary dir for the src/dst suitemodel - _dst_suitemodel.set_primary_dir(dest) - _src_suitemodel.set_primary_dir(source) - - _sclone(source, dest, None, args.no_imports) - -def _sclone(source, dest, version, no_imports): - cmd = ['hg', 'clone'] - if version is not None: - cmd.append('-r') - cmd.append(version) - cmd.append(source) - cmd.append(dest) - - run(cmd) - - mxDir = _is_suite_dir(dest) - if mxDir is None: - warn(source + ' is not an mx suite') - return None - - # create a Suite (without loading) to enable imports visitor - s = Suite(mxDir, False, load=False) - if not no_imports: - s.visit_imports(_scloneimports_visitor, source=source) - return s - -def _scloneimports_visitor(s, suite_import, source, **extra_args): - """ - cloneimports visitor for Suite.visit_imports. - The destination information is encapsulated by 's' - """ - _scloneimports(s, suite_import, source) - -def _scloneimports_suitehelper(sdir): - mxDir = _is_suite_dir(sdir) - if mxDir is None: - abort(sdir + ' is not an mx suite') - else: - # create a Suite (without loading) to enable imports visitor - return Suite(mxDir, False, load=False) - -def _scloneimports(s, suite_import, source): - # clone first, then visit imports once we can locate them - importee_source = _src_suitemodel.importee_dir(source, suite_import.name) - importee_dest = _dst_suitemodel.importee_dir(s.dir, suite_import.name) - if exists(importee_dest): - # already exists in the suite model, but may be wrong version - importee_suite = _scloneimports_suitehelper(importee_dest) - if suite_import.version is not None and importee_suite.version() != suite_import.version: - abort("imported version of " + suite_import.name + " in " + s.name + " does not match the version in already existing suite: " + importee_suite.dir) - importee_suite.visit_imports(_scloneimports_visitor, source=importee_source) - else: - _sclone(importee_source, importee_dest, suite_import.version, False) - # _clone handles the recursive visit of the new imports - -def scloneimports(args): - """clone the imports of an existing suite""" - _hg.check() - parser = ArgumentParser(prog='mx scloneimports') - parser.add_argument('--source', help='url/path of repo containing suite', metavar='') - parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...') - args = parser.parse_args(args) - # check for non keyword args - if args.source is None: - args.source = _kwArg(args.nonKWArgs) - - if not os.path.isdir(args.source): - abort(args.source + ' is not a directory') - - s = _scloneimports_suitehelper(args.source) - - default_path = _hg.default_push(args.source) - - if default_path is None: - abort('no default path in ' + join(args.source, '.hg', 'hgrc')) - - # We can now set the primary dir for the dst suitemodel - # N.B. source is effectively the destination and the default_path is the (original) source - _dst_suitemodel.set_primary_dir(args.source) - - s.visit_imports(_scloneimports_visitor, source=default_path) - -def _spush_import_visitor(s, suite_import, dest, checks, clonemissing, **extra_args): - """push visitor for Suite.visit_imports""" - if dest is not None: - dest = _dst_suitemodel.importee_dir(dest, suite_import.name) - _spush(suite(suite_import.name), suite_import, dest, checks, clonemissing) - -def _spush_check_import_visitor(s, suite_import, **extra_args): - """push check visitor for Suite.visit_imports""" - currentTip = suite(suite_import.name).version() - if currentTip != suite_import.version: - abort('imported version of ' + suite_import.name + ' in suite ' + s.name + ' does not match tip') - -def _spush(s, suite_import, dest, checks, clonemissing): - if checks: - if not _hg.can_push(s): - abort('working directory ' + s.dir + ' contains uncommitted changes, push aborted') - - # check imports first - if checks: - s.visit_imports(_spush_check_import_visitor) - - # ok, push imports - s.visit_imports(_spush_import_visitor, dest=dest, checks=checks, clonemissing=clonemissing) - - dest_exists = True - - if clonemissing: - if not os.path.exists(dest): - dest_exists = False - - def add_version(cmd, suite_import): - if suite_import is not None and suite_import.version is not None: - cmd.append('-r') - cmd.append(suite_import.version) - - if dest_exists: - cmd = ['hg', '-R', s.dir, 'push'] - add_version(cmd, suite_import) - if dest is not None: - cmd.append(dest) - rc = run(cmd, nonZeroIsFatal=False) - if rc != 0: - # rc of 1 not an error, means no changes - if rc != 1: - abort("push failed, exit code " + str(rc)) - else: - cmd = ['hg', 'clone'] - add_version(cmd, suite_import) - cmd.append(s.dir) - cmd.append(dest) - run(cmd) - -def spush(args): - """push primary suite and all its imports""" - _hg.check() - parser = ArgumentParser(prog='mx spush') - parser.add_argument('--dest', help='url/path of repo to push to (default as per hg push)', metavar='') - parser.add_argument('--no-checks', action='store_true', help='checks on status, versions are disabled') - parser.add_argument('--clonemissing', action='store_true', help='clone missing imported repos at destination (forces --no-checks)') - parser.add_argument('nonKWArgs', nargs=REMAINDER, metavar='source [dest]...') - args = parser.parse_args(args) - if args.dest is None: - args.dest = _kwArg(args.nonKWArgs) - if len(args.nonKWArgs) > 0: - abort('unrecognized args: ' + ' '.join(args.nonKWArgs)) - - if args.dest is not None and not os.path.isdir(args.dest): - abort('destination must be a directory') - - s = _check_primary_suite() - - if args.clonemissing: - if args.dest is None: - abort('--dest required with --clonemissing') - args.nochecks = True - - if args.dest is not None: - _dst_suitemodel.set_primary_dir(args.dest) - - _spush(s, None, args.dest, not args.no_checks, args.clonemissing) - -def _supdate_import_visitor(s, suite_import, **extra_args): - _supdate(suite(suite_import.name), suite_import) - -def _supdate(s, suite_import): - s.visit_imports(_supdate_import_visitor) - - run(['hg', '-R', s.dir, 'update']) - -def supdate(args): - """update primary suite and all its imports""" - - _hg.check() - s = _check_primary_suite() - - _supdate(s, None) - -def _scheck_imports_visitor(s, suite_import, update_versions, updated_imports): - """scheckimports visitor for Suite.visit_imports""" - _scheck_imports(s, suite(suite_import.name), suite_import, update_versions, updated_imports) - -def _scheck_imports(importing_suite, imported_suite, suite_import, update_versions, updated_imports): - # check imports recursively - imported_suite.visit_imports(_scheck_imports_visitor, update_versions=update_versions) - - currentTip = imported_suite.version() - if currentTip != suite_import.version: - print('imported version of ' + imported_suite.name + ' in ' + importing_suite.name + ' does not match tip' + (': updating' if update_versions else '')) - - if update_versions: - suite_import.version = currentTip - line = str(suite_import) - updated_imports.write(line + '\n') - -def scheckimports(args): - """check that suite import versions are up to date""" - parser = ArgumentParser(prog='mx scheckimports') - parser.add_argument('--update-versions', help='update imported version ids', action='store_true') - args = parser.parse_args(args) - _check_primary_suite().visit_imports(_scheck_imports_visitor, update_versions=args.update_versions) - -def _spull_import_visitor(s, suite_import, update_versions, updated_imports): - """pull visitor for Suite.visit_imports""" - _spull(suite(suite_import.name), update_versions, updated_imports) - -def _spull(s, update_versions, updated_imports): - _hg.check() - # pull imports first - s.visit_imports(_spull_import_visitor, update_versions=update_versions) - - run(['hg', '-R', s.dir, 'pull', '-u']) - if update_versions and updated_imports is not None: - tip = s.version() - updated_imports.write(SuiteImport.tostring(s.name, tip) + '\n') - -def spull(args): - """pull primary suite and all its imports""" - _hg.check() - parser = ArgumentParser(prog='mx spull') - parser.add_argument('--update-versions', action='store_true', help='update version ids of imported suites') - args = parser.parse_args(args) - - _spull(_check_primary_suite(), args.update_versions, None) - def findclass(args, logToConsole=True): """find all classes matching a given substring""" matches = [] @@ -4421,7 +3899,7 @@ def warn(msg): if _warn: - print('WARNING: ' + msg) + print 'WARNING: ' + msg # Table of commands in alphabetical order. # Keys are command names, value are lists: [, , ...] @@ -4443,12 +3921,6 @@ 'ideinit': [ideinit, ''], 'archive': [archive, '[options]'], 'projectgraph': [projectgraph, ''], - 'sclone': [sclone, '[options]'], - 'scheckimports': [scheckimports, ''], - 'scloneimports': [scloneimports, '[options]'], - 'spull': [spull, '[options'], - 'spush': [spush, '[options'], - 'supdate': [supdate, ''], 'pylint': [pylint, ''], 'javap': [javap, ''], 'javadoc': [javadoc, '[options]'], @@ -4486,12 +3958,6 @@ else: return _primary_suite -def _needs_primary_suite(command): - return not command.startswith("sclone") - -def _needs_primary_suite_cl(): - return not any("sclone" in s for s in sys.argv[1:]) - def _findPrimarySuiteMxDirFrom(d): """ search for a suite directory upwards from 'd' """ while d: @@ -4522,34 +3988,15 @@ return _findPrimarySuiteMxDirFrom(dirname(__file__)) def main(): - SuiteModel.parse_options() - - global _hg - _hg = HgConfig() - - primary_suite_error = 'no primary suite found' primarySuiteMxDir = _findPrimarySuiteMxDir() if primarySuiteMxDir: - _src_suitemodel.set_primary_dir(dirname(primarySuiteMxDir)) global _primary_suite _primary_suite = _loadSuite(primarySuiteMxDir, True) else: - # in general this is an error, except for the sclone/scloneimports commands, - # and an extensions command will likely not parse in this case, as any extra arguments - # will not have been added to _argParser. - # If the command line does not contain a string matching one of the exceptions, we can safely abort, - # but not otherwise, as we can't be sure the string isn't in a value for some other option. - if _needs_primary_suite_cl(): - abort(primary_suite_error) + abort('no primary suite found') opts, commandAndArgs = _argParser._parse_cmd_line() - if primarySuiteMxDir is None: - if len(commandAndArgs) > 0 and _needs_primary_suite(commandAndArgs[0]): - abort(primary_suite_error) - else: - warn(primary_suite_error) - global _opts, _java _opts = opts _java = JavaConfig(opts) diff -r d0e82d536325 -r a124cc76cde9 src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -1006,6 +1006,15 @@ __ delayed()->nop(); } +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { + AdapterGenerator agen(masm); + agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); +} + // --------------------------------------------------------------- AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, int total_args_passed, @@ -1016,9 +1025,7 @@ AdapterFingerPrint* fingerprint) { address i2c_entry = __ pc(); - AdapterGenerator agen(masm); - - agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); + gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); // ------------------------------------------------------------------------- @@ -1063,7 +1070,7 @@ } address c2i_entry = __ pc(); - + AdapterGenerator agen(masm); agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup); __ flush(); diff -r d0e82d536325 -r a124cc76cde9 src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -711,7 +711,7 @@ __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, int total_args_passed, int comp_args_on_stack, const BasicType *sig_bt, diff -r d0e82d536325 -r a124cc76cde9 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -642,7 +642,7 @@ __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, int total_args_passed, int comp_args_on_stack, const BasicType *sig_bt, diff -r d0e82d536325 -r a124cc76cde9 src/gpu/hsail/vm/gpu_hsail.cpp --- a/src/gpu/hsail/vm/gpu_hsail.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/gpu/hsail/vm/gpu_hsail.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -25,43 +25,60 @@ #include "precompiled.hpp" #include "runtime/javaCalls.hpp" #include "runtime/gpu.hpp" +#include "hsail/vm/gpu_hsail.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" +#include "graal/graalEnv.hpp" +#include "graal/graalCompiler.hpp" +#include "graal/graalJavaAccess.hpp" #include "hsailKernelArguments.hpp" -void * gpu::Hsail::_device_context; +// 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 { \ + GRAAL_VM_ENTRY_MARK; \ + +// Entry to GPU native method implementation that calls a JNI function +// and hence cannot transition current thread to '_thread_in_vm'. +#define GPU_ENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL name signature { \ + +#define GPU_END } + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(f)) + +#define OBJECT "Ljava/lang/Object;" +#define STRING "Ljava/lang/String;" +#define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" + +// public native void executeKernel(HotSpotNmethod kernel, int jobSize, int i, int j, Object[] args) throws InvalidInstalledCodeException; -gpu::Hsail::okra_create_context_func_t gpu::Hsail::_okra_create_context; -gpu::Hsail::okra_create_kernel_func_t gpu::Hsail::_okra_create_kernel; -gpu::Hsail::okra_push_object_func_t gpu::Hsail::_okra_push_object; -gpu::Hsail::okra_push_boolean_func_t gpu::Hsail::_okra_push_boolean; -gpu::Hsail::okra_push_byte_func_t gpu::Hsail::_okra_push_byte; -gpu::Hsail::okra_push_double_func_t gpu::Hsail::_okra_push_double; -gpu::Hsail::okra_push_float_func_t gpu::Hsail::_okra_push_float; -gpu::Hsail::okra_push_int_func_t gpu::Hsail::_okra_push_int; -gpu::Hsail::okra_push_long_func_t gpu::Hsail::_okra_push_long; -gpu::Hsail::okra_execute_with_range_func_t gpu::Hsail::_okra_execute_with_range; -gpu::Hsail::okra_clearargs_func_t gpu::Hsail::_okra_clearargs; -gpu::Hsail::okra_register_heap_func_t gpu::Hsail::_okra_register_heap; +JNINativeMethod Hsail::HSAIL_methods[] = { + {CC"initialize", CC"()Z", FN_PTR(Hsail::initialize)}, + {CC"generateKernel", CC"([B" STRING ")J", FN_PTR(Hsail::generate_kernel)}, + {CC"executeKernel0", CC"("HS_INSTALLED_CODE"I["OBJECT")Z", FN_PTR(Hsail::execute_kernel_void_1d)}, +}; + +void * Hsail::_device_context = NULL; + +Hsail::okra_create_context_func_t Hsail::_okra_create_context; +Hsail::okra_create_kernel_func_t Hsail::_okra_create_kernel; +Hsail::okra_push_object_func_t Hsail::_okra_push_object; +Hsail::okra_push_boolean_func_t Hsail::_okra_push_boolean; +Hsail::okra_push_byte_func_t Hsail::_okra_push_byte; +Hsail::okra_push_double_func_t Hsail::_okra_push_double; +Hsail::okra_push_float_func_t Hsail::_okra_push_float; +Hsail::okra_push_int_func_t Hsail::_okra_push_int; +Hsail::okra_push_long_func_t Hsail::_okra_push_long; +Hsail::okra_execute_with_range_func_t Hsail::_okra_execute_with_range; +Hsail::okra_clearargs_func_t Hsail::_okra_clearargs; +Hsail::okra_register_heap_func_t Hsail::_okra_register_heap; -bool gpu::Hsail::initialize_gpu() { - // All the initialization is done in the okra library so - // nothing to do here. - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] Simulator: initialize_gpu"); - } - return true; -} - -unsigned int gpu::Hsail::total_cores() { - // This is not important with simulator - return 1; -} - -void gpu::Hsail::register_heap() { +void Hsail::register_heap() { // After the okra functions are set up and the heap is initialized, register the java heap with HSA guarantee(Universe::heap() != NULL, "heap should be there by now."); if (TraceGPUInteraction) { @@ -71,48 +88,67 @@ _okra_register_heap(Universe::heap()->base(), Universe::heap()->capacity()); } -bool gpu::Hsail::execute_kernel_void_1d(address kernel, int dimX, jobject args, methodHandle& mh) { - objArrayOop argsArray = (objArrayOop) JNIHandles::resolve(args); +GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args_handle)) + + ResourceMark rm; + jlong nmethodValue = HotSpotInstalledCode::codeBlob(kernel_handle); + if (nmethodValue == 0) { + SharedRuntime::throw_and_post_jvmti_exception(JavaThread::current(), vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL); + } + nmethod* nm = (nmethod*) (address) nmethodValue; + methodHandle mh = nm->method(); + Symbol* signature = mh->signature(); + + void* kernel = (void*) HotSpotInstalledCode::codeStart(kernel_handle); + if (kernel == NULL) { + SharedRuntime::throw_and_post_jvmti_exception(JavaThread::current(), vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL); + } + + objArrayOop args = (objArrayOop) JNIHandles::resolve(args_handle); // Reset the kernel arguments _okra_clearargs(kernel); // This object sets up the kernel arguments - HSAILKernelArguments hka(kernel, mh->signature(), argsArray, mh->is_static()); + HSAILKernelArguments hka((address) kernel, mh->signature(), args, mh->is_static()); // Run the kernel - bool success = _okra_execute_with_range(kernel, dimX); - return success; -} + return _okra_execute_with_range(kernel, dimX); +GPU_END + +GPU_ENTRY(jlong, Hsail::generate_kernel, (JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle)) + guarantee(_okra_create_kernel != NULL, "[HSAIL] Okra not linked"); + ResourceMark rm; + jsize name_len = env->GetStringLength(name_handle); + jsize code_len = env->GetArrayLength(code_handle); -void *gpu::Hsail::generate_kernel(unsigned char *code, int code_len, const char *name) { + char* name = NEW_RESOURCE_ARRAY(char, name_len + 1); + unsigned char *code = NEW_RESOURCE_ARRAY(unsigned char, code_len + 1); - gpu::Hsail::register_heap(); + code[code_len] = 0; + name[name_len] = 0; + + env->GetByteArrayRegion(code_handle, 0, code_len, (jbyte*) code); + env->GetStringUTFRegion(name_handle, 0, name_len, name); + + register_heap(); // The kernel entrypoint is always run for the time being const char* entryPointName = "&run"; _device_context = _okra_create_context(); - // code is not null terminated, must be a better way to do this - unsigned char* nullTerminatedCodeBuffer = (unsigned char*) malloc(code_len + 1); - memcpy(nullTerminatedCodeBuffer, code, code_len); - nullTerminatedCodeBuffer[code_len] = 0; - void* kernel = _okra_create_kernel(_device_context, nullTerminatedCodeBuffer, entryPointName); - free(nullTerminatedCodeBuffer); - return kernel; -} + return (jlong) _okra_create_kernel(_device_context, code, entryPointName); +GPU_END #if defined(LINUX) -static const char okra_library_name[] = "libokra_x86_64.so"; -#elif defined (_WINDOWS) -static char const okra_library_name[] = "okra_x86_64.dll"; +static const char* okra_library_name = "libokra_x86_64.so"; +#elif defined(_WINDOWS) +static char const* okra_library_name = "okra_x86_64.dll"; #else -static char const okra_library_name[] = ""; +static char const* okra_library_name = NULL; #endif -#define STD_BUFFER_SIZE 1024 - #define STRINGIFY(x) #x #define LOOKUP_OKRA_FUNCTION(name, alias) \ @@ -120,48 +156,76 @@ CAST_TO_FN_PTR(alias##_func_t, os::dll_lookup(handle, STRINGIFY(name))); \ if (_##alias == NULL) { \ tty->print_cr("[HSAIL] ***** Error: Failed to lookup %s in %s, wrong version of OKRA?", STRINGIFY(name), okra_library_name); \ - return 0; \ + return false; \ } \ -bool gpu::Hsail::probe_linkage() { - if (okra_library_name != NULL) { - char *buffer = (char*)malloc(STD_BUFFER_SIZE); - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] library is %s", okra_library_name); - } - void *handle = os::dll_load(okra_library_name, buffer, STD_BUFFER_SIZE); - free(buffer); - if (handle != NULL) { - - LOOKUP_OKRA_FUNCTION(okra_create_context, okra_create_context); - LOOKUP_OKRA_FUNCTION(okra_create_kernel, okra_create_kernel); - LOOKUP_OKRA_FUNCTION(okra_push_object, okra_push_object); - LOOKUP_OKRA_FUNCTION(okra_push_boolean, okra_push_boolean); - LOOKUP_OKRA_FUNCTION(okra_push_byte, okra_push_byte); - LOOKUP_OKRA_FUNCTION(okra_push_double, okra_push_double); - LOOKUP_OKRA_FUNCTION(okra_push_float, okra_push_float); - LOOKUP_OKRA_FUNCTION(okra_push_int, okra_push_int); - LOOKUP_OKRA_FUNCTION(okra_push_long, okra_push_long); - LOOKUP_OKRA_FUNCTION(okra_execute_with_range, okra_execute_with_range); - LOOKUP_OKRA_FUNCTION(okra_clearargs, okra_clearargs); - LOOKUP_OKRA_FUNCTION(okra_register_heap, okra_register_heap); - - return true; - } else { - // Unable to dlopen okra - if (TraceGPUInteraction) { - tty->print_cr("[HSAIL] library load failed."); - } - return false; - } - } else { +GPU_ENTRY(jboolean, Hsail::initialize, (JNIEnv *env, jclass)) + if (okra_library_name == NULL) { if (TraceGPUInteraction) { tty->print_cr("Unsupported HSAIL platform"); } return false; } + + // here we know we have a valid okra_library_name to try to load + char ebuf[O_BUFLEN]; if (TraceGPUInteraction) { - tty->print_cr("Failed to find HSAIL linkage"); + tty->print_cr("[HSAIL] library is %s", okra_library_name); + } + void *handle = os::dll_load(okra_library_name, ebuf, O_BUFLEN); + // try alternate location if env variable set + char *okra_lib_name_from_env_var = getenv("_OKRA_SIM_LIB_PATH_"); + if ((handle == NULL) && (okra_lib_name_from_env_var != NULL)) { + handle = os::dll_load(okra_lib_name_from_env_var, ebuf, O_BUFLEN); + if ((handle != NULL) && TraceGPUInteraction) { + tty->print_cr("[HSAIL] using _OKRA_SIM_LIB_PATH_=%s", getenv("_OKRA_SIM_LIB_PATH_")); + } + } + + if (handle == NULL) { + // Unable to dlopen okra + if (TraceGPUInteraction) { + tty->print_cr("[HSAIL] library load failed."); + } + return false; } - return false; + + guarantee(_okra_create_context == NULL, "cannot repeat GPU initialization"); + + // at this point we know handle is valid and we can lookup the functions + LOOKUP_OKRA_FUNCTION(okra_create_context, okra_create_context); + LOOKUP_OKRA_FUNCTION(okra_create_kernel, okra_create_kernel); + LOOKUP_OKRA_FUNCTION(okra_push_object, okra_push_object); + LOOKUP_OKRA_FUNCTION(okra_push_boolean, okra_push_boolean); + LOOKUP_OKRA_FUNCTION(okra_push_byte, okra_push_byte); + LOOKUP_OKRA_FUNCTION(okra_push_double, okra_push_double); + LOOKUP_OKRA_FUNCTION(okra_push_float, okra_push_float); + LOOKUP_OKRA_FUNCTION(okra_push_int, okra_push_int); + LOOKUP_OKRA_FUNCTION(okra_push_long, okra_push_long); + LOOKUP_OKRA_FUNCTION(okra_execute_with_range, okra_execute_with_range); + LOOKUP_OKRA_FUNCTION(okra_clearargs, okra_clearargs); + LOOKUP_OKRA_FUNCTION(okra_register_heap, okra_register_heap); + // if we made it this far, real success + + gpu::initialized_gpu("Okra"); + + return true; +GPU_END + +bool Hsail::register_natives(JNIEnv* env) { + jclass klass = env->FindClass("com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend"); + if (klass == NULL) { + if (TraceGPUInteraction) { + tty->print_cr("HSAILHotSpotBackend class not found"); + } + return false; + } + jint status = env->RegisterNatives(klass, HSAIL_methods, sizeof(HSAIL_methods) / sizeof(JNINativeMethod)); + if (status != JNI_OK) { + if (TraceGPUInteraction) { + tty->print_cr("Error registering natives for HSAILHotSpotBackend: %d", status); + } + return false; + } + return true; } diff -r d0e82d536325 -r a124cc76cde9 src/gpu/hsail/vm/gpu_hsail.hpp --- a/src/gpu/hsail/vm/gpu_hsail.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/gpu/hsail/vm/gpu_hsail.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -26,17 +26,27 @@ #define GPU_HSAIL_HPP class Hsail { - friend class gpu; + +private: + + static JNINativeMethod HSAIL_methods[]; - protected: - static bool probe_linkage(); - static bool initialize_gpu(); - static unsigned int total_cores(); - static void* generate_kernel(unsigned char *code, int code_len, const char *name); - static bool execute_kernel_void_1d(address kernel, int dimX, jobject args, methodHandle& mh); + // static native boolean initialize(); + JNIEXPORT static jboolean initialize(JNIEnv *env, jclass); + + // static native long generateKernel(byte[] targetCode, String name); + JNIEXPORT static jlong generate_kernel(JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle); + + // static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args); + JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv *env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args); + static void register_heap(); public: + + // Registers the implementations for the native methods in HSAILHotSpotBackend + static bool register_natives(JNIEnv* env); + #if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) typedef unsigned long long CUdeviceptr; #else @@ -56,7 +66,7 @@ typedef bool (*okra_execute_with_range_func_t)(void*, jint); typedef bool (*okra_clearargs_func_t)(void*); typedef bool (*okra_register_heap_func_t)(void*, size_t); - + public: static okra_create_context_func_t _okra_create_context; static okra_create_kernel_func_t _okra_create_kernel; diff -r d0e82d536325 -r a124cc76cde9 src/gpu/hsail/vm/hsailKernelArguments.cpp --- a/src/gpu/hsail/vm/hsailKernelArguments.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/gpu/hsail/vm/hsailKernelArguments.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -46,7 +46,7 @@ jvalue jValue; java_lang_boxing_object::get_value(arg, &jValue); - bool pushed = gpu::Hsail::_okra_push_boolean(_kernel, jValue.z); + bool pushed = Hsail::_okra_push_boolean(_kernel, jValue.z); assert(pushed == true, "arg push failed"); } @@ -58,7 +58,7 @@ jvalue jValue; java_lang_boxing_object::get_value(arg, &jValue); - bool pushed = gpu::Hsail::_okra_push_byte(_kernel, jValue.b); + bool pushed = Hsail::_okra_push_byte(_kernel, jValue.b); assert(pushed == true, "arg push failed"); } @@ -70,9 +70,9 @@ 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 = gpu::Hsail::_okra_push_double(_kernel, jValue.d); + bool pushed = Hsail::_okra_push_double(_kernel, jValue.d); assert(pushed == true, "arg push failed"); } @@ -84,16 +84,16 @@ 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 = gpu::Hsail::_okra_push_float(_kernel, jValue.f); + bool pushed = Hsail::_okra_push_float(_kernel, jValue.f); assert(pushed == true, "float push failed"); } 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,8 +106,11 @@ 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 = gpu::Hsail::_okra_push_int(_kernel, jValue.i); + bool pushed = Hsail::_okra_push_int(_kernel, jValue.i); assert(pushed == true, "arg push failed"); } @@ -118,8 +121,11 @@ 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 = gpu::Hsail::_okra_push_long(_kernel, jValue.j); + bool pushed = Hsail::_okra_push_long(_kernel, jValue.j); assert(pushed == true, "arg push failed"); } @@ -127,22 +133,22 @@ 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 = gpu::Hsail::_okra_push_object(_kernel, arg); + bool pushed = Hsail::_okra_push_object(_kernel, arg); assert(pushed == true, "arg push failed"); } 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,10 +156,10 @@ } 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 = gpu::Hsail::_okra_push_object(_kernel, arg); + bool pushed = Hsail::_okra_push_object(_kernel, arg); assert(pushed == true, "arg push failed"); } diff -r d0e82d536325 -r a124cc76cde9 src/gpu/hsail/vm/hsailKernelArguments.hpp --- a/src/gpu/hsail/vm/hsailKernelArguments.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/gpu/hsail/vm/hsailKernelArguments.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -26,10 +26,11 @@ #define KERNEL_ARGUMENTS_HSAIL_HPP #include "runtime/gpu.hpp" +#include "hsail/vm/gpu_hsail.hpp" #include "runtime/signature.hpp" class HSAILKernelArguments : public SignatureIterator { - friend class gpu::Hsail; + friend class Hsail; public: @@ -62,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' @@ -71,7 +73,7 @@ if (TraceGPUInteraction) { tty->print_cr("[HSAIL] instance method, this 0x%08x, is a %s", (address) arg, arg->klass()->external_name()); } - bool pushed = gpu::Hsail::_okra_push_object(kernel, arg); + bool pushed = Hsail::_okra_push_object(kernel, arg); assert(pushed == true, "'this' push failed"); } else { if (TraceGPUInteraction) { @@ -102,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 d0e82d536325 -r a124cc76cde9 src/gpu/ptx/vm/gpu_ptx.cpp --- a/src/gpu/ptx/vm/gpu_ptx.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/gpu/ptx/vm/gpu_ptx.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -25,34 +25,77 @@ #include "precompiled.hpp" #include "runtime/javaCalls.hpp" #include "runtime/gpu.hpp" +#include "ptx/vm/gpu_ptx.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" +#include "memory/gcLocker.inline.hpp" #include "runtime/interfaceSupport.hpp" -#include "ptxKernelArguments.hpp" +#include "runtime/vframe.hpp" +#include "graal/graalEnv.hpp" +#include "graal/graalCompiler.hpp" + +#define T_BYTE_SIZE 1 +#define T_BOOLEAN_SIZE 4 +#define T_INT_BYTE_SIZE 4 +#define T_FLOAT_BYTE_SIZE 4 +#define T_DOUBLE_BYTE_SIZE 8 +#define T_LONG_BYTE_SIZE 8 +#define T_OBJECT_BYTE_SIZE sizeof(intptr_t) +#define T_ARRAY_BYTE_SIZE sizeof(intptr_t) -void * gpu::Ptx::_device_context; -int gpu::Ptx::_cu_device = 0; +// 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] " #name); \ + GRAAL_VM_ENTRY_MARK; \ + +// Entry to GPU native method implementation that calls a JNI function +// and hence cannot transition current thread to '_thread_in_vm'. +#define GPU_ENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL name signature { \ + if (TraceGPUInteraction) tty->print_cr("[CUDA] Ptx::" #name); \ + +#define GPU_END } + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(f)) -gpu::Ptx::cuda_cu_init_func_t gpu::Ptx::_cuda_cu_init; -gpu::Ptx::cuda_cu_ctx_create_func_t gpu::Ptx::_cuda_cu_ctx_create; -gpu::Ptx::cuda_cu_ctx_destroy_func_t gpu::Ptx::_cuda_cu_ctx_destroy; -gpu::Ptx::cuda_cu_ctx_synchronize_func_t gpu::Ptx::_cuda_cu_ctx_synchronize; -gpu::Ptx::cuda_cu_ctx_set_current_func_t gpu::Ptx::_cuda_cu_ctx_set_current; -gpu::Ptx::cuda_cu_device_get_count_func_t gpu::Ptx::_cuda_cu_device_get_count; -gpu::Ptx::cuda_cu_device_get_name_func_t gpu::Ptx::_cuda_cu_device_get_name; -gpu::Ptx::cuda_cu_device_get_func_t gpu::Ptx::_cuda_cu_device_get; -gpu::Ptx::cuda_cu_device_compute_capability_func_t gpu::Ptx::_cuda_cu_device_compute_capability; -gpu::Ptx::cuda_cu_device_get_attribute_func_t gpu::Ptx::_cuda_cu_device_get_attribute; -gpu::Ptx::cuda_cu_launch_kernel_func_t gpu::Ptx::_cuda_cu_launch_kernel; -gpu::Ptx::cuda_cu_module_get_function_func_t gpu::Ptx::_cuda_cu_module_get_function; -gpu::Ptx::cuda_cu_module_load_data_ex_func_t gpu::Ptx::_cuda_cu_module_load_data_ex; -gpu::Ptx::cuda_cu_memcpy_dtoh_func_t gpu::Ptx::_cuda_cu_memcpy_dtoh; -gpu::Ptx::cuda_cu_memfree_func_t gpu::Ptx::_cuda_cu_memfree; -gpu::Ptx::cuda_cu_mem_host_register_func_t gpu::Ptx::_cuda_cu_mem_host_register; -gpu::Ptx::cuda_cu_mem_host_get_device_pointer_func_t gpu::Ptx::_cuda_cu_mem_host_get_device_pointer; -gpu::Ptx::cuda_cu_mem_host_unregister_func_t gpu::Ptx::_cuda_cu_mem_host_unregister; +#define STRING "Ljava/lang/String;" + +JNINativeMethod Ptx::PTX_methods[] = { + {CC"initialize", CC"()Z", FN_PTR(Ptx::initialize)}, + {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 = 0; +int Ptx::_cu_device = 0; + +Ptx::cuda_cu_init_func_t Ptx::_cuda_cu_init; +Ptx::cuda_cu_ctx_create_func_t Ptx::_cuda_cu_ctx_create; +Ptx::cuda_cu_ctx_destroy_func_t Ptx::_cuda_cu_ctx_destroy; +Ptx::cuda_cu_ctx_synchronize_func_t Ptx::_cuda_cu_ctx_synchronize; +Ptx::cuda_cu_ctx_get_current_func_t Ptx::_cuda_cu_ctx_get_current; +Ptx::cuda_cu_ctx_set_current_func_t Ptx::_cuda_cu_ctx_set_current; +Ptx::cuda_cu_device_get_count_func_t Ptx::_cuda_cu_device_get_count; +Ptx::cuda_cu_device_get_name_func_t Ptx::_cuda_cu_device_get_name; +Ptx::cuda_cu_device_get_func_t Ptx::_cuda_cu_device_get; +Ptx::cuda_cu_device_compute_capability_func_t Ptx::_cuda_cu_device_compute_capability; +Ptx::cuda_cu_device_get_attribute_func_t Ptx::_cuda_cu_device_get_attribute; +Ptx::cuda_cu_launch_kernel_func_t Ptx::_cuda_cu_launch_kernel; +Ptx::cuda_cu_module_get_function_func_t Ptx::_cuda_cu_module_get_function; +Ptx::cuda_cu_module_load_data_ex_func_t Ptx::_cuda_cu_module_load_data_ex; +Ptx::cuda_cu_memcpy_htod_func_t Ptx::_cuda_cu_memcpy_htod; +Ptx::cuda_cu_memcpy_dtoh_func_t Ptx::_cuda_cu_memcpy_dtoh; +Ptx::cuda_cu_memalloc_func_t Ptx::_cuda_cu_memalloc; +Ptx::cuda_cu_memfree_func_t Ptx::_cuda_cu_memfree; +Ptx::cuda_cu_mem_host_register_func_t Ptx::_cuda_cu_mem_host_register; +Ptx::cuda_cu_mem_host_get_device_pointer_func_t Ptx::_cuda_cu_mem_host_get_device_pointer; +Ptx::cuda_cu_mem_host_unregister_func_t Ptx::_cuda_cu_mem_host_unregister; #define STRINGIFY(x) #x @@ -61,7 +104,7 @@ CAST_TO_FN_PTR(alias##_func_t, os::dll_lookup(handle, STRINGIFY(name))); \ if (_##alias == NULL) { \ tty->print_cr("[CUDA] ***** Error: Failed to lookup %s", STRINGIFY(name)); \ - return 0; \ + return false; \ } \ #define LOOKUP_CUDA_V2_FUNCTION(name, alias) LOOKUP_CUDA_FUNCTION(name##_v2, alias) @@ -69,7 +112,7 @@ /* * see http://en.wikipedia.org/wiki/CUDA#Supported_GPUs */ -int ncores(int major, int minor) { +int Ptx::ncores(int major, int minor) { int device_type = (major << 4) + minor; switch (device_type) { @@ -87,12 +130,36 @@ } } -bool gpu::Ptx::initialize_gpu() { +bool Ptx::register_natives(JNIEnv* env) { + jclass klass = env->FindClass("com/oracle/graal/hotspot/ptx/PTXHotSpotBackend"); + if (klass == NULL) { + if (TraceGPUInteraction) { + tty->print_cr("PTXHotSpotBackend class not found"); + } + return false; + } + jint status = env->RegisterNatives(klass, PTX_methods, sizeof(PTX_methods) / sizeof(JNINativeMethod)); + if (status != JNI_OK) { + if (true || TraceGPUInteraction) { + tty->print_cr("Error registering natives for PTXHotSpotBackend: %d", status); + } + return false; + } + return true; +} + +GPU_ENTRY(jboolean, Ptx::initialize, (JNIEnv *env, jclass)) + + if (!link()) { + return false; + } /* Initialize CUDA driver API */ int status = _cuda_cu_init(0); if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("Failed to initialize CUDA device"); + if (TraceGPUInteraction) { + tty->print_cr("Failed to initialize CUDA device: %d", status); + } return false; } @@ -132,7 +199,34 @@ } /* Get device attributes */ + int minor, major; int unified_addressing; + float version = 0.0; + + /* Get the compute capability of the device found */ + status = _cuda_cu_device_get_attribute(&minor, GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, _cu_device); + if (status != GRAAL_CUDA_SUCCESS) { + tty->print_cr("[CUDA] Failed to get minor attribute of device: %d", _cu_device); + return false; + } + status = _cuda_cu_device_get_attribute(&major, GRAAL_CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, _cu_device); + if (status != GRAAL_CUDA_SUCCESS) { + tty->print_cr("[CUDA] Failed to get major attribute of device: %d", _cu_device); + return false; + } + + /* Check if the device supports atleast GRAAL_SUPPORTED_COMPUTE_CAPABILITY_VERSION */ + version = (float) major + ((float) minor)/10; + + if (version < GRAAL_SUPPORTED_COMPUTE_CAPABILITY_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; + } + + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Device %d supports cuda compute capability %.1f", _cu_device, version); + } status = _cuda_cu_device_get_attribute(&unified_addressing, GRAAL_CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING, _cu_device); @@ -140,12 +234,18 @@ tty->print_cr("[CUDA] Failed to query unified addressing mode of device: %d", _cu_device); return false; } + /* The CUDA driver runtime interaction and generated code as implemented requires + that the device supports Unified Addressing. + */ + if (unified_addressing == 0) { + tty->print_cr("[CUDA] CUDA device %d does NOT have required Unified Addressing support.", _cu_device); + return false; + } if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Unified addressing support on device %d: %d", _cu_device, unified_addressing); + tty->print_cr("[CUDA] Device %d has Unified Addressing support", _cu_device); } - /* Get device name */ char device_name[256]; status = _cuda_cu_device_get_name(device_name, 256, _cu_device); @@ -159,11 +259,24 @@ 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; -} +GPU_END -unsigned int gpu::Ptx::total_cores() { +GPU_ENTRY(jint, Ptx::get_total_cores, (JNIEnv *env, jobject)) int minor, major, nmp; int status = _cuda_cu_device_get_attribute(&minor, @@ -189,7 +302,7 @@ _cu_device); if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] Failed to get numberof MPs on device: %d", _cu_device); + tty->print_cr("[CUDA] Failed to get number of MPs on device: %d", _cu_device); return 0; } @@ -243,22 +356,32 @@ } if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Compatibility version of device %d: %d.%d", _cu_device, major, minor); tty->print_cr("[CUDA] Number of cores: %d async engines: %d can map host mem: %d concurrent kernels: %d", total, async_engines, can_map_host_memory, concurrent_kernels); tty->print_cr("[CUDA] Max threads per block: %d warp size: %d", max_threads_per_block, warp_size); } - return (total); + return total; +GPU_END + +GPU_ENTRY(jlong, Ptx::generate_kernel, (JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle)) + ResourceMark rm; + jsize name_len = env->GetStringLength(name_handle); + jsize code_len = env->GetArrayLength(code_handle); -} + char* name = NEW_RESOURCE_ARRAY(char, name_len + 1); + unsigned char *code = NEW_RESOURCE_ARRAY(unsigned char, code_len + 1); -void *gpu::Ptx::generate_kernel(unsigned char *code, int code_len, const char *name) { + code[code_len] = 0; + name[name_len] = 0; + + env->GetByteArrayRegion(code_handle, 0, code_len, (jbyte*) code); + env->GetStringUTFRegion(name_handle, 0, name_len, name); struct CUmod_st * cu_module; // Use three JIT compiler options const unsigned int jit_num_options = 3; - int *jit_options = NEW_C_HEAP_ARRAY(int, jit_num_options, mtCompiler); - void **jit_option_values = NEW_C_HEAP_ARRAY(void *, jit_num_options, mtCompiler); + int *jit_options = NEW_RESOURCE_ARRAY(int, jit_num_options); + void **jit_option_values = NEW_RESOURCE_ARRAY(void *, jit_num_options); // Set up PTX JIT compiler options // 1. set size of compilation log buffer @@ -267,400 +390,419 @@ jit_option_values[0] = (void *)(size_t)jit_log_buffer_size; // 2. set pointer to compilation log buffer - char *jit_log_buffer = NEW_C_HEAP_ARRAY(char, jit_log_buffer_size, mtCompiler); + char *jit_log_buffer = NEW_RESOURCE_ARRAY(char, jit_log_buffer_size); jit_options[1] = GRAAL_CU_JIT_INFO_LOG_BUFFER; jit_option_values[1] = jit_log_buffer; - // 3. set pointer to set the Maximum # of registers (32) for the kernel + // 3. set pointer to set the maximum number of registers (32) for the kernel int jit_register_count = 32; 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 NULL; + if (_device_context == NULL) { + tty->print_cr("[CUDA] Encountered uninitialized CUDA context for device(%d)", _cu_device); + return 0L; } - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Created context for device: %d", _cu_device); - } - - 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 NULL; + return 0L; } if (TraceGPUInteraction) { tty->print_cr("[CUDA] Success: Set current context for device: %d", _cu_device); - } - - if (TraceGPUInteraction) { tty->print_cr("[CUDA] PTX Kernel\n%s", code); tty->print_cr("[CUDA] Function name : %s", name); - } /* Load module's data with compiler options */ status = _cuda_cu_module_load_data_ex(&cu_module, (void*) code, jit_num_options, - jit_options, (void **)jit_option_values); + jit_options, (void **)jit_option_values); if (status != GRAAL_CUDA_SUCCESS) { if (status == GRAAL_CUDA_ERROR_NO_BINARY_FOR_GPU) { tty->print_cr("[CUDA] Check for malformed PTX kernel or incorrect PTX compilation options"); } tty->print_cr("[CUDA] *** Error (%d) Failed to load module data with online compiler options for method %s", status, name); - return NULL; + return 0L; } if (TraceGPUInteraction) { tty->print_cr("[CUDA] Loaded data for PTX Kernel"); } - struct CUfunc_st * cu_function; - + struct CUfunc_st* cu_function; status = _cuda_cu_module_get_function(&cu_function, cu_module, name); if (status != GRAAL_CUDA_SUCCESS) { tty->print_cr("[CUDA] *** Error: Failed to get function %s", name); - return NULL; + return 0L; } if (TraceGPUInteraction) { tty->print_cr("[CUDA] Got function handle for %s kernel address %p", name, cu_function); } + return (jlong) cu_function; +GPU_END - return cu_function; +// A PtxCall is used to manage executing a GPU kernel. In addition to launching +// the kernel, this class releases resources allocated for the execution. +class PtxCall: StackObj { + private: + JavaThread* _thread; // the thread on which this call is made + address _buffer; // buffer containing parameters and _return_value + int _buffer_size; // size (in bytes) of _buffer + oop* _pinned; // objects that have been pinned with cuMemHostRegister + int _pinned_length; // length of _pinned + Ptx::CUdeviceptr _ret_value; // pointer to slot in GPU memory holding the return value + int _ret_type_size; // size of the return type value + bool _ret_is_object; // specifies if the return type is Object + bool _gc_locked; // denotes when execution has locked GC + + bool check(int status, const char *action) { + if (status != GRAAL_CUDA_SUCCESS) { + Thread* THREAD = _thread; + ResourceMark rm(THREAD); + char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, O_BUFLEN + 1); + jio_snprintf(message, O_BUFLEN, "[CUDA] *** Error (status=%d): %s", status, action); + if (TraceGPUInteraction) { + tty->print_cr(message); + } + if (!HAS_PENDING_EXCEPTION) { + SharedRuntime::throw_and_post_jvmti_exception(_thread, vmSymbols::java_lang_RuntimeException(), message); + } + return false; + } + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Success: %s", action); + } + return true; + } + + public: + PtxCall(JavaThread* thread, address buffer, int buffer_size, oop* pinned, int encodedReturnTypeSize) : _thread(thread), _gc_locked(false), + _buffer(buffer), _buffer_size(buffer_size), _pinned(pinned), _pinned_length(0), _ret_value(0), _ret_is_object(encodedReturnTypeSize < 0) { + _ret_type_size = _ret_is_object ? -encodedReturnTypeSize : encodedReturnTypeSize; + } + + bool is_object_return() { return _ret_is_object; } + + void alloc_return_value() { + if (_ret_type_size != 0) { + if (check(Ptx::_cuda_cu_memalloc(&_ret_value, _ret_type_size), "Allocate device memory for return value")) { + Ptx::CUdeviceptr* retValuePtr = (Ptx::CUdeviceptr*) ((_buffer + _buffer_size) - sizeof(_ret_value)); + *retValuePtr = _ret_value; + } + } + } + + void pin_objects(int count, int* objectOffsets) { + if (count == 0) { + return; + } + // Once we start pinning objects, no GC must occur + // until the kernel has completed. This is a big + // hammer for ensuring we can safely pass objects + // to the GPU. + GC_locker::lock_critical(_thread); + _gc_locked = true; + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Locked GC"); + } + + for (int i = 0; i < count; i++) { + int offset = objectOffsets[i]; + oop* argPtr = (oop*) (_buffer + offset); + oop obj = *argPtr; + if (obj != NULL) { + // Size (in bytes) of object + int objSize = obj->size() * HeapWordSize; + //tty->print_cr("Pinning object %d at offset %d: %p", i, offset, obj); + if (!check(Ptx::_cuda_cu_mem_host_register(obj, objSize, GRAAL_CU_MEMHOSTREGISTER_DEVICEMAP), "Pin object")) { + return; + } + + // Record original oop so that its memory can be unpinned + _pinned[_pinned_length++] = obj; + + // Replace host pointer to object with device pointer + // to object in kernel parameters buffer + if (!check(Ptx::_cuda_cu_mem_host_get_device_pointer((Ptx::CUdeviceptr*) argPtr, obj, 0), "Get device pointer for pinned object")) { + return; + } + } + } + } + + void launch(address kernel, jint dimX, jint dimY, jint dimZ) { + // grid dimensionality + unsigned int gridX = 1; + unsigned int gridY = 1; + unsigned int gridZ = 1; + void * config[] = { + GRAAL_CU_LAUNCH_PARAM_BUFFER_POINTER, (char*) (address) _buffer, + GRAAL_CU_LAUNCH_PARAM_BUFFER_SIZE, &_buffer_size, + GRAAL_CU_LAUNCH_PARAM_END + }; + if (check(Ptx::_cuda_cu_launch_kernel((struct CUfunc_st*) (address) kernel, + gridX, gridY, gridZ, + dimX, dimY, dimZ, + 0, NULL, NULL, (void**) &config), "Launch kernel")) { + } + } + + void synchronize() { + check(Ptx::_cuda_cu_ctx_synchronize(), "Synchronize kernel"); + } + + void unpin_objects() { + while (_pinned_length > 0) { + oop obj = _pinned[--_pinned_length]; + assert(obj != NULL, "npe"); + //tty->print_cr("Unpinning object %d: %p", _pinned_length, obj); + if (!check(Ptx::_cuda_cu_mem_host_unregister(obj), "Unpin object")) { + return; + } + } + } + + oop get_object_return_value() { + oop return_val; + check(Ptx::_cuda_cu_memcpy_dtoh(&return_val, _ret_value, T_OBJECT_BYTE_SIZE), "Copy return value from device"); + return return_val; + } + + jlong get_primitive_return_value() { + jlong return_val; + check(Ptx::_cuda_cu_memcpy_dtoh(&return_val, _ret_value, _ret_type_size), "Copy return value from device"); + return return_val; + } + + void free_return_value() { + if (_ret_value != 0) { + check(Ptx::_cuda_cu_memfree(_ret_value), "Free device memory"); + _ret_value = 0; + } + } + + ~PtxCall() { + unpin_objects(); + free_return_value(); + if (_gc_locked) { + GC_locker::unlock_critical(_thread); + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Unlocked GC"); + } + _gc_locked = false; + } + } +}; + +// Prints values in the kernel arguments buffer +class KernelArgumentsPrinter: public SignatureIterator { + Method* _method; + address _buffer; + size_t _bufferOffset; + outputStream* _st; + +private: + + // Get next java argument + oop next_arg(BasicType expectedType); + + public: + KernelArgumentsPrinter(Method* method, address buffer, outputStream* st) : SignatureIterator(method->signature()), + _method(method), _buffer(buffer), _bufferOffset(0), _st(st) { + if (!method->is_static()) { + print_oop(); + } + iterate(); + } + + address next(size_t dataSz) { + if (is_return_type()) { + return _buffer; + } + if (_bufferOffset != 0) { + _st->print(", "); + } + _bufferOffset = align_size_up_(_bufferOffset, dataSz); + address result = _buffer + _bufferOffset; + _bufferOffset += dataSz; + return result; + } + + void print_oop() { + oop obj = *((oop*) next(sizeof(oop))); + if (obj != NULL) { + char type[256]; + obj->klass()->name()->as_C_string(type, 256); + _st->print("oop "PTR_FORMAT" (%s)", (address) obj, type); + } else { + _st->print("oop null"); + } + } + + bool skip() { + return is_return_type(); + } + + void do_bool () { if (!skip()) _st->print("bool %d", *((jboolean*) next(sizeof(jboolean)))); } + void do_char () { if (!skip()) _st->print("char %c", *((jchar*) next(sizeof(jchar)))); } + void do_float () { if (!skip()) _st->print("float %g", *((jfloat*) next(sizeof(jfloat)))); } + void do_double() { if (!skip()) _st->print("double %g", *((jdouble*) next(sizeof(jdouble)))); } + void do_byte () { if (!skip()) _st->print("byte %d", *((jbyte*) next(sizeof(jbyte)))); } + void do_short () { if (!skip()) _st->print("short %d", *((jshort*) next(sizeof(jshort)))); } + void do_int () { if (!skip()) _st->print("int %d", *((jint*) next(sizeof(jint)))); } + void do_long () { if (!skip()) _st->print("long "JLONG_FORMAT, *((jlong*) next(sizeof(jlong)))); } + void do_void () { } + void do_object(int begin, int end) { if (!skip()) print_oop(); } + void do_array (int begin, int end) { if (!skip()) print_oop(); } +}; + +static void printKernelArguments(JavaThread* thread, address buffer) { + for (vframeStream vfst(thread); !vfst.at_end(); vfst.next()) { + Method* m = vfst.method(); + if (m != NULL) { + ResourceMark rm; + stringStream st(O_BUFLEN); + st.print("[CUDA] Call: %s.%s(", m->method_holder()->name()->as_C_string(), m->name()->as_C_string()); + KernelArgumentsPrinter kap(m, buffer, &st); + tty->print_cr("%s)", st.as_string()); + return; + } + } } -JRT_ENTRY(jlong, gpu::Ptx::execute_kernel_from_vm(JavaThread* thread, jlong kernel, jint dimX, jint dimY, jint dimZ, - jlong parametersAndReturnValueBuffer, - jint parametersAndReturnValueBufferSize, +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 + +JRT_ENTRY(jlong, Ptx::execute_kernel_from_vm(JavaThread* thread, jlong kernel, jint dimX, jint dimY, jint dimZ, + jlong buffer, + jint bufferSize, + jint objectParametersCount, + jlong objectParametersOffsets, + jlong pinnedObjects, int encodedReturnTypeSize)) if (kernel == 0L) { SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_NullPointerException(), NULL); return 0L; } - // grid dimensionality - unsigned int gridX = 1; - unsigned int gridY = 1; - unsigned int gridZ = 1; - - struct CUfunc_st* cu_function = (struct CUfunc_st*) (address) kernel; - - void * config[5] = { - GRAAL_CU_LAUNCH_PARAM_BUFFER_POINTER, (char*) (address) parametersAndReturnValueBuffer, - GRAAL_CU_LAUNCH_PARAM_BUFFER_SIZE, ¶metersAndReturnValueBufferSize, - GRAAL_CU_LAUNCH_PARAM_END - }; - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] launching kernel"); - } - - bool isObjectReturn = encodedReturnTypeSize < 0; - int returnTypeSize = encodedReturnTypeSize < 0 ? -encodedReturnTypeSize : encodedReturnTypeSize; - gpu::Ptx::CUdeviceptr device_return_value; - int status; - if (returnTypeSize != 0) { - status = _cuda_cu_memalloc(&device_return_value, returnTypeSize); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status); - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_RuntimeException(), "[CUDA] Failed to allocate memory for return value pointer on device"); - return 0L; - } - // Push device_return_value to kernelParams - gpu::Ptx::CUdeviceptr* returnValuePtr = (gpu::Ptx::CUdeviceptr*) - ((address) parametersAndReturnValueBuffer + - parametersAndReturnValueBufferSize - sizeof(device_return_value)); - *returnValuePtr = device_return_value; - } - - status = _cuda_cu_launch_kernel(cu_function, - gridX, gridY, gridZ, - dimX, dimY, dimZ, - 0, NULL, NULL, (void **) &config); - - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] Failed to launch kernel"); - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_RuntimeException(), "[CUDA] Failed to launch kernel"); - return 0L; - } - - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Kernel Launch: X: %d Y: %d Z: %d", dimX, dimY, dimZ); + printKernelArguments(thread, (address) buffer); } - status = _cuda_cu_ctx_synchronize(); + PtxCall call(thread, (address) buffer, bufferSize, (oop*) (address) pinnedObjects, encodedReturnTypeSize); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] Failed to synchronize launched kernel (%d)", status); - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_RuntimeException(), "[CUDA] Failed to synchronize launched kernel"); - return 0L; - } +#define TRY(action) do { \ + action; \ + if (HAS_PENDING_EXCEPTION) return 0L; \ +} while (0) + + TRY(call.alloc_return_value()); - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Synchronized launch kernel"); - } + TRY(call.pin_objects(objectParametersCount, (int*) (address) objectParametersOffsets)); + + TRY(call.launch((address) kernel, dimX, dimY, dimZ)); - jlong primitiveReturnValue = 0L; - if (isObjectReturn) { + TRY(call.synchronize()); + + if (call.is_object_return()) { oop return_val; - status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, device_return_value, T_OBJECT_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to copy value from device argument", status); - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_Exception(), "[CUDA] Failed to copy value from device argument"); - return 0L; - } + TRY(return_val = call.get_object_return_value()); thread->set_vm_result(return_val); - } else if (returnTypeSize > 0) { - status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&primitiveReturnValue, device_return_value, returnTypeSize); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to copy value from device argument", status); - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_Exception(), "[CUDA] Failed to copy value from device argument"); - return 0L; - } - } - - // Free device memory allocated for result - if (returnTypeSize != 0) { - status = gpu::Ptx::_cuda_cu_memfree(device_return_value); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to free device memory of return value", status); - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_Exception(), "[CUDA] Failed to free device memory of return value"); - return 0L; - } - } - - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Freed device memory of return value"); - } - - // Destroy context - status = gpu::Ptx::_cuda_cu_ctx_destroy(_device_context); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to destroy context", status); - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_Exception(), "[CUDA] Failed to destroy context"); return 0L; } - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Destroy context"); - } + jlong return_val; + TRY(return_val = call.get_primitive_return_value()); + return return_val; - return primitiveReturnValue; +#undef TRY + JRT_END -bool gpu::Ptx::execute_kernel(address kernel, PTXKernelArguments &ptxka, JavaValue &ret) { - return gpu::Ptx::execute_warp(1, 1, 1, kernel, ptxka, ret); -} - -bool gpu::Ptx::execute_warp(int dimX, int dimY, int dimZ, - address kernel, PTXKernelArguments &ptxka, JavaValue &ret) { - // grid dimensionality - unsigned int gridX = 1; - unsigned int gridY = 1; - unsigned int gridZ = 1; - - // thread dimensionality - unsigned int blockX = dimX; - unsigned int blockY = dimY; - unsigned int blockZ = dimZ; - - struct CUfunc_st* cu_function = (struct CUfunc_st*) kernel; - - void * config[5] = { - GRAAL_CU_LAUNCH_PARAM_BUFFER_POINTER, ptxka._kernelArgBuffer, - GRAAL_CU_LAUNCH_PARAM_BUFFER_SIZE, &(ptxka._bufferOffset), - GRAAL_CU_LAUNCH_PARAM_END - }; - - if (kernel == NULL) { - return false; - } - - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] launching kernel"); - } - - int status = _cuda_cu_launch_kernel(cu_function, - gridX, gridY, gridZ, - blockX, blockY, blockZ, - 0, NULL, NULL, (void **) &config); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] Failed to launch kernel"); - return false; - } - - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Kernel Launch: X: %d Y: %d Z: %d", blockX, blockY, blockZ); - } - - status = _cuda_cu_ctx_synchronize(); - - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] Failed to synchronize launched kernel (%d)", status); - return false; - } - - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Synchronized launch kernel"); - } - - - // Get the result. TODO: Move this code to get_return_oop() - BasicType return_type = ptxka.get_ret_type(); - switch (return_type) { - case T_INT: - { - int return_val; - status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._dev_return_value, T_INT_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to copy value to device argument", status); - return false; - } - ret.set_jint(return_val); - } - break; - case T_BOOLEAN: - { - int return_val; - status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._dev_return_value, T_INT_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to copy value to device argument", status); - return false; - } - ret.set_jint(return_val); - } - break; - case T_FLOAT: - { - float return_val; - status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._dev_return_value, T_FLOAT_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to copy value to device argument", status); - return false; - } - ret.set_jfloat(return_val); - } - break; - case T_DOUBLE: - { - double return_val; - status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._dev_return_value, T_DOUBLE_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to copy value to device argument", status); - return false; - } - ret.set_jdouble(return_val); - } - break; - case T_LONG: - { - long return_val; - status = gpu::Ptx::_cuda_cu_memcpy_dtoh(&return_val, ptxka._dev_return_value, T_LONG_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to copy value to device argument", status); - return false; - } - ret.set_jlong(return_val); - } - break; - case T_VOID: - break; - default: - tty->print_cr("[CUDA] TODO *** Unhandled return type: %d", return_type); - } - - // Free device memory allocated for result - status = gpu::Ptx::_cuda_cu_memfree(ptxka._dev_return_value); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to free device memory of return value", status); - return false; - } - - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Freed device memory of return value"); - } - - // Destroy context - status = gpu::Ptx::_cuda_cu_ctx_destroy(_device_context); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to destroy context", status); - return false; - } - - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: Destroy context"); - } - - return (status == GRAAL_CUDA_SUCCESS); -} - #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 static char const cuda_library_name[] = ""; #endif -#define STD_BUFFER_SIZE 1024 +bool Ptx::link() { + if (cuda_library_name == NULL) { + if (TraceGPUInteraction) { + tty->print_cr("Failed to find CUDA linkage"); + } + return false; + } + char ebuf[O_BUFLEN]; + void *handle = os::dll_load(cuda_library_name, ebuf, O_BUFLEN); + if (handle == NULL) { + if (TraceGPUInteraction) { + tty->print_cr("Unsupported CUDA platform: %s", ebuf); + } + return false; + } -bool gpu::Ptx::probe_linkage() { - if (cuda_library_name != NULL) { - char *buffer = (char*)malloc(STD_BUFFER_SIZE); - void *handle = os::dll_load(cuda_library_name, buffer, STD_BUFFER_SIZE); - free(buffer); - if (handle != NULL) { - LOOKUP_CUDA_FUNCTION(cuInit, cuda_cu_init); - LOOKUP_CUDA_FUNCTION(cuCtxSynchronize, cuda_cu_ctx_synchronize); - LOOKUP_CUDA_FUNCTION(cuCtxSetCurrent, cuda_cu_ctx_set_current); - LOOKUP_CUDA_FUNCTION(cuDeviceGetCount, cuda_cu_device_get_count); - LOOKUP_CUDA_FUNCTION(cuDeviceGetName, cuda_cu_device_get_name); - LOOKUP_CUDA_FUNCTION(cuDeviceGet, cuda_cu_device_get); - LOOKUP_CUDA_FUNCTION(cuDeviceComputeCapability, cuda_cu_device_compute_capability); - LOOKUP_CUDA_FUNCTION(cuDeviceGetAttribute, cuda_cu_device_get_attribute); - LOOKUP_CUDA_FUNCTION(cuModuleGetFunction, cuda_cu_module_get_function); - LOOKUP_CUDA_FUNCTION(cuModuleLoadDataEx, cuda_cu_module_load_data_ex); - LOOKUP_CUDA_FUNCTION(cuLaunchKernel, cuda_cu_launch_kernel); - LOOKUP_CUDA_FUNCTION(cuMemHostRegister, cuda_cu_mem_host_register); - LOOKUP_CUDA_FUNCTION(cuMemHostUnregister, cuda_cu_mem_host_unregister); + LOOKUP_CUDA_FUNCTION(cuInit, cuda_cu_init); + LOOKUP_CUDA_FUNCTION(cuCtxSynchronize, cuda_cu_ctx_synchronize); + LOOKUP_CUDA_FUNCTION(cuCtxGetCurrent, cuda_cu_ctx_get_current); + LOOKUP_CUDA_FUNCTION(cuCtxSetCurrent, cuda_cu_ctx_set_current); + LOOKUP_CUDA_FUNCTION(cuDeviceGetCount, cuda_cu_device_get_count); + LOOKUP_CUDA_FUNCTION(cuDeviceGetName, cuda_cu_device_get_name); + LOOKUP_CUDA_FUNCTION(cuDeviceGet, cuda_cu_device_get); + LOOKUP_CUDA_FUNCTION(cuDeviceComputeCapability, cuda_cu_device_compute_capability); + LOOKUP_CUDA_FUNCTION(cuDeviceGetAttribute, cuda_cu_device_get_attribute); + LOOKUP_CUDA_FUNCTION(cuModuleGetFunction, cuda_cu_module_get_function); + LOOKUP_CUDA_FUNCTION(cuModuleLoadDataEx, cuda_cu_module_load_data_ex); + LOOKUP_CUDA_FUNCTION(cuLaunchKernel, cuda_cu_launch_kernel); + LOOKUP_CUDA_FUNCTION(cuMemHostRegister, cuda_cu_mem_host_register); + LOOKUP_CUDA_FUNCTION(cuMemHostUnregister, cuda_cu_mem_host_unregister); #if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) - LOOKUP_CUDA_V2_FUNCTION(cuCtxCreate, cuda_cu_ctx_create); - LOOKUP_CUDA_V2_FUNCTION(cuCtxDestroy, cuda_cu_ctx_destroy); - LOOKUP_CUDA_V2_FUNCTION(cuMemAlloc, cuda_cu_memalloc); - LOOKUP_CUDA_V2_FUNCTION(cuMemFree, cuda_cu_memfree); - LOOKUP_CUDA_V2_FUNCTION(cuMemcpyHtoD, cuda_cu_memcpy_htod); - LOOKUP_CUDA_V2_FUNCTION(cuMemcpyDtoH, cuda_cu_memcpy_dtoh); - LOOKUP_CUDA_V2_FUNCTION(cuMemHostGetDevicePointer, cuda_cu_mem_host_get_device_pointer); + LOOKUP_CUDA_V2_FUNCTION(cuCtxCreate, cuda_cu_ctx_create); + LOOKUP_CUDA_V2_FUNCTION(cuCtxDestroy, cuda_cu_ctx_destroy); + LOOKUP_CUDA_V2_FUNCTION(cuMemAlloc, cuda_cu_memalloc); + LOOKUP_CUDA_V2_FUNCTION(cuMemFree, cuda_cu_memfree); + LOOKUP_CUDA_V2_FUNCTION(cuMemcpyHtoD, cuda_cu_memcpy_htod); + LOOKUP_CUDA_V2_FUNCTION(cuMemcpyDtoH, cuda_cu_memcpy_dtoh); + LOOKUP_CUDA_V2_FUNCTION(cuMemHostGetDevicePointer, cuda_cu_mem_host_get_device_pointer); #else - LOOKUP_CUDA_FUNCTION(cuCtxCreate, cuda_cu_ctx_create); - LOOKUP_CUDA_FUNCTION(cuCtxDestroy, cuda_cu_ctx_destroy); - LOOKUP_CUDA_FUNCTION(cuMemAlloc, cuda_cu_memalloc); - LOOKUP_CUDA_FUNCTION(cuMemFree, cuda_cu_memfree); - LOOKUP_CUDA_FUNCTION(cuMemcpyHtoD, cuda_cu_memcpy_htod); - LOOKUP_CUDA_FUNCTION(cuMemcpyDtoH, cuda_cu_memcpy_dtoh); - LOOKUP_CUDA_FUNCTION(cuMemHostGetDevicePointer, cuda_cu_mem_host_get_device_pointer); + LOOKUP_CUDA_FUNCTION(cuCtxCreate, cuda_cu_ctx_create); + LOOKUP_CUDA_FUNCTION(cuCtxDestroy, cuda_cu_ctx_destroy); + LOOKUP_CUDA_FUNCTION(cuMemAlloc, cuda_cu_memalloc); + LOOKUP_CUDA_FUNCTION(cuMemFree, cuda_cu_memfree); + LOOKUP_CUDA_FUNCTION(cuMemcpyHtoD, cuda_cu_memcpy_htod); + LOOKUP_CUDA_FUNCTION(cuMemcpyDtoH, cuda_cu_memcpy_dtoh); + LOOKUP_CUDA_FUNCTION(cuMemHostGetDevicePointer, cuda_cu_mem_host_get_device_pointer); #endif - if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Success: library linkage"); - } - return true; - } else { - // Unable to dlopen libcuda - return false; - } - } else { - tty->print_cr("Unsupported CUDA platform"); - return false; + if (TraceGPUInteraction) { + tty->print_cr("[CUDA] Success: library linkage"); } - tty->print_cr("Failed to find CUDA linkage"); - return false; + return true; } diff -r d0e82d536325 -r a124cc76cde9 src/gpu/ptx/vm/gpu_ptx.hpp --- a/src/gpu/ptx/vm/gpu_ptx.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/gpu/ptx/vm/gpu_ptx.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -84,19 +84,45 @@ * Context creation flags */ -#define GRAAL_CU_CTX_MAP_HOST 0x08 +#define GRAAL_CU_CTX_MAP_HOST 0x08 +#define GRAAL_CU_CTX_SCHED_BLOCKING_SYNC 0x04 + +/** + * Support compute capability 3.0 and later + */ + +#define GRAAL_SUPPORTED_COMPUTE_CAPABILITY_VERSION 3.0 class Ptx { - friend class gpu; + friend class PtxCall; + +private: + + static JNINativeMethod PTX_methods[]; + + // static native boolean initialize(); + JNIEXPORT static jboolean initialize(JNIEnv* env, jclass); + + // static native long generateKernel(byte[] targetCode, String name); + JNIEXPORT static jlong generate_kernel(JNIEnv *env, jclass, jbyteArray code_handle, jstring name_handle); + + // static native long getLaunchKernelAddress(); + JNIEXPORT static jlong get_execute_kernel_from_vm_address(JNIEnv *env, jclass); - protected: - static bool probe_linkage(); - static bool initialize_gpu(); - static unsigned int total_cores(); - static void * generate_kernel(unsigned char *code, int code_len, const char *name); - static bool execute_warp(int dimX, int dimY, int dimZ, address kernel, PTXKernelArguments & ka, JavaValue &ret); - static bool execute_kernel(address kernel, PTXKernelArguments & ka, JavaValue &ret); + // 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(); + + static int ncores(int major, int minor); + public: + // Registers the implementations for the native methods in PTXHotSpotBackend + static bool register_natives(JNIEnv* env); + #if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) typedef unsigned long long CUdeviceptr; #else @@ -106,8 +132,11 @@ typedef int CUdevice; /* CUDA device */ static jlong execute_kernel_from_vm(JavaThread* thread, jlong kernel, jint dimX, jint dimY, jint dimZ, - jlong parametersAndReturnValueBuffer, - jint parametersAndReturnValueBufferSize, + jlong buffer, + jint bufferSize, + jint objectParametersCount, + jlong objectParametersOffsets, + jlong pinnedObjects, int encodedReturnTypeSize); private: @@ -115,6 +144,7 @@ typedef int (*cuda_cu_ctx_create_func_t)(void*, unsigned int, CUdevice); typedef int (*cuda_cu_ctx_destroy_func_t)(void*); typedef int (*cuda_cu_ctx_synchronize_func_t)(void); + typedef int (*cuda_cu_ctx_get_current_func_t)(void*); typedef int (*cuda_cu_ctx_set_current_func_t)(void*); typedef int (*cuda_cu_device_get_count_func_t)(int*); typedef int (*cuda_cu_device_get_name_func_t)(char*, int, int); @@ -127,12 +157,12 @@ unsigned int, void*, void**, void**); typedef int (*cuda_cu_module_get_function_func_t)(void*, void*, const char*); typedef int (*cuda_cu_module_load_data_ex_func_t)(void*, void*, unsigned int, void*, void**); - typedef int (*cuda_cu_memalloc_func_t)(gpu::Ptx::CUdeviceptr*, size_t); - typedef int (*cuda_cu_memfree_func_t)(gpu::Ptx::CUdeviceptr); - typedef int (*cuda_cu_memcpy_htod_func_t)(gpu::Ptx::CUdeviceptr, const void*, unsigned int); - typedef int (*cuda_cu_memcpy_dtoh_func_t)(const void*, gpu::Ptx::CUdeviceptr, unsigned int); + typedef int (*cuda_cu_memalloc_func_t)(Ptx::CUdeviceptr*, size_t); + typedef int (*cuda_cu_memfree_func_t)(Ptx::CUdeviceptr); + typedef int (*cuda_cu_memcpy_htod_func_t)(Ptx::CUdeviceptr, const void*, unsigned int); + typedef int (*cuda_cu_memcpy_dtoh_func_t)(const void*, Ptx::CUdeviceptr, unsigned int); typedef int (*cuda_cu_mem_host_register_func_t)(void*, size_t, unsigned int); - typedef int (*cuda_cu_mem_host_get_device_pointer_func_t)(gpu::Ptx::CUdeviceptr*, void*, unsigned int); + typedef int (*cuda_cu_mem_host_get_device_pointer_func_t)(Ptx::CUdeviceptr*, void*, unsigned int); typedef int (*cuda_cu_mem_host_unregister_func_t)(void*); public: @@ -152,6 +182,7 @@ static cuda_cu_memfree_func_t _cuda_cu_memfree; static cuda_cu_memcpy_htod_func_t _cuda_cu_memcpy_htod; static cuda_cu_memcpy_dtoh_func_t _cuda_cu_memcpy_dtoh; + static cuda_cu_ctx_get_current_func_t _cuda_cu_ctx_get_current; static cuda_cu_ctx_set_current_func_t _cuda_cu_ctx_set_current; static cuda_cu_mem_host_register_func_t _cuda_cu_mem_host_register; static cuda_cu_mem_host_get_device_pointer_func_t _cuda_cu_mem_host_get_device_pointer; diff -r d0e82d536325 -r a124cc76cde9 src/gpu/ptx/vm/ptxKernelArguments.cpp --- a/src/gpu/ptx/vm/ptxKernelArguments.cpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,332 +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. - * - */ - -#include "precompiled.hpp" -#include "ptxKernelArguments.hpp" -#include "runtime/javaCalls.hpp" - -gpu::Ptx::cuda_cu_memalloc_func_t gpu::Ptx::_cuda_cu_memalloc; -gpu::Ptx::cuda_cu_memcpy_htod_func_t gpu::Ptx::_cuda_cu_memcpy_htod; - -// Get next java argument -oop PTXKernelArguments::next_arg(BasicType expectedType) { - assert(_index < _args->length(), "out of bounds"); - oop arg = ((objArrayOop) (_args))->obj_at(_index++); - assert(expectedType == T_OBJECT || - java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); - return arg; -} - -/* - * Pad kernel argument buffer to naturally align for given size. - */ -void PTXKernelArguments::pad_kernel_argument_buffer(size_t dataSz) { - while ((_bufferOffset % dataSz) != 0) { - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = (char) 0; - _bufferOffset += sizeof(char); - } - return; -} -void PTXKernelArguments::do_int() { - // If the parameter is a return value, - if (is_return_type()) { - // Allocate device memory for T_INT return value pointer on device. Size in bytes - int status = gpu::Ptx::_cuda_cu_memalloc(&_dev_return_value, T_INT_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status); - _success = false; - return; - } - - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(_dev_return_value)); - // Push _dev_return_value to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _dev_return_value; - _bufferOffset += sizeof(_dev_return_value); - } else { - // Get the next java argument and its value which should be a T_INT - oop arg = next_arg(T_INT); - // Copy the java argument value to kernelArgBuffer - jvalue intval; - if (java_lang_boxing_object::get_value(arg, &intval) != T_INT) { - tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_INT"); - _success = false; - return; - } - - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(intval.i)); - // Push _dev_return_value to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = intval.i; - - // Advance _bufferOffset - _bufferOffset += sizeof(intval.i); - } - return; -} - -void PTXKernelArguments::do_float() { - // If the parameter is a return value, - if (is_return_type()) { - // Allocate device memory for T_FLOAT return value pointer on device. Size in bytes - int status = gpu::Ptx::_cuda_cu_memalloc(&_dev_return_value, T_FLOAT_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(_dev_return_value)); - // Push _dev_return_value to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _dev_return_value; - // Advance _bufferOffset - _bufferOffset += sizeof(_dev_return_value); - } else { - // Get the next java argument and its value which should be a T_FLOAT - oop arg = next_arg(T_FLOAT); - // Copy the java argument value to kernelArgBuffer - jvalue floatval; - if (java_lang_boxing_object::get_value(arg, &floatval) != T_FLOAT) { - tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_FLOAT"); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(floatval.f)); - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = (gpu::Ptx::CUdeviceptr) floatval.f; - - // Advance _bufferOffset - _bufferOffset += sizeof(floatval.f); - } - return; -} - -void PTXKernelArguments::do_double() { - // If the parameter is a return value, - jvalue doubleval; - if (is_return_type()) { - // Allocate device memory for T_DOUBLE return value pointer on device. Size in bytes - int status = gpu::Ptx::_cuda_cu_memalloc(&_dev_return_value, T_DOUBLE_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(_dev_return_value)); - // Push _dev_return_value to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _dev_return_value; - // Advance _bufferOffset. - _bufferOffset += sizeof(doubleval.d); - } else { - // Get the next java argument and its value which should be a T_INT - oop arg = next_arg(T_FLOAT); - // Copy the java argument value to kernelArgBuffer - if (java_lang_boxing_object::get_value(arg, &doubleval) != T_DOUBLE) { - tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_INT"); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(doubleval.d)); - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = (gpu::Ptx::CUdeviceptr) doubleval.d; - - // Advance _bufferOffset - _bufferOffset += sizeof(doubleval.d); - // For a 64-bit host, since size of double is 8, there is no need - // to pad the kernel argument buffer to ensure 8-byte alignment of - // the next potential argument to be pushed. - } - return; -} - -void PTXKernelArguments::do_long() { - // If the parameter is a return value, - if (is_return_type()) { - // Allocate device memory for T_LONG return value pointer on device. Size in bytes - int status = gpu::Ptx::_cuda_cu_memalloc(&_dev_return_value, T_LONG_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(_dev_return_value)); - // Push _dev_return_value to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _dev_return_value; - // Advance _bufferOffset - _bufferOffset += sizeof(_dev_return_value); - } else { - // Get the next java argument and its value which should be a T_LONG - oop arg = next_arg(T_LONG); - // Copy the java argument value to kernelArgBuffer - jvalue val; - if (java_lang_boxing_object::get_value(arg, &val) != T_LONG) { - tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_LONG"); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(val.j)); - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.j; - - // Advance _bufferOffset - _bufferOffset += sizeof(val.j); - // For a 64-bit host, since size of long is 8, there is no need - // to pad the kernel argument buffer to ensure 8-byte alignment of - // the next potential argument to be pushed. - } - return; -} - -void PTXKernelArguments::do_byte() { - // If the parameter is a return value, - if (is_return_type()) { - // Allocate device memory for T_BYTE return value pointer on device. Size in bytes - int status = gpu::Ptx::_cuda_cu_memalloc(&_dev_return_value, T_BYTE_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(_dev_return_value)); - // Push _dev_return_value to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _dev_return_value; - - // Advance _bufferOffset - _bufferOffset += sizeof(_dev_return_value); - } else { - // Get the next java argument and its value which should be a T_BYTE - oop arg = next_arg(T_BYTE); - // Copy the java argument value to kernelArgBuffer - jvalue val; - if (java_lang_boxing_object::get_value(arg, &val) != T_BYTE) { - tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_BYTE"); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(val.b)); - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.b; - - // Advance _bufferOffset - _bufferOffset += sizeof(val.b); - // For a 64-bit host, since size of T_BYTE is 8, there is no need - // to pad the kernel argument buffer to ensure 8-byte alignment of - // the next potential argument to be pushed. - } - return; -} - -void PTXKernelArguments::do_bool() { - // If the parameter is a return value, - if (is_return_type()) { - // Allocate device memory for T_BYTE return value pointer on device. Size in bytes - int status = gpu::Ptx::_cuda_cu_memalloc(&_dev_return_value, T_BOOLEAN_SIZE); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to allocate memory for return value pointer on device", status); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(_dev_return_value)); - // Push _dev_return_value to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = _dev_return_value; - _bufferOffset += sizeof(_dev_return_value); - } else { - // Get the next java argument and its value which should be a T_BOOLEAN - oop arg = next_arg(T_BOOLEAN); - // Copy the java argument value to kernelArgBuffer - jvalue val; - if (java_lang_boxing_object::get_value(arg, &val) != T_BOOLEAN) { - tty->print_cr("[CUDA] *** Error: Unexpected argument type; expecting T_BOOLEAN"); - _success = false; - return; - } - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(val.z)); - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = val.z; - - // Advance _bufferOffset - _bufferOffset += sizeof(val.z); - } - return; -} - -void PTXKernelArguments::do_array(int begin, int end) { - // Get the next java argument and its value which should be a T_ARRAY - oop arg = next_arg(T_OBJECT); - assert(arg->is_array(), "argument value not an array"); - // Size of array argument - int argSize = arg->size() * HeapWordSize; - // Device pointer to array argument. - gpu::Ptx::CUdeviceptr arrayArgOnDev; - int status; - - // Register host memory for use by the device. Size in bytes - status = gpu::Ptx::_cuda_cu_mem_host_register(arg, argSize, GRAAL_CU_MEMHOSTREGISTER_DEVICEMAP); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to register host memory for array argument on device", - status); - _success = false; - return; - } - // Get device pointer - status = gpu::Ptx::_cuda_cu_mem_host_get_device_pointer(&arrayArgOnDev, arg, 0); - if (status != GRAAL_CUDA_SUCCESS) { - tty->print_cr("[CUDA] *** Error (%d) Failed to get device pointer of mapped pinned memory of array argument.", - status); - _success = false; - return; - } - - // Kernel arguments are expected to be naturally aligned. - // Insert padding into kernel argument buffer, if needed. - pad_kernel_argument_buffer(sizeof(arrayArgOnDev)); - // Push device array argument to _kernelBuffer - *((gpu::Ptx::CUdeviceptr*) &_kernelArgBuffer[_bufferOffset]) = arrayArgOnDev; - - // Advance _bufferOffset - _bufferOffset += sizeof(arrayArgOnDev); - return; -} - -void PTXKernelArguments::do_void() { - return; -} - -// TODO implement other do_* diff -r d0e82d536325 -r a124cc76cde9 src/gpu/ptx/vm/ptxKernelArguments.hpp --- a/src/gpu/ptx/vm/ptxKernelArguments.hpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +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. - * - */ - -#ifndef KERNEL_ARGUMENTS_PTX_HPP -#define KERNEL_ARGUMENTS_PTX_HPP - -#include "runtime/gpu.hpp" -#include "runtime/signature.hpp" - -#define T_BYTE_SIZE 1 -#define T_BOOLEAN_SIZE 4 -#define T_INT_BYTE_SIZE 4 -#define T_FLOAT_BYTE_SIZE 4 -#define T_DOUBLE_BYTE_SIZE 8 -#define T_LONG_BYTE_SIZE 8 -#define T_OBJECT_BYTE_SIZE 8 -#define T_ARRAY_BYTE_SIZE 8 - -class PTXKernelArguments : public SignatureIterator { -public: - // Buffer holding CUdeviceptr values that represent the kernel arguments - char _kernelArgBuffer[1024]; - // Current offset into _kernelArgBuffer - size_t _bufferOffset; - // Device pointer holding return value - gpu::Ptx::CUdeviceptr _dev_return_value; - -private: - // Array of java argument oops - arrayOop _args; - // Current index into _args - int _index; - // Flag to indicate successful creation of kernel argument buffer - bool _success; - - // Get next java argument - oop next_arg(BasicType expectedType); - - public: - PTXKernelArguments(Symbol* signature, arrayOop args, bool is_static) : SignatureIterator(signature) { - this->_return_type = T_ILLEGAL; - _index = 0; - _args = args; - _success = true; - _bufferOffset = 0; - _dev_return_value = 0; - if (!is_static) { - // TODO : Create a device argument for receiver object and add it to _kernelBuffer - tty->print_cr("{CUDA] ****** TODO: Support for execution of non-static java methods not implemented yet."); - } - // Iterate over the entire signature - iterate(); - assert((_success && (_index == args->length())), "arg count mismatch with signature"); - } - - inline char* device_argument_buffer() { - return _kernelArgBuffer; - } - - inline size_t device_argument_buffer_size() { - return _bufferOffset; - } - - // Get the return oop value - oop get_return_oop(); - - // get device return value ptr - gpu::Ptx::CUdeviceptr get_dev_return_value() { - return _dev_return_value; - } - - /* - * Pad kernel argument buffer to naturally align for given size. - */ - void pad_kernel_argument_buffer(size_t); - - void do_byte(); - void do_bool(); - void do_int(); - void do_float(); - void do_double(); - void do_long(); - void do_array(int begin, int end); - void do_void(); - - inline void do_char() { - /* TODO : To be implemented */ - guarantee(false, "do_char:NYI"); - } - inline void do_short() { - /* TODO : To be implemented */ - guarantee(false, "do_short:NYI"); - } - inline void do_object() { - /* TODO : To be implemented */ - guarantee(false, "do_object:NYI"); - } - - inline void do_object(int begin, int end) { - /* TODO : To be implemented */ - guarantee(false, "do_object(II):NYI"); - } - -}; - -#endif // KERNEL_ARGUMENTS_HPP diff -r d0e82d536325 -r a124cc76cde9 src/os/bsd/vm/gpu_bsd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/bsd/vm/gpu_bsd.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,49 @@ +/* + * 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. + * + */ + +#include "runtime/gpu.hpp" +#include "ptx/vm/gpu_ptx.hpp" +#include "hsail/vm/gpu_hsail.hpp" +#include "utilities/ostream.hpp" + +jobject gpu::probe_gpus(JNIEnv* env) { +#ifdef __APPLE__ + /* + * Let the CUDA driver initialization be the gate to GPU for now, pending + * a better detection solution for NVIDA PTX and AMD HSAIL. + */ + if (Ptx::register_natives(env)) { + if (TraceGPUInteraction) { + tty->print_cr("Assuming NVidia/PTX support (APPLE)"); + } + return env->NewStringUTF("PTX"); + } +#else + if (TraceGPUInteraction) { + tty->print_cr("Assuming no GPU (not APPLE)"); + } +#endif + return env->NewStringUTF(""); +} + diff -r d0e82d536325 -r a124cc76cde9 src/os/linux/vm/gpu_linux.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/linux/vm/gpu_linux.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,95 @@ +/* + * 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. + * + */ + +#include "runtime/gpu.hpp" +#include "ptx/vm/gpu_ptx.hpp" +#include "hsail/vm/gpu_hsail.hpp" +#include "utilities/ostream.hpp" + +/* + * Probe for CUDA device on PCI bus using /proc/bus/pci/devices. Do + * not rely on CUDA tool kit being installed. We will check if CUDA + * library is installed later. + */ + +static unsigned int nvidia_vendor_id = 0x10de; +static unsigned int amd_vendor_id = 0x1002; + +#define PCI_DRIVER_NAME_START_POS 255 + +jobject gpu::probe_gpus(JNIEnv* env) { + bool hsail = false; + bool ptx = false; + + if (Hsail::register_natives(env)) { + hsail = true; + } + + /* + * Open /proc/bus/pci/devices to look for the first GPU device. For + * now, we will just find the first GPU device. Will need to revisit + * this to support execution on multiple GPU devices, if they exist. + */ + FILE *pci_devices = fopen("/proc/bus/pci/devices", "r"); + char contents[4096]; + unsigned int bus_num_devfn_ign; + unsigned int vendor; + unsigned int device; + const char *driver_name_string = "nvidia"; + const int driver_name_string_len = strlen(driver_name_string); + + if (pci_devices == NULL) { + tty->print_cr("*** Failed to open /proc/bus/pci/devices"); + return NULL; + } + + while (fgets(contents, sizeof(contents)-1, pci_devices)) { + sscanf(contents, "%04x%04x%04x", &bus_num_devfn_ign, &vendor, &device); + if (vendor == nvidia_vendor_id) { + /* Check if this device is registered to be using nvidia driver */ + if (strncmp(&contents[PCI_DRIVER_NAME_START_POS], + driver_name_string, driver_name_string_len) == 0) { + if (TraceGPUInteraction) { + tty->print_cr("Found supported nVidia device [vendor=0x%04x, device=0x%04x]", vendor, device); + } + if (!ptx && Ptx::register_natives(env)) { + ptx = true; + } + } + } + } + + // Close file pointer. + fclose(pci_devices); + + const char* gpus = ""; + if (ptx && hsail) { + gpus = "PTX,HSAIL"; + } else if (ptx) { + gpus = "PTX"; + } else if (hsail) { + gpus = "HSAIL"; + } + return env->NewStringUTF(gpus); +} diff -r d0e82d536325 -r a124cc76cde9 src/os/windows/vm/gpu_windows.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/windows/vm/gpu_windows.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,36 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/gpu.hpp" +#include "hsail/vm/gpu_hsail.hpp" +#include "utilities/ostream.hpp" + +jobject gpu::probe_gpus(JNIEnv* env) { + // TODO: add detection of PTX/NVidia + if (Hsail::register_natives(env)) { + return env->NewStringUTF("HSAIL"); + } + return env->NewStringUTF(""); +} diff -r d0e82d536325 -r a124cc76cde9 src/os_gpu/bsd_ptx/vm/gpu_bsd.cpp --- a/src/os_gpu/bsd_ptx/vm/gpu_bsd.cpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +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. - * - */ - -#include "runtime/gpu.hpp" -#include "utilities/ostream.hpp" - - -void gpu::probe_gpu() { -#ifdef __APPLE__ - /* - * Let the CUDA driver initialization be the gate to GPU for now, pending - * a better detection solution for NVIDA PTX and AMD HSAIL. - */ - set_available(true); - set_target_il_type(gpu::PTX); - if (TraceGPUInteraction) { - tty->print_cr("gpu_bsd::probe_gpu(APPLE): %d", gpu::is_available()); - } -#else - if (TraceGPUInteraction) { - tty->print_cr("gpu_bsd::probe_gpu(not APPLE)"); - } - set_available(false); -#endif -} - diff -r d0e82d536325 -r a124cc76cde9 src/os_gpu/bsd_ptx/vm/gpu_bsd.hpp --- a/src/os_gpu/bsd_ptx/vm/gpu_bsd.hpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +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. - * - */ - -#ifndef OS_BSD_VM_GPU_BSD_HPP -#define OS_BSD_VM_GPU_BSD_HPP - - -class Bsd { - friend class gpu; - - protected: - static bool probe_gpu(); -#ifdef __APPLE__ - static bool probe_gpu_apple(); -#endif -}; - -#endif // OS_BSD_VM_GPU_BSD_HPP diff -r d0e82d536325 -r a124cc76cde9 src/os_gpu/linux_ptx/vm/gpu_linux.cpp --- a/src/os_gpu/linux_ptx/vm/gpu_linux.cpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +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. - * - */ - -#include "runtime/gpu.hpp" -#include "utilities/ostream.hpp" - -void gpu::probe_gpu() { - set_available(gpu::Linux::probe_gpu()); - if (TraceGPUInteraction) { - tty->print_cr("gpu_linux::probe_gpu(): %d", gpu::is_available()); - } -} - -/* - * Probe for CUDA device on PCI bus using /proc/bus/pci/devices. Do - * not rely on CUDA tool kit being installed. We will check if CUDA - * library is installed later. - */ - -static unsigned int nvidia_vendor_id = 0x10de; -static unsigned int amd_vendor_id = 0x1002; - -bool gpu::Linux::probe_gpu() { - - /* - * The simulator only depends on shared libraries. - * That linkage is checked in a later step. - */ - if (UseHSAILSimulator) { - set_target_il_type(gpu::HSAIL); - if (TraceGPUInteraction) { - tty->print_cr("Setup HSAIL Simulator"); - } - return true; - } - - /* - * Open /proc/bus/pci/devices to look for the first GPU device. For - * now, we will just find the first GPU device. Will need to revisit - * this to support execution on multiple GPU devices, if they exist. - */ - FILE *pci_devices = fopen("/proc/bus/pci/devices", "r"); - char contents[4096]; - unsigned int bus_num_devfn_ign; - unsigned int vendor; - unsigned int device; - bool gpu_device_exists = false; - if (pci_devices == NULL) { - tty->print_cr("*** Failed to open /proc/bus/pci/devices"); - return gpu_device_exists; - } - - while (fgets(contents, sizeof(contents)-1, pci_devices)) { - sscanf(contents, "%04x%04x%04x", &bus_num_devfn_ign, &vendor, &device); - /* Break after finding the first GPU device. */ - if (vendor == nvidia_vendor_id) { - gpu_device_exists = true; - set_target_il_type(gpu::PTX); - if (TraceGPUInteraction) { - tty->print_cr("Found supported nVidia GPU device vendor : 0x%04x device 0x%04x", vendor, device); - } - break; - /* - * Remove AMD detection until we decide how to detect real HSA hardware. - * In the current form this check does not work correctly on AMD CPU system with - * Nvidia GPU. - * - * } else if (vendor == amd_vendor_id) { - * gpu_device_exists = true; - * set_target_il_type(gpu::HSAIL); - * if (TraceGPUInteraction) { - * tty->print_cr("Found supported AMD GPU device vendor : 0x%04x device 0x%04x", vendor, device); - * } - * break; - */ - } - } - - // Close file pointer. - fclose(pci_devices); - - return gpu_device_exists; -} diff -r d0e82d536325 -r a124cc76cde9 src/os_gpu/linux_ptx/vm/gpu_linux.hpp --- a/src/os_gpu/linux_ptx/vm/gpu_linux.hpp Sun Feb 23 17:00:35 2014 -0800 +++ /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. - * - */ - -#ifndef OS_BSD_VM_GPU_LINUX_HPP -#define OS_BSD_VM_GPU_LINUX_HPP - - -class Linux { - friend class gpu; - - protected: - static bool probe_gpu(); -}; - -#endif // OS_BSD_VM_GPU_LINUX_HPP diff -r d0e82d536325 -r a124cc76cde9 src/os_gpu/windows_hsail/vm/gpu_windows.cpp --- a/src/os_gpu/windows_hsail/vm/gpu_windows.cpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +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. - * - */ - -#include "precompiled.hpp" -#include "runtime/gpu.hpp" -#include "utilities/ostream.hpp" - -void gpu::probe_gpu() { - set_available(gpu::Windows::probe_gpu()); - if (TraceGPUInteraction) { - tty->print_cr("probe_gpu(): %d", gpu::is_available()); - } -} - -bool gpu::Windows::probe_gpu() { - - /* - * We will check the HSA environment in the libraries, - * so nothing to do here. - * The HSA library linkage is checked in a later step. - */ - bool gpu_device_exists = true; - set_target_il_type(gpu::HSAIL); - - return gpu_device_exists; -} diff -r d0e82d536325 -r a124cc76cde9 src/os_gpu/windows_hsail/vm/gpu_windows.hpp --- a/src/os_gpu/windows_hsail/vm/gpu_windows.hpp Sun Feb 23 17:00:35 2014 -0800 +++ /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. - * - */ - -#ifndef OS_WINDOWS_VM_GPU_WINDOWS_HPP -#define OS_WINDOWS_VM_GPU_WINDOWS_HPP - - -class Windows { - friend class gpu; - - protected: - static bool probe_gpu(); -}; - -#endif // OS_WINDOWS_VM_GPU_WINDOWS_HPP diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java Wed Mar 05 19:40:15 2014 -0800 @@ -24,6 +24,8 @@ package com.sun.hotspot.igv.data; import java.util.Comparator; +import java.util.WeakHashMap; +import java.lang.ref.WeakReference; /** * @@ -32,7 +34,7 @@ public class InputEdge { public enum State { - + IMMUTABLE, SAME, NEW, DELETED @@ -61,12 +63,12 @@ } }; - private char toIndex; - private char fromIndex; - private int from; - private int to; + private final char toIndex; + private final char fromIndex; + private final int from; + private final int to; + private final String label; private State state; - private String label; public InputEdge(char toIndex, int from, int to) { this((char) 0, toIndex, from, to, null); @@ -85,11 +87,38 @@ this.label = label; } + static WeakHashMap> immutableCache = new WeakHashMap<>(); + + public static synchronized InputEdge createImmutable(char fromIndex, char toIndex, int from, int to, String label) { + InputEdge edge = new InputEdge(fromIndex, toIndex, from, to, label, State.IMMUTABLE); + WeakReference result = immutableCache.get(edge); + if (result != null) { + InputEdge edge2 = result.get(); + if (edge2 != null) { + return edge2; + } + } + immutableCache.put(edge, new WeakReference<>(edge)); + return edge; + } + + public InputEdge(char fromIndex, char toIndex, int from, int to, String label, State state) { + this.toIndex = toIndex; + this.fromIndex = fromIndex; + this.from = from; + this.to = to; + this.state = state; + this.label = label; + } + public State getState() { return state; } public void setState(State x) { + if (state == State.IMMUTABLE) { + throw new InternalError("Can't change immutable instances"); + } this.state = x; } @@ -123,7 +152,12 @@ return false; } InputEdge conn2 = (InputEdge) o; - return conn2.fromIndex == fromIndex && conn2.toIndex == toIndex && conn2.from == from && conn2.to == to; + boolean result = conn2.fromIndex == fromIndex && conn2.toIndex == toIndex && conn2.from == from && conn2.to == to; + if (result && (state == State.IMMUTABLE || conn2.state == State.IMMUTABLE)) { + // Immutable instances must be exactly the same + return conn2.label == label && conn2.state == state; + } + return result; } @Override diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Wed Mar 05 19:40:15 2014 -0800 @@ -32,19 +32,19 @@ public class InputGraph extends Properties.Entity implements FolderElement { private Map nodes; - private Set edges; + private List edges; private Folder parent; private Group parentGroup; private Map blocks; - private Set blockEdges; + private List blockEdges; private Map nodeToBlock; public InputGraph(String name) { setName(name); nodes = new LinkedHashMap<>(); - edges = new LinkedHashSet<>(); + edges = new ArrayList<>(); blocks = new LinkedHashMap<>(); - blockEdges = new LinkedHashSet<>(); + blockEdges = new ArrayList<>(); nodeToBlock = new LinkedHashMap<>(); } @@ -234,7 +234,7 @@ } public Collection getEdges() { - return Collections.unmodifiableSet(edges); + return Collections.unmodifiableList(edges); } public void removeEdge(InputEdge c) { @@ -283,7 +283,7 @@ } public Collection getBlockEdges() { - return Collections.unmodifiableSet(blockEdges); + return Collections.unmodifiableList(blockEdges); } @Override diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Wed Mar 05 19:40:15 2014 -0800 @@ -320,6 +320,9 @@ } public void setProperty(String name, String value) { + setPropertyInternal(name.intern(), value != null ? value.intern() : null); + } + private void setPropertyInternal(String name, String value) { for (int i = 0; i < map.length; i += 2) { if (map[i] != null && map[i].equals(name)) { @@ -353,7 +356,8 @@ public void add(Properties properties) { for (Property p : properties) { - setProperty(p.getName(), p.getValue()); + // Already interned + setPropertyInternal(p.getName(), p.getValue()); } } diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Wed Mar 05 19:40:15 2014 -0800 @@ -35,6 +35,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.SwingUtilities; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; public class BinaryParser implements GraphParser { private static final int BEGIN_GROUP = 0x00; @@ -72,7 +74,10 @@ private final ReadableByteChannel channel; private final GraphDocument rootDocument; private final Deque folderStack; + private final Deque hashStack; private final ParseMonitor monitor; + + private MessageDigest digest; private enum Length { S, @@ -259,7 +264,12 @@ this.channel = channel; this.rootDocument = rootDocument; folderStack = new LinkedList<>(); + hashStack = new LinkedList<>(); this.monitor = monitor; + try { + this.digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + } } private void fill() throws IOException { @@ -274,6 +284,11 @@ while (buffer.remaining() < i) { fill(); } + buffer.mark(); + byte[] result = new byte[i]; + buffer.get(result); + digest.update(result); + buffer.reset(); } private int readByte() throws IOException { @@ -312,7 +327,7 @@ char[] chars = new char[len]; buffer.asCharBuffer().get(chars); buffer.position(buffer.position() + len * 2); - return new String(chars); + return new String(chars).intern(); } private byte[] readBytes() throws IOException { @@ -340,7 +355,7 @@ } } sb.append(']'); - return sb.toString(); + return sb.toString().intern(); } private String readDoublesToString() throws IOException { @@ -357,7 +372,7 @@ } } sb.append(']'); - return sb.toString(); + return sb.toString().intern(); } private String readPoolObjectsToString() throws IOException { @@ -373,7 +388,7 @@ } } sb.append(']'); - return sb.toString(); + return sb.toString().intern(); } private T readPoolObject(Class klass) throws IOException { @@ -536,7 +551,7 @@ throw new IOException("Unknown type"); } case PROPERTY_SUBGRAPH: - InputGraph graph = parseGraph(null); + InputGraph graph = parseGraph(""); new Group(null).addElement(graph); return graph; default: @@ -547,6 +562,7 @@ @Override public GraphDocument parse() throws IOException { folderStack.push(rootDocument); + hashStack.push(null); if (monitor != null) { monitor.setState("Starting parsing"); } @@ -589,6 +605,7 @@ }); } folderStack.push(group); + hashStack.push(null); if (callback != null && parent instanceof GraphDocument) { callback.started(group); } @@ -599,6 +616,7 @@ throw new IOException("Unbalanced groups"); } folderStack.pop(); + hashStack.pop(); break; } default: @@ -629,7 +647,17 @@ monitor.updateProgress(); } String title = readPoolObject(String.class); - return parseGraph(title); + digest.reset(); + InputGraph graph = parseGraph(title); + byte[] d = digest.digest(); + byte[] hash = hashStack.peek(); + if (hash != null && Arrays.equals(hash, d)) { + graph.getProperties().setProperty("_isDuplicate", "true"); + } else { + hashStack.pop(); + hashStack.push(d); + } + return graph; } private InputGraph parseGraph(String title) throws IOException { @@ -752,7 +780,7 @@ for (Edge e : edges) { char fromIndex = e.input ? 1 : e.num; char toIndex = e.input ? e.num : 0; - graph.addEdge(new InputEdge(fromIndex, toIndex, e.from, e.to, e.label)); + graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label)); } } @@ -809,7 +837,7 @@ m.appendReplacement(sb, result); } m.appendTail(sb); - return sb.toString(); + return sb.toString().intern(); } private static class Edge { @@ -824,7 +852,7 @@ public Edge(int from, int to, char num, String label, boolean input) { this.from = from; this.to = to; - this.label = label; + this.label = label != null ? label.intern() : label; this.num = num; this.input = input; } diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Wed Mar 05 19:40:15 2014 -0800 @@ -43,6 +43,7 @@ // Warning: Update setData method if fields are added private Group group; + private ArrayList graphs; private Set hiddenNodes; private Set onScreenNodes; private Set selectedNodes; @@ -56,6 +57,7 @@ private ChangedEvent hiddenNodesChangedEvent; private ChangedEvent viewPropertiesChangedEvent; private boolean showNodeHull; + private boolean hideDuplicates; private ChangedListener filterChainChangedListener = new ChangedListener() { @Override @@ -83,6 +85,10 @@ boolean groupChanged = (group == newModel.group); this.group = newModel.group; + if (groupChanged) { + filterGraphs(); + } + diagramChanged |= (filterChain != newModel.filterChain); this.filterChain = newModel.filterChain; diagramChanged |= (sequenceFilterChain != newModel.sequenceFilterChain); @@ -122,11 +128,33 @@ viewPropertiesChangedEvent.fire(); } + public boolean getHideDuplicates() { + return hideDuplicates; + } + + public void setHideDuplicates(boolean b) { + System.err.println("setHideDuplicates: " + b); + hideDuplicates = b; + InputGraph currentGraph = getFirstGraph(); + if (hideDuplicates) { + // Back up to the unhidden equivalent graph + int index = graphs.indexOf(currentGraph); + while (graphs.get(index).getProperties().get("_isDuplicate") != null) { + index--; + } + currentGraph = graphs.get(index); + } + filterGraphs(); + selectGraph(currentGraph); + viewPropertiesChangedEvent.fire(); + } + public DiagramViewModel(Group g, FilterChain filterChain, FilterChain sequenceFilterChain) { - super(calculateStringList(g)); + super(Arrays.asList("default")); this.showNodeHull = true; this.group = g; + filterGraphs(); assert filterChain != null; this.filterChain = filterChain; assert sequenceFilterChain != null; @@ -165,7 +193,7 @@ @Override public void changed(Group source) { assert source == group; - setPositions(calculateStringList(source)); + filterGraphs(); setSelectedNodes(selectedNodes); } }; @@ -211,7 +239,7 @@ } InputNode last = null; int index = 0; - for (InputGraph g : group.getGraphs()) { + for (InputGraph g : graphs) { Color curColor = colors.get(index); InputNode cur = g.getNode(id); if (cur != null) { @@ -316,16 +344,24 @@ diagramChanged(); } - private static List calculateStringList(Group g) { - List result = new ArrayList<>(); - for (InputGraph graph : g.getGraphs()) { - result.add(graph.getName()); + /* + * Select the set of graphs to be presented. + */ + private void filterGraphs() { + ArrayList result = new ArrayList<>(); + List positions = new ArrayList<>(); + for (InputGraph graph : group.getGraphs()) { + String duplicate = graph.getProperties().get("_isDuplicate"); + if (duplicate == null || !hideDuplicates) { + result.add(graph); + positions.add(graph.getName()); + } } - return result; + this.graphs = result; + setPositions(positions); } public InputGraph getFirstGraph() { - List graphs = group.getGraphs(); if (getFirstPosition() < graphs.size()) { return graphs.get(getFirstPosition()); } @@ -333,7 +369,6 @@ } public InputGraph getSecondGraph() { - List graphs = group.getGraphs(); if (getSecondPosition() < graphs.size()) { return graphs.get(getSecondPosition()); } @@ -341,7 +376,12 @@ } public void selectGraph(InputGraph g) { - int index = group.getGraphs().indexOf(g); + int index = graphs.indexOf(g); + if (index == -1 && hideDuplicates) { + // A graph was selected that's currently hidden, so unhide and select it. + setHideDuplicates(false); + index = graphs.indexOf(g); + } assert index != -1; setPositions(index, index); } diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java Wed Mar 05 19:40:15 2014 -0800 @@ -78,6 +78,7 @@ private InstanceContent content; private InstanceContent graphContent; private OverviewAction overviewAction; + private HideDuplicatesAction hideDuplicatesAction; private PredSuccAction predSuccAction; private SelectionModeAction selectionModeAction; private PanModeAction panModeAction; @@ -87,6 +88,7 @@ private CardLayout cardLayout; private RangeSlider rangeSlider; private JToggleButton overviewButton; + private JToggleButton hideDuplicatesButton; private static final String PREFERRED_ID = "EditorTopComponent"; private static final String SATELLITE_STRING = "satellite"; private static final String SCENE_STRING = "scene"; @@ -207,6 +209,14 @@ rangeSliderModel.getDiagramChangedEvent().addListener(diagramChangedListener); rangeSliderModel.selectGraph(diagram.getGraph()); + rangeSliderModel.getViewPropertiesChangedEvent().addListener(new ChangedListener() { + @Override + public void changed(DiagramViewModel source) { + hideDuplicatesButton.setSelected(getModel().getHideDuplicates()); + hideDuplicatesAction.setState(getModel().getHideDuplicates()); + } + }); + toolBar.add(NextDiagramAction.get(NextDiagramAction.class)); toolBar.add(PrevDiagramAction.get(PrevDiagramAction.class)); @@ -230,6 +240,12 @@ toolBar.add(button); predSuccAction.addPropertyChangeListener(this); + hideDuplicatesAction = new HideDuplicatesAction(); + hideDuplicatesButton = new JToggleButton(hideDuplicatesAction); + hideDuplicatesButton.setSelected(false); + toolBar.add(hideDuplicatesButton); + hideDuplicatesAction.addPropertyChangeListener(this); + toolBar.addSeparator(); toolBar.add(UndoAction.get(UndoAction.class)); toolBar.add(RedoAction.get(RedoAction.class)); @@ -477,6 +493,9 @@ } else { showScene(); } + } else if (evt.getSource() == this.hideDuplicatesAction) { + boolean b = (Boolean) hideDuplicatesAction.getValue(HideDuplicatesAction.STATE); + this.getModel().setHideDuplicates(b); } else if (evt.getSource() == this.selectionModeAction || evt.getSource() == this.panModeAction) { if (panModeAction.isSelected()) { scene.setInteractionMode(DiagramViewer.InteractionMode.PANNING); diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/HideDuplicatesAction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/HideDuplicatesAction.java Wed Mar 05 19:40:15 2014 -0800 @@ -0,0 +1,60 @@ +/* + * 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.sun.hotspot.igv.view.actions; + +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ImageIcon; +import org.openide.util.ImageUtilities; + +/** + * + * @author Tom Rodriguez + */ +public class HideDuplicatesAction extends AbstractAction { + + private boolean state; + public static final String STATE = "state"; + + public HideDuplicatesAction() { + putValue(AbstractAction.SMALL_ICON, new ImageIcon(ImageUtilities.loadImage(iconResource()))); + putValue(Action.SHORT_DESCRIPTION, "Hide graphs which are the same as the previous graph"); + setState(false); + } + + @Override + public void actionPerformed(ActionEvent ev) { + setState(!state); + } + + public void setState(boolean b) { + this.putValue(STATE, b); + this.state = b; + } + + protected String iconResource() { + return "com/sun/hotspot/igv/view/images/hideDuplicates.png"; + } +} diff -r d0e82d536325 -r a124cc76cde9 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/images/hideDuplicates.png Binary file src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/images/hideDuplicates.png has changed diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/classfile/systemDictionary.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -197,8 +197,6 @@ do_klass(HotSpotInstalledCode_klass, com_oracle_graal_hotspot_meta_HotSpotInstalledCode, Opt) \ do_klass(HotSpotNmethod_klass, com_oracle_graal_hotspot_meta_HotSpotNmethod, Opt) \ do_klass(HotSpotJavaType_klass, com_oracle_graal_hotspot_meta_HotSpotJavaType, Opt) \ - do_klass(HotSpotMethodData_klass, com_oracle_graal_hotspot_meta_HotSpotMethodData, Opt) \ - do_klass(HotSpotResolvedJavaField_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedJavaField, Opt) \ do_klass(HotSpotResolvedJavaMethod_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, Opt) \ do_klass(HotSpotResolvedObjectType_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, Opt) \ do_klass(HotSpotMonitorValue_klass, com_oracle_graal_hotspot_meta_HotSpotMonitorValue, Opt) \ diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -308,8 +308,6 @@ template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode, "com/oracle/graal/hotspot/meta/HotSpotInstalledCode") \ template(com_oracle_graal_hotspot_meta_HotSpotNmethod, "com/oracle/graal/hotspot/meta/HotSpotNmethod") \ template(com_oracle_graal_hotspot_meta_HotSpotJavaType, "com/oracle/graal/hotspot/meta/HotSpotJavaType") \ - template(com_oracle_graal_hotspot_meta_HotSpotMethodData, "com/oracle/graal/hotspot/meta/HotSpotMethodData") \ - template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaField, "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField") \ template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod") \ template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType") \ template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue, "com/oracle/graal/hotspot/meta/HotSpotMonitorValue") \ @@ -361,20 +359,6 @@ template(setOption_name, "setOption") \ template(setOption_signature, "(Ljava/lang/String;)Z") \ template(finalizeOptions_name, "finalizeOptions") \ - template(createUnresolvedJavaMethod_name, "createUnresolvedJavaMethod") \ - template(createUnresolvedJavaMethod_signature, "(Ljava/lang/String;Ljava/lang/String;Lcom/oracle/graal/api/meta/JavaType;)Lcom/oracle/graal/api/meta/JavaMethod;") \ - template(createSignature_name, "createSignature") \ - template(createSignature_signature, "(Ljava/lang/String;)Lcom/oracle/graal/api/meta/Signature;") \ - template(createJavaField_name, "createJavaField") \ - template(createJavaField_signature, "(Lcom/oracle/graal/api/meta/JavaType;Ljava/lang/String;Lcom/oracle/graal/api/meta/JavaType;IIZ)Lcom/oracle/graal/api/meta/JavaField;") \ - template(createResolvedJavaMethod_name, "createResolvedJavaMethod") \ - template(createResolvedJavaMethod_signature, "(Lcom/oracle/graal/api/meta/JavaType;J)Lcom/oracle/graal/api/meta/ResolvedJavaMethod;") \ - template(createUnresolvedJavaType_name, "createUnresolvedJavaType") \ - template(createUnresolvedJavaType_signature, "(Ljava/lang/String;)Lcom/oracle/graal/api/meta/JavaType;") \ - template(createResolvedJavaType_name, "createResolvedJavaType") \ - template(createResolvedJavaType_signature, "(Ljava/lang/Class;)Lcom/oracle/graal/api/meta/ResolvedJavaType;") \ - template(createPrimitiveJavaType_name, "createPrimitiveJavaType") \ - template(createPrimitiveJavaType_signature, "(I)Lcom/oracle/graal/api/meta/JavaType;") \ template(getVMToCompiler_name, "getVMToCompiler") \ template(getVMToCompiler_signature, "()Lcom/oracle/graal/hotspot/bridge/VMToCompiler;") \ template(runtime_name, "runtime") \ diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/compiler/compileBroker.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -1472,6 +1472,16 @@ // ------------------------------------------------------------------ +// CompileBroker::assign_compile_id_unlocked +// +// Public wrapper for assign_compile_id that acquires the needed locks +uint CompileBroker::assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci) { + MutexLocker locker(MethodCompileQueue_lock, thread); + return assign_compile_id(method, osr_bci); +} + + +// ------------------------------------------------------------------ // CompileBroker::is_compile_blocking // // Should the current thread be blocked until this compilation request diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/compiler/compileBroker.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -321,6 +321,7 @@ static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level); static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level); + static uint assign_compile_id (methodHandle method, int osr_bci); static bool is_compile_blocking (methodHandle method, int osr_bci); static void preload_classes (methodHandle method, TRAPS); @@ -385,7 +386,8 @@ int hot_count, const char* comment, Thread* thread); - static uint assign_compile_id (methodHandle method, int osr_bci); + // Acquire any needed locks and assign a compile id + static uint assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci); static void compiler_thread_loop(); static uint get_compilation_id() { return _compilation_id; } diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/gc_implementation/g1/vmStructs_g1.hpp --- a/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -68,6 +68,7 @@ \ declare_type(G1CollectedHeap, SharedHeap) \ \ + declare_type(G1OffsetTableContigSpace, ContiguousSpace) \ declare_type(HeapRegion, ContiguousSpace) \ declare_toplevel_type(HeapRegionSeq) \ declare_toplevel_type(HeapRegionSetBase) \ diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -22,6 +22,7 @@ */ #include "precompiled.hpp" +#include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" #include "runtime/javaCalls.hpp" #include "graal/graalEnv.hpp" @@ -419,6 +420,10 @@ methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code)); jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code); jint id = HotSpotCompiledNmethod::id(compiled_code); + if (id == -1) { + // Make sure a valid compile_id is associated with every compile + id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci); + } result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, id, false, leaf_graph_ids, installed_code, speculation_log); cb = nm; @@ -803,7 +808,6 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) { oop id_obj = CompilationResult_Mark::id(site); - arrayOop references = (arrayOop) CompilationResult_Mark::references(site); if (id_obj != NULL) { assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalCompiler.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -28,7 +28,6 @@ #include "graal/graalJavaAccess.hpp" #include "graal/graalVMToCompiler.hpp" #include "graal/graalCompilerToVM.hpp" -#include "graal/graalCompilerToGPU.hpp" #include "graal/graalEnv.hpp" #include "graal/graalRuntime.hpp" #include "runtime/arguments.hpp" @@ -72,13 +71,6 @@ } env->RegisterNatives(klass, CompilerToVM_methods, CompilerToVM_methods_count()); - klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToGPUImpl"); - if (klass == NULL) { - tty->print_cr("graal CompilerToGPUImpl class not found"); - vm_abort(false); - } - env->RegisterNatives(klass, CompilerToGPU_methods, CompilerToGPU_methods_count()); - ResourceMark rm; HandleMark hm; { @@ -219,30 +211,21 @@ TRACE_graal_1("GraalCompiler::print_timers"); } -Handle GraalCompiler::get_JavaTypeFromSignature(Symbol* signature, KlassHandle loading_klass, TRAPS) { +KlassHandle GraalCompiler::get_KlassFromSignature(Symbol* signature, KlassHandle loading_klass) { BasicType field_type = FieldType::basic_type(signature); - // If the field is a pointer type, get the klass of the - // field. + // If the field is a pointer type, get the klass of the field. if (field_type == T_OBJECT || field_type == T_ARRAY) { - KlassHandle klass = GraalEnv::get_klass_by_name(loading_klass, signature, false); - if (klass.is_null()) { - Handle signature_string = java_lang_String::create_from_symbol(signature, CHECK_NH); - return VMToCompiler::createUnresolvedJavaType(signature_string, CHECK_NH); - } else { - return VMToCompiler::createResolvedJavaType(klass->java_mirror(), CHECK_NH); - } - } else { - return VMToCompiler::createPrimitiveJavaType(field_type, CHECK_NH); + return GraalEnv::get_klass_by_name(loading_klass, signature, false); } + return NULL; } -Handle GraalCompiler::get_JavaType(constantPoolHandle cp, int index, KlassHandle loading_klass, TRAPS) { +KlassHandle GraalCompiler::get_Klass(constantPoolHandle cp, int index, KlassHandle loading_klass, Symbol*& klass_name) { bool is_accessible = false; KlassHandle klass = GraalEnv::get_klass_by_index(cp, index, is_accessible, loading_klass); - oop catch_class = NULL; if (klass.is_null()) { - Symbol* klass_name = NULL; + klass_name = NULL; { // We have to lock the cpool to keep the oop from being resolved // while we are accessing it. But we must release the lock before @@ -252,7 +235,9 @@ if (tag.is_klass()) { // The klass has been inserted into the constant pool // very recently. - return VMToCompiler::createResolvedJavaType(cp->resolved_klass_at(index)->java_mirror(), CHECK_NH); + klass = cp->resolved_klass_at(index); + klass_name = klass->name(); + return klass; } else if (tag.is_symbol()) { klass_name = cp->symbol_at(index); } else { @@ -260,16 +245,10 @@ klass_name = cp->unresolved_klass_at(index); } } - Handle klass_name_string = java_lang_String::create_from_symbol(klass_name, CHECK_NH); - return VMToCompiler::createUnresolvedJavaType(klass_name_string, CHECK_NH); } else { - return VMToCompiler::createResolvedJavaType(klass->java_mirror(), CHECK_NH); + klass_name = klass->name(); } -} - -Handle GraalCompiler::get_JavaField(int offset, int flags, Symbol* field_name, Handle field_holder, Handle field_type, TRAPS) { - Handle name = java_lang_String::create_from_symbol(field_name, CHECK_NH); - return VMToCompiler::createJavaField(field_holder, name, field_type, offset, flags, false, CHECK_NH); + return klass; } BasicType GraalCompiler::kindToBasicType(jchar ch) { diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalCompiler.hpp --- a/src/share/vm/graal/graalCompiler.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalCompiler.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -71,34 +71,13 @@ // Print compilation timers and statistics virtual void print_timers(); - static Handle get_JavaTypeFromSignature(Symbol* signature, KlassHandle accessor, TRAPS); - static Handle get_JavaType(constantPoolHandle cp, int index, KlassHandle accessor, TRAPS); - static Handle get_JavaField(int offset, int flags, Symbol* field_name, Handle field_holder, Handle field_type, TRAPS); + static KlassHandle get_KlassFromSignature(Symbol* signature, KlassHandle loading_klass); + static KlassHandle get_Klass(constantPoolHandle cp, int index, KlassHandle accessor, Symbol*& klass_name); void exit(); static BasicType kindToBasicType(jchar ch); - static int to_cp_index_u2(int index) { - // Tag. - return index + ConstantPool::CPCACHE_INDEX_TAG; - } - - static int to_cp_index(int raw_index, Bytecodes::Code bc) { - int cp_index; - if (bc == Bytecodes::_invokedynamic) { - cp_index = raw_index; - assert(ConstantPool::is_invokedynamic_index(cp_index), "not an invokedynamic constant pool index"); - } else { - assert(bc == Bytecodes::_getfield || bc == Bytecodes::_putfield || - bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic || - bc == Bytecodes::_invokeinterface || bc == Bytecodes::_invokevirtual || - bc == Bytecodes::_invokespecial || bc == Bytecodes::_invokestatic, err_msg("unexpected invoke opcode: %d %s", bc, Bytecodes::name(bc))); - cp_index = to_cp_index_u2(raw_index); - } - return cp_index; - } - static BufferBlob* initialize_buffer_blob(); }; diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalCompilerToGPU.cpp --- a/src/share/vm/graal/graalCompilerToGPU.cpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,269 +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. - */ - -#include "precompiled.hpp" - -#include "memory/oopFactory.hpp" -#include "graal/graalCompiler.hpp" -#include "graal/graalEnv.hpp" -#include "graal/graalJavaAccess.hpp" -#include "runtime/gpu.hpp" -#include "runtime/javaCalls.hpp" -# include "ptx/vm/ptxKernelArguments.hpp" - -// Entry to native method implementation that transitions current thread to '_thread_in_vm'. -#define C2V_VMENTRY(result_type, name, signature) \ - JNIEXPORT result_type JNICALL c2v_ ## name signature { \ - TRACE_graal_3("CompilerToGPU::" #name); \ - GRAAL_VM_ENTRY_MARK; \ - -// Entry to native method implementation that calls a JNI function -// and hence cannot transition current thread to '_thread_in_vm'. -#define C2V_ENTRY(result_type, name, signature) \ - JNIEXPORT result_type JNICALL c2v_ ## name signature { \ - TRACE_graal_3("CompilerToGPU::" #name); \ - -#define C2V_END } - - -C2V_ENTRY(jlong, generateKernel, (JNIEnv *env, jobject, jbyteArray code, jstring name)) - if (gpu::is_available() == false || gpu::has_gpu_linkage() == false && gpu::is_initialized()) { - if (TraceGPUInteraction) { - tty->print_cr("generateKernel - not available / no linkage / not initialized"); - } - return 0; - } - jboolean is_copy; - jbyte *bytes = env->GetByteArrayElements(code, &is_copy); - jint len = env->GetArrayLength(code); - const char *namestr = env->GetStringUTFChars(name, &is_copy); - void *kernel = gpu::generate_kernel((unsigned char *)bytes, len, namestr); - if (kernel == NULL) { - tty->print_cr("[CUDA] *** Error: Failed to compile kernel"); - } else if (TraceGPUInteraction) { - tty->print_cr("[CUDA] Generated kernel"); - } - env->ReleaseByteArrayElements(code, bytes, 0); - env->ReleaseStringUTFChars(name, namestr); - - return (jlong)kernel; -C2V_END - -C2V_VMENTRY(jobject, executeExternalMethodVarargs, (JNIEnv *env, jobject, jobject args, jobject hotspotInstalledCode)) - ResourceMark rm; - HandleMark hm; - - if (gpu::is_available() == false || gpu::has_gpu_linkage() == false && gpu::is_initialized()) { - tty->print_cr("executeExternalMethodVarargs - not available / no linkage / not initialized"); - return NULL; - } - jlong nmethodValue = HotSpotInstalledCode::codeBlob(hotspotInstalledCode); - nmethod* nm = (nmethod*) (address) nmethodValue; - methodHandle mh = nm->method(); - Symbol* signature = mh->signature(); - - // start value is the kernel - jlong startValue = HotSpotInstalledCode::codeStart(hotspotInstalledCode); - - PTXKernelArguments ptxka(signature, (arrayOop) JNIHandles::resolve(args), mh->is_static()); - JavaValue result(ptxka.get_ret_type()); - if (!gpu::execute_kernel((address)startValue, ptxka, result)) { - return NULL; - } - - if (ptxka.get_ret_type() == T_VOID) { - return NULL; - } else if (ptxka.get_ret_type() == T_OBJECT || ptxka.get_ret_type() == T_ARRAY) { - return JNIHandles::make_local((oop) result.get_jobject()); - } else { - oop o = java_lang_boxing_object::create(ptxka.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL); - if (TraceGPUInteraction) { - switch (ptxka.get_ret_type()) { - case T_INT: - tty->print_cr("GPU execution returned (int) %d", result.get_jint()); - break; - case T_LONG: - tty->print_cr("GPU execution returned (long) %ld", result.get_jlong()); - break; - case T_FLOAT: - tty->print_cr("GPU execution returned (float) %f", result.get_jfloat()); - break; - case T_DOUBLE: - tty->print_cr("GPU execution returned (double) %f", result.get_jdouble()); - break; - default: - tty->print_cr("**** Value returned by GPU not yet handled"); - break; - } - } - return JNIHandles::make_local(o); - } -C2V_END - -C2V_VMENTRY(jobject, executeParallelMethodVarargs, (JNIEnv *env, - jobject, - jint dimX, jint dimY, jint dimZ, - jobject args, jobject hotspotInstalledCode)) - ResourceMark rm; - HandleMark hm; - - if (gpu::is_available() == false || gpu::has_gpu_linkage() == false && gpu::is_initialized()) { - tty->print_cr("executeParallelMethodVarargs - not available / no linkage / not initialized"); - return NULL; - } - jlong nmethodValue = HotSpotInstalledCode::codeBlob(hotspotInstalledCode); - nmethod* nm = (nmethod*) (address) nmethodValue; - methodHandle mh = nm->method(); - Symbol* signature = mh->signature(); - - // start value is the kernel - jlong startValue = HotSpotInstalledCode::codeStart(hotspotInstalledCode); - - if (UseHSAILSimulator) { - gpu::execute_kernel_void_1d((address)startValue, dimX, args, mh); - return NULL; - } - - PTXKernelArguments ptxka(signature, (arrayOop) JNIHandles::resolve(args), mh->is_static()); - JavaValue result(ptxka.get_ret_type()); - if (!gpu::execute_warp(dimX, dimY, dimZ, (address) startValue, ptxka, result)) { - return NULL; - } - - if (ptxka.get_ret_type() == T_VOID) { - return NULL; - } else if (ptxka.get_ret_type() == T_OBJECT || ptxka.get_ret_type() == T_ARRAY) { - return JNIHandles::make_local((oop) result.get_jobject()); - } else { - oop o = java_lang_boxing_object::create(ptxka.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL); - if (TraceGPUInteraction) { - switch (ptxka.get_ret_type()) { - case T_INT: - tty->print_cr("GPU execution returned %d", result.get_jint()); - break; - case T_FLOAT: - tty->print_cr("GPU execution returned %f", result.get_jfloat()); - break; - case T_DOUBLE: - tty->print_cr("GPU execution returned %g", result.get_jdouble()); - break; - default: - tty->print_cr("GPU returned unhandled"); - break; - } - } - return JNIHandles::make_local(o); - } -C2V_END - -JRT_ENTRY(jlong, invalidLaunchKernel(JavaThread* thread)) - SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_LinkageError(), "invalid kernel launch function"); - return 0L; -JRT_END - -C2V_VMENTRY(jlong, getLaunchKernelAddress, (JNIEnv *env, jobject)) - if (gpu::get_target_il_type() == gpu::PTX) { - return (jlong) gpu::Ptx::execute_kernel_from_vm; - } - return (jlong) invalidLaunchKernel; -C2V_END - -C2V_VMENTRY(jboolean, deviceInit, (JNIEnv *env, jobject)) - if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) { - if (TraceGPUInteraction) { - tty->print_cr("deviceInit - not available / no linkage"); - } - return false; - } - if (gpu::is_initialized()) { - tty->print_cr("deviceInit - already initialized"); - return true; - } - gpu::initialize_gpu(); - return gpu::is_initialized(); -C2V_END - -C2V_VMENTRY(jint, availableProcessors, (JNIEnv *env, jobject)) - if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) { - if (TraceGPUInteraction) { - tty->print_cr("deviceInit - not available / no linkage"); - } - return false; - } - return gpu::available_processors(); -C2V_END - -C2V_VMENTRY(jboolean, deviceDetach, (JNIEnv *env, jobject)) -return true; -C2V_END - - -#define CC (char*) /*cast a literal from (const char*)*/ -#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) - -#define RESOLVED_TYPE "Lcom/oracle/graal/api/meta/ResolvedJavaType;" -#define TYPE "Lcom/oracle/graal/api/meta/JavaType;" -#define METHOD "Lcom/oracle/graal/api/meta/JavaMethod;" -#define FIELD "Lcom/oracle/graal/api/meta/JavaField;" -#define SIGNATURE "Lcom/oracle/graal/api/meta/Signature;" -#define CONSTANT_POOL "Lcom/oracle/graal/api/meta/ConstantPool;" -#define CONSTANT "Lcom/oracle/graal/api/meta/Constant;" -#define KIND "Lcom/oracle/graal/api/meta/Kind;" -#define LOCAL "Lcom/oracle/graal/api/meta/Local;" -#define RUNTIME_CALL "Lcom/oracle/graal/api/code/RuntimeCall;" -#define EXCEPTION_HANDLERS "[Lcom/oracle/graal/api/meta/ExceptionHandler;" -#define REFLECT_METHOD "Ljava/lang/reflect/Method;" -#define REFLECT_CONSTRUCTOR "Ljava/lang/reflect/Constructor;" -#define REFLECT_FIELD "Ljava/lang/reflect/Field;" -#define STRING "Ljava/lang/String;" -#define OBJECT "Ljava/lang/Object;" -#define CLASS "Ljava/lang/Class;" -#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" -#define HS_RESOLVED_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;" -#define HS_RESOLVED_JAVA_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaType;" -#define HS_RESOLVED_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;" -#define HS_RESOLVED_FIELD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaField;" -#define HS_COMPILED_CODE "Lcom/oracle/graal/hotspot/HotSpotCompiledCode;" -#define HS_CONFIG "Lcom/oracle/graal/hotspot/HotSpotVMConfig;" -#define HS_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotMethod;" -#define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" -#define METHOD_DATA "Lcom/oracle/graal/hotspot/meta/HotSpotMethodData;" -#define METASPACE_METHOD "J" -#define METASPACE_METHOD_DATA "J" -#define NMETHOD "J" -#define GPUSPACE_METHOD "J" - -JNINativeMethod CompilerToGPU_methods[] = { - {CC"generateKernel", CC"([B" STRING ")"GPUSPACE_METHOD, FN_PTR(generateKernel)}, - {CC"deviceInit", CC"()Z", FN_PTR(deviceInit)}, - {CC"deviceDetach", CC"()Z", FN_PTR(deviceDetach)}, - {CC"availableProcessors", CC"()I", FN_PTR(availableProcessors)}, - {CC"executeExternalMethodVarargs", CC"(["OBJECT HS_INSTALLED_CODE")"OBJECT, FN_PTR(executeExternalMethodVarargs)}, - {CC"executeParallelMethodVarargs", CC"(III["OBJECT HS_INSTALLED_CODE")"OBJECT, FN_PTR(executeParallelMethodVarargs)}, - {CC"getLaunchKernelAddress", CC"()J", FN_PTR(getLaunchKernelAddress)}, -}; - -int CompilerToGPU_methods_count() { - return sizeof(CompilerToGPU_methods) / sizeof(JNINativeMethod); -} - diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalCompilerToGPU.hpp --- a/src/share/vm/graal/graalCompilerToGPU.hpp Sun Feb 23 17:00:35 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP -#define SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP - -#include "prims/jni.h" - -extern JNINativeMethod CompilerToGPU_methods[]; -int CompilerToGPU_methods_count(); - - -#endif // SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -40,6 +40,7 @@ #include "gc_implementation/g1/heapRegion.hpp" #include "runtime/javaCalls.hpp" #include "runtime/vmStructs.hpp" +#include "runtime/gpu.hpp" Method* getMethodFromHotSpotMethod(oop hotspot_method) { @@ -196,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)) @@ -251,53 +257,57 @@ return JNIHandles::make_local(THREAD, result); C2V_END -C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode)) - Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); - index = GraalCompiler::to_cp_index(index, bc); +C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index)) constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool; oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index); return JNIHandles::make_local(THREAD, appendix_oop); C2V_END -C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode)) +C2V_VMENTRY(jlong, lookupMethodInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode, jlongArray unresolvedInfo_handle)) constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool; instanceKlassHandle pool_holder(cp->pool_holder()); Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); - int cp_index = GraalCompiler::to_cp_index(index, bc); - methodHandle method = GraalEnv::get_method_by_index(cp, cp_index, bc, pool_holder); + methodHandle method = GraalEnv::get_method_by_index(cp, index, bc, pool_holder); if (!method.is_null()) { - Handle holder = VMToCompiler::createResolvedJavaType(method->method_holder()->java_mirror(), CHECK_NULL); - return JNIHandles::make_local(THREAD, VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD)); + return (jlong) method(); } else { - // Get the method's name and signature. - Handle name = java_lang_String::create_from_symbol(cp->name_ref_at(cp_index), CHECK_NULL); - Handle signature = java_lang_String::create_from_symbol(cp->signature_ref_at(cp_index), CHECK_NULL); + // Get the unresolved method's name and signature. + typeArrayOop unresolvedInfo = (typeArrayOop) JNIHandles::resolve(unresolvedInfo_handle); + assert(unresolvedInfo != NULL && unresolvedInfo->length() == 4, "must be"); + unresolvedInfo->long_at_put(0, (jlong) cp->name_ref_at(index)); + unresolvedInfo->long_at_put(1, (jlong) cp->signature_ref_at(index)); Handle type; if (bc != Bytecodes::_invokedynamic) { - int holder_index = cp->klass_ref_index_at(cp_index); - type = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); + int holder_index = cp->klass_ref_index_at(index); + Symbol* klass_name = NULL; + KlassHandle klass = GraalCompiler::get_Klass(cp, holder_index, cp->pool_holder(), klass_name); + unresolvedInfo->long_at_put(2, (jlong) klass_name); + unresolvedInfo->long_at_put(3, (jlong) klass()); } else { - type = Handle(SystemDictionary::MethodHandle_klass()->java_mirror()); + unresolvedInfo->long_at_put(3, (jlong) SystemDictionary::MethodHandle_klass()); } - return JNIHandles::make_local(THREAD, VMToCompiler::createUnresolvedJavaMethod(name, signature, type, THREAD)); + return 0L; } C2V_END -C2V_VMENTRY(jobject, lookupTypeInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index)) +C2V_VMENTRY(jlong, lookupTypeInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jlongArray unresolvedTypeName_handle)) ConstantPool* cp = (ConstantPool*) metaspace_constant_pool; - Handle result = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); - return JNIHandles::make_local(THREAD, result()); + Symbol* klass_name = NULL; + KlassHandle klass = GraalCompiler::get_Klass(cp, index, cp->pool_holder(), klass_name); + typeArrayOop unresolvedTypeName = (typeArrayOop) JNIHandles::resolve(unresolvedTypeName_handle); + unresolvedTypeName->long_at_put(0, (jlong) klass_name); + return (jlong) klass(); C2V_END -C2V_VMENTRY(void, lookupReferencedTypeInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte op)) +C2V_VMENTRY(void, loadReferencedTypeInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte op)) ConstantPool* cp = (ConstantPool*) metaspace_constant_pool; Bytecodes::Code bc = (Bytecodes::Code) (((int) op) & 0xFF); if (bc != Bytecodes::_checkcast && bc != Bytecodes::_instanceof && bc != Bytecodes::_new && bc != Bytecodes::_anewarray && bc != Bytecodes::_multianewarray && bc != Bytecodes::_ldc && bc != Bytecodes::_ldc_w && bc != Bytecodes::_ldc2_w) { - index = cp->remap_instruction_operand_from_cache(GraalCompiler::to_cp_index(index, bc)); + index = cp->remap_instruction_operand_from_cache(index); } constantTag tag = cp->tag_at(index); if (tag.is_field_or_method()) { @@ -313,42 +323,44 @@ } C2V_END -C2V_VMENTRY(jobject, lookupFieldInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode)) +C2V_VMENTRY(jboolean, lookupFieldInPool, (JNIEnv *env, jobject, jlong metaspace_constant_pool, jint index, jbyte opcode, jlongArray info_handle)) ResourceMark rm; - int cp_index = GraalCompiler::to_cp_index_u2(index); constantPoolHandle cp = (ConstantPool*) metaspace_constant_pool; - int nt_index = cp->name_and_type_ref_index_at(cp_index); - int sig_index = cp->signature_ref_index_at(nt_index); - Symbol* signature = cp->symbol_at(sig_index); + int nt_index = cp->name_and_type_ref_index_at(index); + int type_index = cp->signature_ref_index_at(nt_index); + Symbol* type_name = cp->symbol_at(type_index); int name_index = cp->name_ref_index_at(nt_index); Symbol* name = cp->symbol_at(name_index); - int holder_index = cp->klass_ref_index_at(cp_index); - Handle holder = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); - instanceKlassHandle holder_klass; + int holder_index = cp->klass_ref_index_at(index); + Symbol* holder_name = NULL; + KlassHandle holder = GraalCompiler::get_Klass(cp, holder_index, cp->pool_holder(), holder_name); + KlassHandle type = GraalCompiler::get_KlassFromSignature(type_name, cp->pool_holder()); + typeArrayOop info = (typeArrayOop) JNIHandles::resolve(info_handle); + assert(info != NULL && info->length() == 7, "must be"); + info->long_at_put(0, (jlong) name); + info->long_at_put(1, (jlong) type_name); + info->long_at_put(2, (jlong) type()); + info->long_at_put(3, (jlong) holder_name); + info->long_at_put(4, (jlong) holder()); Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); - int offset = -1; - AccessFlags flags; - if (holder->klass() == SystemDictionary::HotSpotResolvedObjectType_klass()) { + if (!holder.is_null()) { + int offset = -1; fieldDescriptor result; - LinkResolver::resolve_field_access(result, cp, cp_index, Bytecodes::java_code(code), true, false, Thread::current()); + LinkResolver::resolve_field_access(result, cp, index, Bytecodes::java_code(code), true, false, Thread::current()); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; } else { - offset = result.offset(); - flags = result.access_flags(); - holder_klass = result.field_holder(); - holder = VMToCompiler::createResolvedJavaType(holder_klass->java_mirror(), CHECK_NULL); + info->long_at_put(4, (jlong) result.field_holder()); + info->long_at_put(5, (jlong) result.access_flags().as_int()); + info->long_at_put(6, (jlong) result.offset()); + return true; } } - - Handle type = GraalCompiler::get_JavaTypeFromSignature(signature, cp->pool_holder(), CHECK_NULL); - Handle field_handle = GraalCompiler::get_JavaField(offset, flags.as_int(), name, holder, type, THREAD); - - return JNIHandles::make_local(THREAD, field_handle()); + return false; C2V_END C2V_VMENTRY(jlong, resolveMethod, (JNIEnv *, jobject, jobject resolved_type, jstring name, jstring signature)) @@ -373,29 +385,6 @@ return Dependencies::find_finalizable_subclass(klass) != NULL; C2V_END -C2V_VMENTRY(jobject, getInstanceFields, (JNIEnv *, jobject, jobject klass)) - ResourceMark rm; - - instanceKlassHandle k = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(klass)); - GrowableArray fields(k->java_fields_count()); - - for (AllFieldStream fs(k()); !fs.done(); fs.next()) { - if (!fs.access_flags().is_static()) { - Handle type = GraalCompiler::get_JavaTypeFromSignature(fs.signature(), k, THREAD); - int flags = fs.access_flags().as_int(); - bool internal = fs.access_flags().is_internal(); - Handle name = java_lang_String::create_from_symbol(fs.name(), THREAD); - Handle field = VMToCompiler::createJavaField(JNIHandles::resolve(klass), name, type, fs.offset(), flags, internal, THREAD); - fields.append(field()); - } - } - objArrayHandle field_array = oopFactory::new_objArray(SystemDictionary::HotSpotResolvedJavaField_klass(), fields.length(), CHECK_NULL); - for (int i = 0; i < fields.length(); ++i) { - field_array->obj_at_put(i, fields.at(i)()); - } - return JNIHandles::make_local(THREAD, field_array()); -C2V_END - C2V_VMENTRY(jlong, getClassInitializer, (JNIEnv *, jobject, jobject klass)) instanceKlassHandle k(THREAD, java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(klass))); Method* clinit = k->class_initializer(); @@ -553,7 +542,15 @@ //------------------------------------------------------------------------------------------------ set_int("graalCountersThreadOffset", in_bytes(JavaThread::graal_counters_offset())); - set_int("graalCountersSize", (jint) GRAAL_COUNTERS_SIZE); + set_int("graalCountersSize", (jint) GraalCounterSize); + + //------------------------------------------------------------------------------------------------ + + 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 #undef set_boolean #undef set_int @@ -669,6 +666,9 @@ } else { Disassembler::decode(cb, &st); } + if (st.size() <= 0) { + return NULL; + } Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); return JNIHandles::make_local(result()); @@ -813,20 +813,32 @@ C2V_END C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv *env, jobject)) - typeArrayOop arrayOop = oopFactory::new_longArray(GRAAL_COUNTERS_SIZE, CHECK_NULL); + typeArrayOop arrayOop = oopFactory::new_longArray(GraalCounterSize, CHECK_NULL); JavaThread::collect_counters(arrayOop); return (jlongArray) JNIHandles::make_local(arrayOop); C2V_END +C2V_ENTRY(jobject, getGPUs, (JNIEnv *env, jobject)) +#if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux) || defined(TARGET_OS_FAMILY_windows) + return gpu::probe_gpus(env); +#else + return env->NewStringUTF(""); +#endif +C2V_END + C2V_VMENTRY(int, allocateCompileId, (JNIEnv *env, jobject, jobject hotspot_method, int entry_bci)) HandleMark hm; ResourceMark rm; Method* method = getMethodFromHotSpotMethod(JNIHandles::resolve(hotspot_method)); - MutexLocker locker(MethodCompileQueue_lock, thread); - return CompileBroker::assign_compile_id(method, entry_bci); + return CompileBroker::assign_compile_id_unlocked(THREAD, method, entry_bci); C2V_END +C2V_VMENTRY(jboolean, isMature, (JNIEnv *env, jobject, jlong metaspace_method_data)) + MethodData* mdo = asMethodData(metaspace_method_data); + return mdo != NULL && mdo->is_mature(); +C2V_END + #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) @@ -840,12 +852,12 @@ #define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" #define HS_RESOLVED_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;" #define HS_RESOLVED_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;" -#define HS_RESOLVED_FIELD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaField;" #define HS_COMPILED_CODE "Lcom/oracle/graal/hotspot/HotSpotCompiledCode;" #define HS_CONFIG "Lcom/oracle/graal/hotspot/HotSpotVMConfig;" #define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" #define METASPACE_KLASS "J" #define METASPACE_METHOD "J" +#define METASPACE_METHOD_DATA "J" #define METASPACE_CONSTANT_POOL "J" JNINativeMethod CompilerToVM_methods[] = { @@ -857,17 +869,17 @@ {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)}, - {CC"lookupAppendixInPool", CC"("METASPACE_CONSTANT_POOL"IB)"OBJECT, FN_PTR(lookupAppendixInPool)}, - {CC"lookupMethodInPool", CC"("METASPACE_CONSTANT_POOL"IB)"METHOD, FN_PTR(lookupMethodInPool)}, - {CC"lookupTypeInPool", CC"("METASPACE_CONSTANT_POOL"I)"TYPE, FN_PTR(lookupTypeInPool)}, - {CC"lookupReferencedTypeInPool", CC"("METASPACE_CONSTANT_POOL"IB)V", FN_PTR(lookupReferencedTypeInPool)}, - {CC"lookupFieldInPool", CC"("METASPACE_CONSTANT_POOL"IB)"FIELD, FN_PTR(lookupFieldInPool)}, + {CC"lookupAppendixInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)}, + {CC"lookupMethodInPool", CC"("METASPACE_CONSTANT_POOL"IB[J)"METASPACE_METHOD, FN_PTR(lookupMethodInPool)}, + {CC"lookupTypeInPool", CC"("METASPACE_CONSTANT_POOL"I[J)"METASPACE_KLASS, FN_PTR(lookupTypeInPool)}, + {CC"loadReferencedTypeInPool", CC"("METASPACE_CONSTANT_POOL"IB)V", FN_PTR(loadReferencedTypeInPool)}, + {CC"lookupFieldInPool", CC"("METASPACE_CONSTANT_POOL"IB[J)Z", FN_PTR(lookupFieldInPool)}, {CC"resolveMethod", CC"("HS_RESOLVED_TYPE STRING STRING")"METASPACE_METHOD, FN_PTR(resolveMethod)}, - {CC"getInstanceFields", CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_FIELD, FN_PTR(getInstanceFields)}, {CC"getClassInitializer", CC"("HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getClassInitializer)}, {CC"hasFinalizableSubclass", CC"("HS_RESOLVED_TYPE")Z", FN_PTR(hasFinalizableSubclass)}, {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, @@ -888,7 +900,9 @@ {CC"readUnsafeUncompressedPointer", CC"("OBJECT"J)"OBJECT, FN_PTR(readUnsafeUncompressedPointer)}, {CC"readUnsafeKlassPointer", CC"("OBJECT")J", FN_PTR(readUnsafeKlassPointer)}, {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)}, + {CC"getGPUs", CC"()"STRING, FN_PTR(getGPUs)}, {CC"allocateCompileId", CC"("HS_RESOLVED_METHOD"I)I", FN_PTR(allocateCompileId)}, + {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)}, }; int CompilerToVM_methods_count() { diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalGlobals.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -55,6 +55,12 @@ product(intx, TraceGraal, 0, \ "Trace level for Graal") \ \ + product(intx, GraalCounterSize, 0, \ + "Reserved size for benchmark counters") \ + \ + product(bool, GraalCountersExcludeCompiler, true, \ + "Exclude Graal compiler threads from benchmark counters") \ + \ product(bool, GraalDeferredInitBarriers, true, \ "Defer write barriers of young objects") \ \ diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalJavaAccess.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -169,7 +169,6 @@ end_class \ start_class(CompilationResult_Mark) \ oop_field(CompilationResult_Mark, id, "Ljava/lang/Object;") \ - oop_field(CompilationResult_Mark, references, "[Lcom/oracle/graal/api/code/CompilationResult$Mark;") \ end_class \ start_class(DebugInfo) \ oop_field(DebugInfo, bytecodePosition, "Lcom/oracle/graal/api/code/BytecodePosition;") \ diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalVMToCompiler.cpp --- a/src/share/vm/graal/graalVMToCompiler.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalVMToCompiler.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -171,80 +171,3 @@ JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::compileTheWorld_name(), vmSymbols::void_method_signature(), &args, THREAD); check_pending_exception("Error while calling compileTheWorld"); } - -oop VMToCompiler::createJavaField(Handle holder, Handle name, Handle type, int index, int flags, jboolean internal, TRAPS) { - assert(!holder.is_null(), "just checking"); - assert(!name.is_null(), "just checking"); - assert(!type.is_null(), "just checking"); - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(instance()); - args.push_oop(holder); - args.push_oop(name); - args.push_oop(type); - args.push_int(index); - args.push_int(flags); - args.push_int(internal); - JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::createJavaField_name(), vmSymbols::createJavaField_signature(), &args, THREAD); - check_pending_exception("Error while calling createJavaField"); - assert(result.get_type() == T_OBJECT, "just checking"); - return (oop) result.get_jobject(); -} - -oop VMToCompiler::createUnresolvedJavaMethod(Handle name, Handle signature, Handle holder, TRAPS) { - assert(!name.is_null(), "just checking"); - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(instance()); - args.push_oop(name); - args.push_oop(signature); - args.push_oop(holder); - JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::createUnresolvedJavaMethod_name(), vmSymbols::createUnresolvedJavaMethod_signature(), &args, THREAD); - check_pending_exception("Error while calling createUnresolvedJavaMethod"); - return (oop) result.get_jobject(); -} - -oop VMToCompiler::createResolvedJavaMethod(Handle holder, Method* method, TRAPS) { - assert(!holder.is_null(), "just checking"); - assert(method != NULL, "just checking"); - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(instance()); - args.push_oop(holder); - args.push_long((jlong) (address) method); - JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::createResolvedJavaMethod_name(), vmSymbols::createResolvedJavaMethod_signature(), &args, THREAD); - check_pending_exception("Error while calling createResolvedJavaMethod"); - assert(result.get_type() == T_OBJECT, "just checking"); - return (oop) result.get_jobject(); -} - -oop VMToCompiler::createPrimitiveJavaType(int basic_type, TRAPS) { - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(instance()); - args.push_int(basic_type); - JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::createPrimitiveJavaType_name(), vmSymbols::createPrimitiveJavaType_signature(), &args, THREAD); - check_pending_exception("Error while calling createPrimitiveJavaType"); - return (oop) result.get_jobject(); -} - -oop VMToCompiler::createUnresolvedJavaType(Handle name, TRAPS) { - assert(!name.is_null(), "just checking"); - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(instance()); - args.push_oop(name); - JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::createUnresolvedJavaType_name(), vmSymbols::createUnresolvedJavaType_signature(), &args, THREAD); - check_pending_exception("Error while calling createUnresolvedJavaType"); - return (oop) result.get_jobject(); -} - -oop VMToCompiler::createResolvedJavaType(Handle java_mirror, TRAPS) { - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(instance()); - args.push_oop(java_mirror); - JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::createResolvedJavaType_name(), vmSymbols::createResolvedJavaType_signature(), &args, THREAD); - check_pending_exception("Error while calling createResolvedJavaType"); - return (oop) result.get_jobject(); -} diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/graalVMToCompiler.hpp --- a/src/share/vm/graal/graalVMToCompiler.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/graalVMToCompiler.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -74,24 +74,6 @@ // public abstract void compileTheWorld(); static void compileTheWorld(); - - // public abstract JavaField createJavaField(JavaType holder, String name, JavaType type, int flags, int offset); - static oop createJavaField(Handle holder, Handle name, Handle type, int index, int flags, jboolean internal, TRAPS); - - // public abstract JavaMethod createUnresolvedJavaMethod(String name, String signature, JavaType holder); - static oop createUnresolvedJavaMethod(Handle name, Handle signature, Handle holder, TRAPS); - - // public abstract JavaMethod createResolvedJavaMethod(JavaType holder, long metaspaceMethod); - static oop createResolvedJavaMethod(Handle holder, Method* method, TRAPS); - - // public abstract JavaType createUnresolvedJavaType(String name); - static oop createUnresolvedJavaType(Handle name, TRAPS); - - // public abstract ResolvedJavaType createResolvedJavaType(Class javaMirror); - static oop createResolvedJavaType(Handle java_mirror, TRAPS); - - // public abstract JavaType createPrimitiveJavaType(int basicType); - static oop createPrimitiveJavaType(int basicType, TRAPS); }; inline void check_pending_exception(const char* message, bool dump_core = false) { diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/graal/vmStructs_graal.hpp --- a/src/share/vm/graal/vmStructs_graal.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/graal/vmStructs_graal.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -34,11 +34,14 @@ #define VM_TYPES_GRAAL(declare_type, declare_toplevel_type) \ -#define VM_INT_CONSTANTS_GRAAL(declare_constant) \ - declare_constant(Deoptimization::Reason_aliasing) \ - declare_constant(GraalEnv::ok) \ - declare_constant(GraalEnv::dependencies_failed) \ - declare_constant(GraalEnv::cache_full) \ - declare_constant(GraalEnv::code_too_large) \ +#define VM_INT_CONSTANTS_GRAAL(declare_constant, declare_preprocessor_constant) \ + declare_constant(Deoptimization::Reason_aliasing) \ + declare_constant(GraalEnv::ok) \ + declare_constant(GraalEnv::dependencies_failed) \ + declare_constant(GraalEnv::cache_full) \ + declare_constant(GraalEnv::code_too_large) \ + \ + declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ + declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ #endif // SHARE_VM_GRAAL_VMSTRUCTS_GRAAL_HPP diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/arguments.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -131,9 +131,6 @@ SystemProperty *Arguments::_java_home = NULL; SystemProperty *Arguments::_java_class_path = NULL; SystemProperty *Arguments::_sun_boot_class_path = NULL; -#ifdef GRAAL -SystemProperty *Arguments::_graal_gpu_isalist = NULL; -#endif char* Arguments::_meta_index_path = NULL; char* Arguments::_meta_index_dir = NULL; @@ -197,9 +194,6 @@ _sun_boot_class_path = new SystemProperty("sun.boot.class.path", NULL, true); _java_class_path = new SystemProperty("java.class.path", "", true); -#ifdef GRAAL - _graal_gpu_isalist = new SystemProperty("graal.gpu.isalist", NULL, true); -#endif // Add to System Property list. PropertyList_add(&_system_properties, _java_ext_dirs); @@ -209,9 +203,6 @@ PropertyList_add(&_system_properties, _java_home); PropertyList_add(&_system_properties, _java_class_path); PropertyList_add(&_system_properties, _sun_boot_class_path); -#ifdef GRAAL - PropertyList_add(&_system_properties, _graal_gpu_isalist); -#endif // Set OS specific system properties values os::init_system_properties_values(); @@ -3844,24 +3835,6 @@ } } -#ifdef GRAAL - if (_graal_gpu_isalist->value() == NULL) { - // Initialize the graal.gpu.isalist system property if - // a) it was not explicitly defined by the user and - // b) at least one GPU is available. - // GPU offload can be disabled by setting the property - // to the empty string on the command line - if (gpu::is_available() && gpu::has_gpu_linkage()) { - if (gpu::get_target_il_type() == gpu::PTX) { - _graal_gpu_isalist->append_value("PTX"); - } - if (gpu::get_target_il_type() == gpu::HSAIL) { - _graal_gpu_isalist->append_value("HSAIL"); - } - } - } -#endif - return JNI_OK; } diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/compilationPolicy.cpp --- a/src/share/vm/runtime/compilationPolicy.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/compilationPolicy.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -163,53 +163,37 @@ bool CompilationPolicy::can_be_offloaded_to_gpu(methodHandle m) { #ifdef GRAAL - if (GPUOffload) { - // Check if this method can be offloaded to GPU. - // 1. Offload it to GPU if it is a Lambda method + if (GPUOffload && gpu::initialized_gpus() > 0) { + // Check if this method can be off-loaded to GPU. if (m->is_synthetic()) { - // A lambda method is a syntheric method. + // A lambda method is a synthetic method. Symbol * klass_name = m->method_holder()->name(); Symbol * method_name = m->name(); - bool offloadToGPU = false; { 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)) { - offloadToGPU = true; + 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; + } } } } } } - if (offloadToGPU) { - // If GPU is available and the necessary linkage is available - // return true indicatin that this method must be compiled. - if (gpu::is_available() && gpu::has_gpu_linkage()) { - if (TraceGPUInteraction) { - tty->print("Compiling Lambda method "); - m->print_short_name(); - switch (gpu::get_target_il_type()) { - case gpu::PTX : - tty->print_cr("to PTX"); - break; - case gpu::HSAIL : - tty->print_cr("to HSAIL"); - break; - default : - tty->print_cr("to Unknown GPU!!!"); - } - } - return true; - } - } } } #endif - return false; } diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/deoptimization.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -1347,7 +1347,7 @@ DeoptReason reason = trap_request_reason(trap_request); DeoptAction action = trap_request_action(trap_request); #ifdef GRAAL - short debug_id = trap_request_debug_id(trap_request); + int debug_id = trap_request_debug_id(trap_request); #endif jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1 @@ -1359,7 +1359,7 @@ ScopeDesc* trap_scope = cvf->scope(); if (TraceDeoptimization) { - tty->print_cr(" bci=%d pc=%d, relative_pc=%d, method=%s" GRAAL_ONLY(", debug_id=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name()->as_C_string() + tty->print_cr(" bci=%d pc=%d, relative_pc=%d, method=%s" GRAAL_ONLY(", debug_id=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string() #ifdef GRAAL , debug_id #endif @@ -2038,7 +2038,7 @@ const char* reason = trap_reason_name(trap_request_reason(trap_request)); const char* action = trap_action_name(trap_request_action(trap_request)); #ifdef GRAAL - short debug_id = trap_request_debug_id(trap_request); + int debug_id = trap_request_debug_id(trap_request); #endif size_t len; if (unloaded_class_index < 0) { diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/deoptimization.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -294,10 +294,9 @@ // standard action for unloaded CP entry return _unloaded_action; } - static short trap_request_debug_id(int trap_request) { + static int trap_request_debug_id(int trap_request) { if (trap_request < 0) - return (DeoptAction) - ((~(trap_request) >> _debug_id_shift) & right_n_bits(_debug_id_bits)); + return ((~(trap_request) >> _debug_id_shift) & right_n_bits(_debug_id_bits)); else // standard action for unloaded CP entry return 0; diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/globals.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -3840,9 +3840,6 @@ product(bool , AllowNonVirtualCalls, false, \ "Obey the ACC_SUPER flag and allow invokenonvirtual calls") \ \ - product(bool, UseHSAILSimulator, false, \ - "Run code on HSAIL Simulator") \ - \ diagnostic(ccstr, SharedArchiveFile, NULL, \ "Override the default location of the CDS archive file") \ \ diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/gpu.cpp --- a/src/share/vm/runtime/gpu.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/gpu.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -26,85 +26,11 @@ #include "runtime/gpu.hpp" #include "runtime/handles.hpp" -bool gpu::_available = false; // does the hardware exist? -bool gpu::_gpu_linkage = false; // is the driver library to access the GPU installed -bool gpu::_initialized = false; // is the GPU device initialized -gpu::TargetGPUIL gpu::_targetIL = gpu::NONE; // No GPU detected yet. - -void gpu::init() { -#if defined(TARGET_OS_FAMILY_bsd) || defined(TARGET_OS_FAMILY_linux) || defined(TARGET_OS_FAMILY_windows) - gpu::probe_gpu(); - if (gpu::get_target_il_type() == gpu::PTX) { - set_gpu_linkage(gpu::Ptx::probe_linkage()); - } else if (gpu::get_target_il_type() == gpu::HSAIL) { - set_gpu_linkage(gpu::Hsail::probe_linkage()); - } else { - set_gpu_linkage(false); - } -#endif -} - -void gpu::initialize_gpu() { - if (gpu::has_gpu_linkage()) { - if (gpu::get_target_il_type() == gpu::PTX) { - set_initialized(gpu::Ptx::initialize_gpu()); - } else if (gpu::get_target_il_type() == gpu::HSAIL) { - set_initialized(gpu::Hsail::initialize_gpu()); - } - } -} - -void * gpu::generate_kernel(unsigned char *code, int code_len, const char *name) { - if (gpu::has_gpu_linkage()) { - if (gpu::get_target_il_type() == gpu::PTX) { - return (gpu::Ptx::generate_kernel(code, code_len, name)); - } else if (gpu::get_target_il_type() == gpu::HSAIL) { - return (gpu::Hsail::generate_kernel(code, code_len, name)); - } - } - return NULL; -} +int gpu::_initialized_gpus = 0; -bool gpu::execute_kernel(address kernel, PTXKernelArguments & ptxka, JavaValue& ret) { - if (gpu::has_gpu_linkage()) { - if (gpu::get_target_il_type() == gpu::PTX) { - return (gpu::Ptx::execute_kernel(kernel, ptxka, ret)); - } - // Add kernel execution functionality of other GPUs here +void gpu::initialized_gpu(const char* name) { + _initialized_gpus++; + if (TraceGPUInteraction) { + tty->print_cr("[GPU] registered initialization of %s (total initialized: %d)", name, _initialized_gpus); } - return false; -} - -// This is HSAIL specific to work with Sumatra JDK -bool gpu::execute_kernel_void_1d(address kernel, int dimX, jobject args, methodHandle& mh) { - if (gpu::has_gpu_linkage()) { - if (gpu::get_target_il_type() == gpu::HSAIL) { - return (gpu::Hsail::execute_kernel_void_1d(kernel, dimX, args, mh)); - } - } - return false; - } - - -bool gpu::execute_warp(int dimX, int dimY, int dimZ, - address kernel, PTXKernelArguments & ptxka, JavaValue& ret) { - if (gpu::has_gpu_linkage()) { - if (gpu::get_target_il_type() == gpu::PTX) { - return (gpu::Ptx::execute_warp(dimX, dimY, dimZ, kernel, ptxka, ret)); - } - // Add kernel execution functionality of other GPUs here - } - return false; -} - -int gpu::available_processors() { - if (gpu::has_gpu_linkage()) { - if (gpu::get_target_il_type() == gpu::PTX) { - return (gpu::Ptx::total_cores()); - } - // Add kernel execution functionality of other GPUs here - } - return 0; -} - diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/gpu.hpp --- a/src/share/vm/runtime/gpu.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/gpu.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -27,85 +27,23 @@ #include "runtime/atomic.hpp" #include "oops/symbol.hpp" - -class PTXKernelArguments; - -// gpu defines the interface to the graphics processor; this includes traditional -// GPU services such as graphics kernel load and execute. - - -class gpu: AllStatic { -public: - - enum TargetGPUIL { NONE = 0, PTX = 1, HSAIL = 2}; - static void init(void); - - static void probe_gpu(); - - static void initialize_gpu(); +#include "utilities/array.hpp" - static int available_processors(); - - static void * generate_kernel(unsigned char *code, int code_len, const char *name); - - static bool execute_warp(int dimX, int dimY, int dimZ, - address kernel, PTXKernelArguments & ptxka, JavaValue & ret); - - static bool execute_kernel(address kernel, PTXKernelArguments & ptxka, JavaValue & ret); +// Defines the interface to the graphics processor(s). +class gpu : AllStatic { + private: + static int _initialized_gpus; // number of initialize GPU devices - // No return value from HSAIL kernels - static bool execute_kernel_void_1d(address kernel, int dimX, jobject args, methodHandle& mh); - - static void set_available(bool value) { - _available = value; - } - - static bool is_available() { return _available; } - - static void set_initialized(bool value) { - _initialized = value; - } + public: - static bool is_initialized() { return _initialized; } - - static void set_gpu_linkage(bool value) { - _gpu_linkage = value; - } - - static bool has_gpu_linkage() { return _gpu_linkage; } - - static void set_target_il_type(TargetGPUIL value) { - _targetIL = value; - } - - static enum gpu::TargetGPUIL get_target_il_type() { - return _targetIL; - } + // Notification of a GPU device that has been initialized. + static void initialized_gpu(const char* name); -protected: - static bool _available; - static bool _gpu_linkage; - static bool _initialized; - static TargetGPUIL _targetIL; - - // Platform dependent stuff -#ifdef TARGET_OS_FAMILY_linux -# include "gpu_linux.hpp" -#endif -#ifdef TARGET_OS_FAMILY_solaris -#endif -#ifdef TARGET_OS_FAMILY_windows -# include "gpu_windows.hpp" -#endif -#ifdef TARGET_OS_FAMILY_bsd -# include "gpu_bsd.hpp" -#endif - -public: -# include "ptx/vm/gpu_ptx.hpp" -# include "hsail/vm/gpu_hsail.hpp" - + // Gets a comma separated list of supported GPU architecture names. + static jobject probe_gpus(JNIEnv* env); + + // Gets the number of GPU devices that have been initialized. + static int initialized_gpus() { return _initialized_gpus; } }; - #endif // SHARE_VM_RUNTIME_GPU_HPP diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/sharedRuntime.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -402,6 +402,12 @@ const VMRegPair *regs, AdapterFingerPrint* fingerprint); + static void gen_i2c_adapter(MacroAssembler *_masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs); + // OSR support // OSR_migration_begin will extract the jvm state from an interpreter diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/thread.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -1418,31 +1418,27 @@ #ifdef GRAAL -#if GRAAL_COUNTERS_SIZE > 0 -jlong JavaThread::_graal_old_thread_counters[GRAAL_COUNTERS_SIZE]; +jlong* JavaThread::_graal_old_thread_counters; bool graal_counters_include(oop threadObj) { - return !GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS || threadObj == NULL || threadObj->klass() != SystemDictionary::CompilerThread_klass(); + return !GraalCountersExcludeCompiler || threadObj == NULL || threadObj->klass() != SystemDictionary::CompilerThread_klass(); } void JavaThread::collect_counters(typeArrayOop array) { - MutexLocker tl(Threads_lock); - for (int i = 0; i < array->length(); i++) { - array->long_at_put(i, _graal_old_thread_counters[i]); - } - for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { - if (graal_counters_include(tp->threadObj())) { - for (int i = 0; i < array->length(); i++) { - array->long_at_put(i, array->long_at(i) + tp->_graal_counters[i]); + if (GraalCounterSize > 0) { + MutexLocker tl(Threads_lock); + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, _graal_old_thread_counters[i]); + } + for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { + if (graal_counters_include(tp->threadObj())) { + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, array->long_at(i) + tp->_graal_counters[i]); + } } } } } -#else -void JavaThread::collect_counters(typeArrayOop array) { - // empty -} -#endif // GRAAL_COUNTERS_SIZE > 0 #endif // GRAAL @@ -1486,11 +1482,12 @@ _graal_alternate_call_target = NULL; _graal_implicit_exception_pc = NULL; _graal_compiling = false; -#if GRAAL_COUNTERS_SIZE > 0 - for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) { - _graal_counters[i] = 0; + if (GraalCounterSize > 0) { + _graal_counters = NEW_C_HEAP_ARRAY(jlong, GraalCounterSize, mtInternal); + memset(_graal_counters, 0, sizeof(jlong) * GraalCounterSize); + } else { + _graal_counters = NULL; } -#endif // GRAAL_COUNTER_SIZE > 0 #endif // GRAAL (void)const_cast(_exception_oop = NULL); _exception_pc = 0; @@ -1680,13 +1677,14 @@ if (_thread_profiler != NULL) delete _thread_profiler; if (_thread_stat != NULL) delete _thread_stat; -#if defined(GRAAL) && (GRAAL_COUNTERS_SIZE > 0) - if (graal_counters_include(threadObj())) { - for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) { +#ifdef GRAAL + if (GraalCounterSize > 0 && graal_counters_include(threadObj())) { + for (int i = 0; i < GraalCounterSize; i++) { _graal_old_thread_counters[i] += _graal_counters[i]; } + FREE_C_HEAP_ARRAY(jlong, _graal_counters, mtInternal); } -#endif +#endif // GRAAL } @@ -3394,14 +3392,6 @@ jint parse_result = Arguments::parse(args); if (parse_result != JNI_OK) return parse_result; -#ifdef GRAAL - if (GPUOffload) { - // Probe for existance of supported GPU and initialize it if one - // exists. - gpu::init(); - } -#endif - os::init_before_ergo(); jint ergo_result = Arguments::apply_ergo(); @@ -3461,6 +3451,15 @@ // Initialize global data structures and create system classes in heap vm_init_globals(); +#ifdef GRAAL + if (GraalCounterSize > 0) { + JavaThread::_graal_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, GraalCounterSize, mtInternal); + memset(JavaThread::_graal_old_thread_counters, 0, sizeof(jlong) * GraalCounterSize); + } else { + JavaThread::_graal_old_thread_counters = NULL; + } +#endif // GRAAL + // Attach the main thread to this os thread JavaThread* main_thread = new JavaThread(); main_thread->set_thread_state(_thread_in_vm); @@ -4112,6 +4111,12 @@ delete thread; +#ifdef GRAAL + if (GraalCounterSize > 0) { + FREE_C_HEAP_ARRAY(jlong, JavaThread::_graal_old_thread_counters, mtInternal); + } +#endif // GRAAL + // exit_globals() will delete tty exit_globals(); diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/thread.hpp Wed Mar 05 19:40:15 2014 -0800 @@ -922,16 +922,10 @@ address _graal_implicit_exception_pc; // pc at which the most recent implicit exception occurred bool _graal_compiling; - // number of counters, increase as needed. 0 == disabled -#define GRAAL_COUNTERS_SIZE (0) -#define GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS (true) - -#if GRAAL_COUNTERS_SIZE > 0 - jlong _graal_counters[GRAAL_COUNTERS_SIZE]; - static jlong _graal_old_thread_counters[GRAAL_COUNTERS_SIZE]; -#endif // GRAAL_COUNTERS_SIZE > 0 + jlong* _graal_counters; public: + static jlong* _graal_old_thread_counters; static void collect_counters(typeArrayOop array); private: #endif // GRAAL @@ -1394,11 +1388,7 @@ #ifdef GRAAL static ByteSize graal_alternate_call_target_offset() { return byte_offset_of(JavaThread, _graal_alternate_call_target); } static ByteSize graal_implicit_exception_pc_offset() { return byte_offset_of(JavaThread, _graal_implicit_exception_pc); } -#if GRAAL_COUNTERS_SIZE > 0 static ByteSize graal_counters_offset() { return byte_offset_of(JavaThread, _graal_counters ); } -#else - static ByteSize graal_counters_offset() { return in_ByteSize(0); } -#endif // GRAAL_COUNTERS_SIZE > 0 #endif // GRAAL static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop ); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); } diff -r d0e82d536325 -r a124cc76cde9 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Sun Feb 23 17:00:35 2014 -0800 +++ b/src/share/vm/runtime/vmStructs.cpp Wed Mar 05 19:40:15 2014 -0800 @@ -568,8 +568,6 @@ nonstatic_field(Space, _bottom, HeapWord*) \ nonstatic_field(Space, _end, HeapWord*) \ \ - static_field(HeapRegion, LogOfHRGrainBytes, int) \ - \ nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ @@ -813,6 +811,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 */ \ @@ -1505,8 +1531,6 @@ declare_type(EdenSpace, ContiguousSpace) \ declare_type(OffsetTableContigSpace, ContiguousSpace) \ declare_type(TenuredSpace, OffsetTableContigSpace) \ - declare_type(G1OffsetTableContigSpace, ContiguousSpace) \ - declare_type(HeapRegion, G1OffsetTableContigSpace) \ declare_toplevel_type(BarrierSet) \ declare_type(ModRefBarrierSet, BarrierSet) \ declare_type(CardTableModRefBS, ModRefBarrierSet) \ @@ -2312,6 +2336,9 @@ declare_constant(JVM_ACC_PROMOTED_FLAGS) \ declare_constant(JVM_ACC_FIELD_ACCESS_WATCHED) \ declare_constant(JVM_ACC_FIELD_MODIFICATION_WATCHED) \ + declare_constant(JVM_ACC_FIELD_INTERNAL) \ + declare_constant(JVM_ACC_FIELD_STABLE) \ + declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ \ declare_constant(JVM_CONSTANT_Utf8) \ declare_constant(JVM_CONSTANT_Unicode) \ @@ -2467,13 +2494,14 @@ \ declare_constant(Symbol::max_symbol_length) \ \ - /*************************************************/ \ - /* ConstantPool* layout enum for InvokeDynamic */ \ - /*************************************************/ \ + /***********************************************/ \ + /* ConstantPool* layout enum for InvokeDynamic */ \ + /***********************************************/ \ \ - declare_constant(ConstantPool::_indy_bsm_offset) \ - declare_constant(ConstantPool::_indy_argc_offset) \ - declare_constant(ConstantPool::_indy_argv_offset) \ + declare_constant(ConstantPool::_indy_bsm_offset) \ + declare_constant(ConstantPool::_indy_argc_offset) \ + declare_constant(ConstantPool::_indy_argv_offset) \ + declare_constant(ConstantPool::CPCACHE_INDEX_TAG) \ \ /********************************/ \ /* ConstantPoolCacheEntry enums */ \ @@ -3060,7 +3088,8 @@ GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) #ifdef GRAAL - VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY) + VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) #endif #if INCLUDE_ALL_GCS