# HG changeset patch # User Doug Simon # Date 1408716229 -7200 # Node ID 433ece7d941d5bb110fd7147caa5a5ee5efd9349 # Parent f90dcdbbb75e37b1e9f182a5d85927888b81bc5d# Parent f3bc50fe51573e0799c30b79b7652cd3e3faa79e Merge. diff -r f90dcdbbb75e -r 433ece7d941d .hgtags --- a/.hgtags Fri Aug 22 15:56:51 2014 +0200 +++ b/.hgtags Fri Aug 22 16:03:49 2014 +0200 @@ -406,3 +406,4 @@ b124e22eb772806c13d942cc110de38da0108147 graal-0.1 483d05bf77a7c2a762aca1e06c4191bc06647176 graal-0.2 9535eccd2a115f6c6f0b15efb508b11ff74cc0d3 graal-0.3 +7d4f630172a16e983212d46c0f1ad6cdb826dfce graal-0.4 diff -r f90dcdbbb75e -r 433ece7d941d CHANGELOG.md --- a/CHANGELOG.md Fri Aug 22 15:56:51 2014 +0200 +++ b/CHANGELOG.md Fri Aug 22 16:03:49 2014 +0200 @@ -2,28 +2,35 @@ ## `tip` ### Graal +* ... + +### Truffle +* ... + +## Version 0.4 +19-Aug-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.4) +### Graal * Made initialization of Graal runtime lazy in hosted mode. -* Added supported for new 'jrelibrary' dependency type in mx/projects. -* Java projects with compliance level higher than the JDKs specified by JAVA_HOME and EXTRA_JAVA_HOMES are ignored once mx/projects has been processed. -* ResolvedJavaType.resolveMethod now takes a context type used to perform access checks. It now works correctly regarding default methods. -* Removed Java based compilation queue (CompilationQueue.java). -* Enabled use of separate class loader (via -XX:+UseGraalClassLoader) for classes loaded from graal.jar to hide them from application classes. +* Added supported for new `jrelibrary` dependency type in `mx/projects`. +* Java projects with compliance level higher than the JDKs specified by `JAVA_HOME` and `EXTRA_JAVA_HOMES` are ignored once `mx/projects` has been processed. +* `ResolvedJavaType.resolveMethod` now takes a context type used to perform access checks. It now works correctly regarding default methods. +* Removed Java based compilation queue (`CompilationQueue.java`). +* Enabled use of separate class loader (via `-XX:+UseGraalClassLoader`) for classes loaded from `graal.jar` to hide them from application classes. ### Truffle * Change API for stack walking to a visitor: `TruffleRuntime#iterateFrames` replaces `TruffleRuntime#getStackTrace` -* New flag -G:+TraceTruffleCompilationCallTree to print the tree of inlined calls before compilation. +* New flag `-G:+TraceTruffleCompilationCallTree` to print the tree of inlined calls before compilation. * `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`) -* New flag -G:+TraceTruffleCompilationAST to print the AST before compilation. -* New experimental TypedObject interface added. -* Renamed flag -G:+TruffleSplittingEnabled to -G:+TruffleSplitting -* New flag -G:+TruffleSplittingNew to enable the experimental splitting mode based on function arguments. -* New flag -G:+TruffleSplittingTypedInstanceStamps to enable splitting for TypedObject instances. -* New flag -G:+TruffleSplittingClassInstanceStamps to enable splitting for Java object instances except TypedObject. -* New flag -G:TruffleSplittingStartCallCount=3 which sets the number of minimal calls until splitting is performed. -* New flag -G:-TruffleSplittingAggressive if enabled splits every function call. -* Added isVisited method for BranchProfile. -* Added new ConditionProfile, BooleanConditionProfile and IntegerConditionProfile utility classes to profile if conditions. -* ... +* New flag `-G:+TraceTruffleCompilationAST` to print the AST before compilation. +* New experimental `TypedObject` interface added. +* Renamed flag `-G:+TruffleSplittingEnabled` to `-G:+TruffleSplitting` +* New flag `-G:+TruffleSplittingNew` to enable the experimental splitting mode based on function arguments. +* New flag `-G:+TruffleSplittingTypedInstanceStamps` to enable splitting for `TypedObject` instances. +* New flag `-G:+TruffleSplittingClassInstanceStamps` to enable splitting for Java object instances except `TypedObject`. +* New flag `-G:TruffleSplittingStartCallCount=3` which sets the number of minimal calls until splitting is performed. +* New flag `-G:-TruffleSplittingAggressive` if enabled splits every function call. +* Added `isVisited` method for `BranchProfile`. +* Added new `ConditionProfile`, `BinaryConditionProfile` and `CountingConditionProfile` utility classes to profile if conditions. ## Version 0.3 9-May-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.3) diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Fri Aug 22 16:03:49 2014 +0200 @@ -161,6 +161,9 @@ * because of Word type rewriting and alternative backends that can't be done. */ public boolean validateFormat() { + if (caller() != null) { + caller().validateFormat(); + } for (int i = 0; i < numLocals + numStack; i++) { if (values[i] != null) { Kind kind = values[i].getKind(); diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Fri Aug 22 16:03:49 2014 +0200 @@ -88,12 +88,30 @@ */ public abstract void mov(Register a, Constant src); + private static String getBitTypeFromKind(Kind kind) { + switch (kind) { + case Boolean: + case Byte: + case Short: + case Char: + case Int: + case Float: + return "b32"; + case Long: + case Double: + case Object: + return "b64"; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + public final void emitMov(Kind kind, Value dst, Value src) { if (isRegister(dst) && isConstant(src) && kind.getStackKind() == Kind.Object) { mov(asRegister(dst), asConstant(src)); } else { - String argtype = getArgTypeFromKind(kind).substring(1); - emitString("mov_b" + argtype + " " + mapRegOrConstToString(dst) + ", " + mapRegOrConstToString(src) + ";"); + String argtype = getBitTypeFromKind(kind); + emitString("mov_" + argtype + " " + mapRegOrConstToString(dst) + ", " + mapRegOrConstToString(src) + ";"); } } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -400,20 +400,7 @@ return; } - double probability = profilingInfo.getBranchTakenProbability(bci()); - if (probability < 0) { - assert probability == -1 : "invalid probability"; - Debug.log("missing probability in %s at bci %d", method, bci()); - probability = 0.5; - } - - if (!optimisticOpts.removeNeverExecutedCode()) { - if (probability == 0) { - probability = 0.0000001; - } else if (probability == 1) { - probability = 0.999999; - } - } + double probability = branchProbability(); LabelRef trueDestination = getSuccessor(0); LabelRef falseDestination = getSuccessor(1); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/MoreThanEightArgsTest.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/lambda/MoreThanEightArgsTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,95 @@ +/* + * 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.hsail.test.lambda; + +import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; + +import org.junit.*; + +public class MoreThanEightArgsTest extends GraalKernelTester { + + int[] makeIntArray(int size) { + int[] out = new int[size]; + + for (int i = 0; i < size; i++) { + out[i] = 1; + } + return out; + } + + final int rows = 4096; + final int cols = 4096; + final int loops = 2; + + @Result int[] result; + + void innerTest(int[] res, int[] a, int[] b, int[] c, int[] d, int base, int stride) { + final int resCols = a.length; + final int resRows = res.length; + final int limit = resCols - stride; + + dispatchLambdaKernel(resRows, (row) -> { + res[row] = 0; + if (a != null) { + for (int col = base; col < limit; col += 4) { + int p0 = 0; + int p1 = 0; + int p2 = 0; + int p3 = 0; + p0 = a[col] + b[col] + c[col] + d[col] + stride; + p1 = a[col + 1] + b[col + 1] + c[col + 1] + d[col + 1]; + p2 = a[col + 2] + b[col + 2] + c[col + 2] + d[col + 2]; + p3 = a[col + 3] + b[col + 3] + c[col + 3] + d[col + 3]; + res[row] += p0 + p1 + p2 + p3; + } + } + }); + } + + @Override + public void runTest() { + int[] a; + int[] b; + int[] c; + int[] d; + + result = makeIntArray(rows); + a = makeIntArray(cols); + b = makeIntArray(cols); + c = makeIntArray(cols); + d = makeIntArray(cols); + for (int i = 0; i < loops; i++) { + innerTest(result, a, b, c, d, 0, 4); + } + } + + @Test + public void test() { + testGeneratedHsail(); + } + + @Test + public void testUsingLambdaMethod() { + testGeneratedHsailUsingLambdaMethod(); + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/GenGraalRuntimeInlineHpp.java --- a/graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/GenGraalRuntimeInlineHpp.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.hotspot.sourcegen/src/com/oracle/graal/hotspot/sourcegen/GenGraalRuntimeInlineHpp.java Fri Aug 22 16:03:49 2014 +0200 @@ -146,7 +146,8 @@ } /** - * Generates code for {@code GraalRuntime::set_option()}. + * Generates code for {@code GraalRuntime::set_option()} and + * {@code GraalRuntime::set_option_bool()}. */ private static void genSetOption(PrintStream out) throws Exception { SortedMap options = getOptions(); @@ -157,21 +158,20 @@ } lengths.add("PrintFlags".length()); - out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, char* name, int name_len, const char* value, TRAPS) {"); + out.println("bool GraalRuntime::set_option_bool(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, char value, TRAPS) {"); out.println(" bool check_only = hotSpotOptionsClass.is_null();"); - out.println(" if (value != NULL && (value[0] == '+' || value[0] == '-')) {"); - out.println(" // boolean options"); genMatchers(out, lengths, options, true); - out.println(" } else {"); - out.println(" // non-boolean options"); + out.println(" return false;"); + out.println("}"); + out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, const char* value, TRAPS) {"); + out.println(" bool check_only = hotSpotOptionsClass.is_null();"); genMatchers(out, lengths, options, false); - out.println(" }"); out.println(" return false;"); out.println("}"); } protected static void genMatchers(PrintStream out, Set lengths, SortedMap options, boolean isBoolean) throws Exception { - out.println(" switch (name_len) {"); + out.println(" switch (name_len) {"); for (int len : lengths) { boolean printedCase = false; @@ -179,56 +179,56 @@ // null terminated for = style options. if (len == "PrintFlags".length() && isBoolean) { printedCase = true; - out.println(" case " + len + ":"); - out.printf(" if (strncmp(name, \"PrintFlags\", %d) == 0) {%n", len); - out.println(" if (value[0] == '+') {"); - out.println(" if (check_only) {"); - out.println(" TempNewSymbol name = SymbolTable::new_symbol(\"Lcom/oracle/graal/hotspot/HotSpotOptions;\", CHECK_(true));"); - out.println(" hotSpotOptionsClass = SystemDictionary::resolve_or_fail(name, true, CHECK_(true));"); - out.println(" }"); - out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), '?', Handle(), 0L);"); + out.println(" case " + len + ":"); + out.printf(" if (strncmp(name, \"PrintFlags\", %d) == 0) {%n", len); + out.println(" if (value == '+') {"); + out.println(" if (check_only) {"); + out.println(" TempNewSymbol name = SymbolTable::new_symbol(\"Lcom/oracle/graal/hotspot/HotSpotOptions;\", CHECK_(true));"); + out.println(" hotSpotOptionsClass = SystemDictionary::resolve_or_fail(name, true, CHECK_(true));"); out.println(" }"); - out.println(" return true;"); + out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), '?', Handle(), 0L);"); out.println(" }"); + out.println(" return true;"); + out.println(" }"); } for (Map.Entry e : options.entrySet()) { OptionDescriptor desc = e.getValue(); if (e.getKey().length() == len && ((desc.getType() == Boolean.class) == isBoolean)) { if (!printedCase) { printedCase = true; - out.println(" case " + len + ":"); + out.println(" case " + len + ":"); } - out.printf(" if (strncmp(name, \"%s\", %d) == 0) {%n", e.getKey(), len); + out.printf(" if (strncmp(name, \"%s\", %d) == 0) {%n", e.getKey(), len); Class declaringClass = desc.getDeclaringClass(); if (isBoolean) { - out.printf(" Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(), + out.printf(" Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(), + toInternalName(getFieldType(desc))); + out.println(" if (!check_only) {"); + out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, option, value, Handle(), 0L);"); + out.println(" }"); + } else if (desc.getType() == String.class) { + out.println(" check_required_value(name, name_len, value, CHECK_(true));"); + out.printf(" Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(), toInternalName(getFieldType(desc))); - out.println(" if (!check_only) {"); - out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, option, value[0], Handle(), 0L);"); - out.println(" }"); - } else if (desc.getType() == String.class) { - out.println(" check_required_value(name, name_len, value, CHECK_(true));"); + out.println(" if (!check_only) {"); + out.println(" Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));"); + out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, option, 's', stringValue, 0L);"); + out.println(" }"); + } else { + char spec = getPrimitiveSpecChar(desc); + out.println(" jlong primitiveValue = parse_primitive_option_value('" + spec + "', name, name_len, value, CHECK_(true));"); + out.println(" if (!check_only) {"); out.printf(" Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(), toInternalName(getFieldType(desc))); - out.println(" if (!check_only) {"); - out.println(" Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));"); - out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, option, 's', stringValue, 0L);"); - out.println(" }"); - } else { - char spec = getPrimitiveSpecChar(desc); - out.println(" jlong primitiveValue = parse_primitive_option_value('" + spec + "', name, name_len, value, CHECK_(true));"); - out.println(" if (!check_only) {"); - out.printf(" Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));%n", toInternalName(declaringClass), desc.getFieldName(), - toInternalName(getFieldType(desc))); - out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, option, '" + spec + "', Handle(), primitiveValue);"); - out.println(" }"); + out.println(" set_option_helper(hotSpotOptionsClass, name, name_len, option, '" + spec + "', Handle(), primitiveValue);"); + out.println(" }"); } - out.println(" return true;"); - out.println(" }"); + out.println(" return true;"); + out.println(" }"); } } } - out.println(" }"); + out.println(" }"); } @SuppressWarnings("unchecked") diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Fri Aug 22 16:03:49 2014 +0200 @@ -42,7 +42,6 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.options.*; import com.oracle.graal.options.OptionValue.OverrideScope; -import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; /** @@ -237,79 +236,81 @@ private void compile(String fileList) throws Throwable { final String[] entries = fileList.split(File.pathSeparator); - for (int i = 0; i < entries.length; i++) { - final String entry = entries[i]; - - // For now we only compile all methods in all classes in zip/jar files. - if (!entry.endsWith(".zip") && !entry.endsWith(".jar")) { - println("CompileTheWorld : Skipped classes in " + entry); - println(); - continue; - } + try (AutoCloseable s = config.apply()) { + for (int i = 0; i < entries.length; i++) { + final String entry = entries[i]; - println("CompileTheWorld : Compiling all classes in " + entry); - println(); - - URL url = new URL("jar", "", "file:" + entry + "!/"); - ClassLoader loader = new URLClassLoader(new URL[]{url}); - - JarFile jarFile = new JarFile(entry); - Enumeration e = jarFile.entries(); - - while (e.hasMoreElements()) { - JarEntry je = e.nextElement(); - if (je.isDirectory() || !je.getName().endsWith(".class")) { + // For now we only compile all methods in all classes in zip/jar files. + if (!entry.endsWith(".zip") && !entry.endsWith(".jar")) { + println("CompileTheWorld : Skipped classes in " + entry); + println(); continue; } - // Are we done? - if (classFileCounter >= stopAt) { - break; - } + println("CompileTheWorld : Compiling all classes in " + entry); + println(); - String className = je.getName().substring(0, je.getName().length() - ".class".length()); - classFileCounter++; + URL url = new URL("jar", "", "file:" + entry + "!/"); + ClassLoader loader = new URLClassLoader(new URL[]{url}); + + JarFile jarFile = new JarFile(entry); + Enumeration e = jarFile.entries(); - try (AutoCloseable s = config.apply()) { - // Load and initialize class - Class javaClass = Class.forName(className.replace('/', '.'), true, loader); + while (e.hasMoreElements()) { + JarEntry je = e.nextElement(); + if (je.isDirectory() || !je.getName().endsWith(".class")) { + continue; + } - // Pre-load all classes in the constant pool. - try { - HotSpotResolvedObjectType objectType = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(javaClass); - ConstantPool constantPool = objectType.constantPool(); - for (int cpi = 1; cpi < constantPool.length(); cpi++) { - constantPool.loadReferencedType(cpi, Bytecodes.LDC); - } - } catch (Throwable t) { - // If something went wrong during pre-loading we just ignore it. - println("Preloading failed for (%d) %s", classFileCounter, className); + // Are we done? + if (classFileCounter >= stopAt) { + break; } - // Are we compiling this class? - HotSpotMetaAccessProvider metaAccess = runtime.getHostProviders().getMetaAccess(); - if (classFileCounter >= startAt) { - println("CompileTheWorld (%d) : %s", classFileCounter, className); + String className = je.getName().substring(0, je.getName().length() - ".class".length()); + classFileCounter++; + + try { + // Load and initialize class + Class javaClass = Class.forName(className.replace('/', '.'), true, loader); - // Compile each constructor/method in the class. - for (Constructor constructor : javaClass.getDeclaredConstructors()) { - HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaConstructor(constructor); - if (canBeCompiled(javaMethod, constructor.getModifiers())) { - compileMethod(javaMethod); + // Pre-load all classes in the constant pool. + try { + HotSpotResolvedObjectType objectType = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(javaClass); + ConstantPool constantPool = objectType.constantPool(); + for (int cpi = 1; cpi < constantPool.length(); cpi++) { + constantPool.loadReferencedType(cpi, Bytecodes.LDC); + } + } catch (Throwable t) { + // If something went wrong during pre-loading we just ignore it. + println("Preloading failed for (%d) %s", classFileCounter, className); + } + + // Are we compiling this class? + HotSpotMetaAccessProvider metaAccess = runtime.getHostProviders().getMetaAccess(); + if (classFileCounter >= startAt) { + println("CompileTheWorld (%d) : %s", classFileCounter, className); + + // Compile each constructor/method in the class. + for (Constructor constructor : javaClass.getDeclaredConstructors()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaConstructor(constructor); + if (canBeCompiled(javaMethod, constructor.getModifiers())) { + compileMethod(javaMethod); + } + } + for (Method method : javaClass.getDeclaredMethods()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method); + if (canBeCompiled(javaMethod, method.getModifiers())) { + compileMethod(javaMethod); + } } } - for (Method method : javaClass.getDeclaredMethods()) { - HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method); - if (canBeCompiled(javaMethod, method.getModifiers())) { - compileMethod(javaMethod); - } - } + } catch (Throwable t) { + println("CompileTheWorld (%d) : Skipping %s", classFileCounter, className); } - } catch (Throwable t) { - println("CompileTheWorld (%d) : Skipping %s", classFileCounter, className); } + jarFile.close(); } - jarFile.close(); } println(); @@ -323,16 +324,6 @@ } /** - * Returns a fresh compilation suite for its compilation so that the CTW option value - * overriding configuration has effect. - */ - @Override - protected Suites getSuites(HotSpotProviders providers) { - assert config.scope != null : "not inside a CTW option value overriding scope"; - return providers.getSuites().createSuites(); - } - - /** * Returns empty profiling info to be as close to the CTW behavior of C1 and C2 as possible. */ @Override diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Fri Aug 22 16:03:49 2014 +0200 @@ -159,8 +159,8 @@ linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); - linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS); - linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); linkForeignCall(providers, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, LEAF_NOFP, NOT_REEXECUTABLE, NO_LOCATIONS); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Fri Aug 22 16:03:49 2014 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.java.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; @@ -35,18 +36,18 @@ */ public class HotSpotSuitesProvider implements SuitesProvider { - protected final Suites defaultSuites; + protected final DerivedOptionValue defaultSuites; protected final PhaseSuite defaultGraphBuilderSuite; protected final HotSpotGraalRuntime runtime; public HotSpotSuitesProvider(HotSpotGraalRuntime runtime) { this.runtime = runtime; this.defaultGraphBuilderSuite = createGraphBuilderSuite(); - defaultSuites = createSuites(); + this.defaultSuites = new DerivedOptionValue<>(this::createSuites); } public Suites getDefaultSuites() { - return defaultSuites; + return defaultSuites.getValue(); } public PhaseSuite getDefaultGraphBuilderSuite() { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java Fri Aug 22 16:03:49 2014 +0200 @@ -88,7 +88,7 @@ @Override public HotSpotNativeFunctionHandle getFunctionHandle(NativeLibraryHandle library, String name, Class returnType, Class... argumentTypes) { - HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, library, true); + HotSpotNativeFunctionPointer functionPointer = lookupFunctionPointer(name, library, false); return createHandle(functionPointer, returnType, argumentTypes); } @@ -179,7 +179,7 @@ if (rtldDefault == null) { throw new UnsatisfiedLinkError(name); } - return lookupFunctionPointer(name, rtldDefault, true); + return lookupFunctionPointer(name, rtldDefault, false); } public boolean isDefaultLibrarySearchSupported() { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -896,6 +896,28 @@ return probability == 0 && optimisticOpts.removeNeverExecutedCode() && entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI; } + protected double branchProbability() { + double probability = profilingInfo.getBranchTakenProbability(bci()); + if (probability < 0) { + assert probability == -1 : "invalid probability"; + Debug.log("missing probability in %s at bci %d", method, bci()); + probability = 0.5; + } + + if (!removeNeverExecutedCode()) { + if (probability == 0) { + probability = 0.0000001; + } else if (probability == 1) { + probability = 0.999999; + } + } + return probability; + } + + protected boolean removeNeverExecutedCode() { + return optimisticOpts.removeNeverExecutedCode() && entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI; + } + protected abstract void processBlock(BciBlock block); protected abstract void iterateBytecodesForBlock(BciBlock block); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java Fri Aug 22 16:03:49 2014 +0200 @@ -22,21 +22,22 @@ */ package com.oracle.graal.java; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; public class DefaultSuitesProvider implements SuitesProvider { - private final Suites defaultSuites; + private final DerivedOptionValue defaultSuites; private final PhaseSuite defaultGraphBuilderSuite; public DefaultSuitesProvider() { this.defaultGraphBuilderSuite = createGraphBuilderSuite(); - this.defaultSuites = createSuites(); + this.defaultSuites = new DerivedOptionValue<>(this::createSuites); } public Suites getDefaultSuites() { - return defaultSuites; + return defaultSuites.getValue(); } public Suites createSuites() { diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Aug 22 16:03:49 2014 +0200 @@ -1401,20 +1401,7 @@ return; } - double probability = profilingInfo.getBranchTakenProbability(bci()); - if (probability < 0) { - assert probability == -1 : "invalid probability"; - Debug.log("missing probability in %s at bci %d", method, bci()); - probability = 0.5; - } - - if (!optimisticOpts.removeNeverExecutedCode()) { - if (probability == 0) { - probability = 0.0000001; - } else if (probability == 1) { - probability = 0.999999; - } - } + double probability = branchProbability(); // the mirroring and negation operations get the condition into canonical form boolean mirror = cond.canonicalMirror(); diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Fri Aug 22 16:03:49 2014 +0200 @@ -926,16 +926,16 @@ break; case B2I: - masm.movsbl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); + masm.movsbl(asIntReg(dst), (AMD64Address) crb.asByteAddr(src)); break; case S2I: - masm.movswl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src)); + masm.movswl(asIntReg(dst), (AMD64Address) crb.asShortAddr(src)); break; case B2L: - masm.movsbq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src)); + masm.movsbq(asLongReg(dst), (AMD64Address) crb.asByteAddr(src)); break; case S2L: - masm.movswq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src)); + masm.movswq(asLongReg(dst), (AMD64Address) crb.asShortAddr(src)); break; case I2L: masm.movslq(asLongReg(dst), (AMD64Address) crb.asIntAddr(src)); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.options/src/com/oracle/graal/options/DerivedOptionValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/DerivedOptionValue.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,55 @@ +/* + * 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.options; + +import java.util.function.*; + +import com.oracle.graal.options.OptionValue.OverrideScope; + +/** + * A cached value that needs to be recomputed when an option changes. + */ +public class DerivedOptionValue { + + private final T initialValue; + private final Supplier supplier; + + public DerivedOptionValue(Supplier supplier) { + this.supplier = supplier; + assert OptionValue.overrideScopes.get() == null : "derived option value should be initialized outside any override scope"; + this.initialValue = createValue(); + } + + public T getValue() { + OverrideScope overrideScope = OptionValue.overrideScopes.get(); + if (overrideScope != null) { + return overrideScope.getDerived(this); + } else { + return initialValue; + } + } + + T createValue() { + return supplier.get(); + } +} diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Fri Aug 22 16:03:49 2014 +0200 @@ -128,7 +128,7 @@ return new MultipleOverridesScope(current, map); } - private static final ThreadLocal overrideScopes = new ThreadLocal<>(); + static final ThreadLocal overrideScopes = new ThreadLocal<>(); /** * The raw option value. @@ -252,6 +252,22 @@ * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}. */ public abstract static class OverrideScope implements AutoCloseable { + + private Map, Object> derivedCache = null; + + public T getDerived(DerivedOptionValue key) { + if (derivedCache == null) { + derivedCache = new HashMap<>(); + } + @SuppressWarnings("unchecked") + T ret = (T) derivedCache.get(key); + if (ret == null) { + ret = key.createValue(); + derivedCache.put(key, ret); + } + return ret; + } + abstract void addToInherited(Map, Object> inherited); abstract T getOverride(OptionValue option); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java Fri Aug 22 16:03:49 2014 +0200 @@ -83,26 +83,19 @@ } } - if (CompilerConfiguration.getValue().equals("")) { - if (nonBasicCount == 1) { - /* - * There is exactly one non-basic configuration. We use this one as default. - */ - defaultConfiguration = nonBasic; - } else { - /* - * There is either no extended configuration available, or more than one. In that - * case, default to "basic". - */ - defaultConfiguration = basic; - if (defaultConfiguration == null) { - throw new GraalInternalError("unable to find basic compiler configuration"); - } - } + if (nonBasicCount == 1) { + /* + * There is exactly one non-basic configuration. We use this one as default. + */ + defaultConfiguration = nonBasic; } else { - defaultConfiguration = configurations.get(CompilerConfiguration.getValue()); + /* + * There is either no extended configuration available, or more than one. In that case, + * default to "basic". + */ + defaultConfiguration = basic; if (defaultConfiguration == null) { - throw new GraalInternalError("unknown compiler configuration: " + CompilerConfiguration.getValue()); + throw new GraalInternalError("unable to find basic compiler configuration"); } } } @@ -120,7 +113,12 @@ } public static Suites createDefaultSuites() { - return new Suites(defaultConfiguration); + String selected = CompilerConfiguration.getValue(); + if (selected.equals("")) { + return new Suites(defaultConfiguration); + } else { + return createSuites(selected); + } } public static Suites createSuites(String name) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java --- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/AbstractVerifier.java Fri Aug 22 16:03:49 2014 +0200 @@ -44,7 +44,7 @@ @SuppressWarnings("unchecked") protected static T resolveAnnotationValue(Class expectedType, AnnotationValue value) { if (value == null) { - throw new NullPointerException("Value must not be null."); + return null; } Object unboxedValue = value.getValue(); if (unboxedValue != null) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Fri Aug 22 16:03:49 2014 +0200 @@ -275,9 +275,17 @@ protected ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) { boolean compressible = load.accessKind() == Kind.Object; Kind readKind = load.accessKind(); - LocationNode location = createLocation(load); + ValueNode[] base = null; + ValueNode object = load.object(); + if (object.isConstant() && object.asConstant().isDefaultForKind()) { + base = new ValueNode[1]; + } + LocationNode location = createLocation(load, base); + if (base != null && base[0] != null) { + object = base[0]; + } Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible); - ReadNode memoryRead = graph.add(ReadNode.create(load.object(), location, loadStamp, guard, BarrierType.NONE)); + ReadNode memoryRead = graph.add(ReadNode.create(object, location, loadStamp, guard, BarrierType.NONE)); ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible); load.replaceAtUsages(readValue); return memoryRead; @@ -285,8 +293,15 @@ protected void lowerUnsafeStoreNode(UnsafeStoreNode store) { StructuredGraph graph = store.graph(); - LocationNode location = createLocation(store); ValueNode object = store.object(); + ValueNode[] base = null; + if (object.isConstant() && object.asConstant().isDefaultForKind()) { + base = new ValueNode[1]; + } + LocationNode location = createLocation(store, base); + if (base != null && base[0] != null) { + object = base[0]; + } boolean compressible = store.value().getKind() == Kind.Object; Kind valueKind = store.accessKind(); ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible); @@ -566,11 +581,26 @@ } } - protected LocationNode createLocation(UnsafeAccessNode access) { - return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind()); + protected LocationNode createLocation(UnsafeAccessNode access, ValueNode[] base) { + return createLocation(access.offset(), access.getLocationIdentity(), access.accessKind(), base); } protected LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind) { + return createLocation(offsetNode, locationIdentity, accessKind, null); + } + + /** + * Try to unpack the operations in offsetNode into a LocationNode, taking advantage of + * addressing modes if possible. + * + * @param offsetNode the computed offset into the base of the memory operation + * @param locationIdentity + * @param accessKind + * @param base if non-null try to find a value that can be used as the base of the memory + * operation and return it as base[0] + * @return the newly created LocationNode + */ + protected LocationNode createLocation(ValueNode offsetNode, LocationIdentity locationIdentity, Kind accessKind, ValueNode[] base) { ValueNode offset = offsetNode; if (offset.isConstant()) { long offsetValue = offset.asConstant().asLong(); @@ -594,7 +624,27 @@ offset = integerAddNode.getX(); } } - + if (base != null && signExtend == false && offset instanceof IntegerAddNode) { + /* + * Try to decompose the operation into base plus offset so the base can go into a new + * node. Prefer the unshifted side of an add as the base. + */ + IntegerAddNode integerAddNode = (IntegerAddNode) offset; + if (integerAddNode.getY() instanceof LeftShiftNode) { + base[0] = integerAddNode.getX(); + offset = integerAddNode.getY(); + } else { + base[0] = integerAddNode.getY(); + offset = integerAddNode.getX(); + } + if (offset instanceof IntegerAddNode) { + integerAddNode = (IntegerAddNode) offset; + if (integerAddNode.getY() instanceof ConstantNode) { + displacement = integerAddNode.getY().asConstant().asLong(); + offset = integerAddNode.getX(); + } + } + } if (offset instanceof LeftShiftNode) { LeftShiftNode leftShiftNode = (LeftShiftNode) offset; if (leftShiftNode.getY() instanceof ConstantNode) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Fri Aug 22 16:03:49 2014 +0200 @@ -231,7 +231,7 @@ MetaAccessProvider metaAccess = providers.getMetaAccess(); SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites(); Suites suites = suitesProvider.createSuites(); - suites.getHighTier().findPhase(InliningPhase.class).remove(); + removeInliningPhase(suites); StructuredGraph graph = new StructuredGraph(javaMethod); new GraphBuilderPhase.Instance(metaAccess, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); PhaseSuite graphBuilderSuite = suitesProvider.getDefaultGraphBuilderSuite(); @@ -247,6 +247,13 @@ return runtimeProvider.getHostBackend().getProviders(); } + private static void removeInliningPhase(Suites suites) { + ListIterator> inliningPhase = suites.getHighTier().findPhase(InliningPhase.class); + if (inliningPhase != null) { + inliningPhase.remove(); + } + } + @SlowPath @Override public T iterateFrames(FrameInstanceVisitor visitor) { diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Fri Aug 22 16:03:49 2014 +0200 @@ -54,6 +54,7 @@ registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class); registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class); registerSubstitutions(OptimizedCallTarget.class, OptimizedCallTargetSubstitutions.class); + registerSubstitutions(FrameWithoutBoxing.class, FrameWithoutBoxingSubstitutions.class); } @Override diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java Fri Aug 22 16:03:49 2014 +0200 @@ -103,11 +103,16 @@ throw new RuntimeException("Frame field not found: " + fieldName); } + @NodeInfo public static class VirtualOnlyInstanceNode extends VirtualInstanceNode { private boolean allowMaterialization; - public VirtualOnlyInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields) { + public static VirtualOnlyInstanceNode create(ResolvedJavaType type, ResolvedJavaField[] fields) { + return new NewFrameNode_VirtualOnlyInstanceNodeGen(type, fields); + } + + VirtualOnlyInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields) { super(type, fields, false); } @@ -125,7 +130,7 @@ } public static ValueNode getMaterializedRepresentationHelper(VirtualObjectNode virtualNode, FixedNode fixed) { - if (fixed instanceof MaterializeFrameNode || fixed instanceof AbstractEndNode) { + if (fixed instanceof MaterializeFrameNode || fixed instanceof AbstractEndNode || fixed instanceof ForceMaterializeNode) { // We need to conservatively assume that a materialization of a virtual frame can also // happen at a merge point. return AllocatedObjectNode.create(virtualNode); @@ -161,7 +166,7 @@ ResolvedJavaField primitiveLocalsField = findField(frameFields, "primitiveLocals"); ResolvedJavaField tagsField = findField(frameFields, "tags"); - VirtualObjectNode virtualFrame = VirtualInstanceNode.create(frameType, frameFields, false); + VirtualObjectNode virtualFrame = VirtualOnlyInstanceNode.create(frameType, frameFields); VirtualObjectNode virtualFrameObjectArray = VirtualArrayNode.create((ResolvedJavaType) localsField.getType().getComponentType(), frameSize); VirtualObjectNode virtualFramePrimitiveArray = VirtualArrayNode.create((ResolvedJavaType) primitiveLocalsField.getType().getComponentType(), frameSize); VirtualObjectNode virtualFrameTagArray = VirtualArrayNode.create((ResolvedJavaType) tagsField.getType().getComponentType(), frameSize); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java Fri Aug 22 16:03:49 2014 +0200 @@ -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.truffle.substitutions; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.truffle.*; +import com.oracle.graal.truffle.nodes.frame.*; +import com.oracle.truffle.api.frame.*; + +@ClassSubstitution(FrameWithoutBoxing.class) +public class FrameWithoutBoxingSubstitutions { + + @MethodSubstitution(isStatic = false) + public static MaterializedFrame materialize(FrameWithoutBoxing frame) { + return MaterializeFrameNode.materialize(frame); + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java Fri Aug 22 16:03:49 2014 +0200 @@ -84,6 +84,32 @@ } } + /** + * CacheEntry describing an Unsafe memory reference. The memory location and the location + * identity are separate so both must be considered when looking for optimizable memory + * accesses. + * + */ + static class UnsafeLoadCacheEntry extends CacheEntry { + + private LocationIdentity locationIdentity; + + public UnsafeLoadCacheEntry(ValueNode object, ValueNode location, LocationIdentity locationIdentity) { + super(object, location); + this.locationIdentity = locationIdentity; + } + + @Override + public CacheEntry duplicateWithObject(ValueNode newObject) { + return new UnsafeLoadCacheEntry(newObject, identity, locationIdentity); + } + + @Override + public boolean conflicts(LocationIdentity other) { + return locationIdentity == other; + } + } + static class ReadCacheEntry extends CacheEntry { public ReadCacheEntry(ValueNode object, LocationNode identity) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Fri Aug 22 16:03:49 2014 +0200 @@ -37,6 +37,7 @@ import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry; import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry; import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.ReadCacheEntry; +import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.UnsafeLoadCacheEntry; public class ReadEliminationClosure extends EffectsClosure { @@ -121,7 +122,7 @@ UnsafeLoadNode load = (UnsafeLoadNode) node; if (load.offset().isConstant() && load.getLocationIdentity() != LocationIdentity.ANY_LOCATION) { ValueNode object = GraphUtil.unproxify(load.object()); - LoadCacheEntry identifier = new LoadCacheEntry(object, load.getLocationIdentity()); + UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, load.offset(), load.getLocationIdentity()); ValueNode cachedValue = state.getCacheEntry(identifier); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); @@ -136,7 +137,7 @@ UnsafeStoreNode write = (UnsafeStoreNode) node; if (write.offset().isConstant() && write.getLocationIdentity() != LocationIdentity.ANY_LOCATION) { ValueNode object = GraphUtil.unproxify(write.object()); - LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity()); + UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity()); ValueNode cachedValue = state.getCacheEntry(identifier); ValueNode value = getScalarAlias(write.value()); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -380,7 +380,7 @@ return true; } - @Specialization() + @Specialization Object f0() { return null; } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -46,25 +46,25 @@ @ImportGuards(Imports0.class) static class ImportGuards1 extends ValueNode { - @ExpectError("No compatible guard with method name 'nonStaticGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'nonStaticGuard' found.") @Specialization(guards = "nonStaticGuard") int f1(int a) { return a; } - @ExpectError("No compatible guard with method name 'protectedGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'protectedGuard' found.") @Specialization(guards = "protectedGuard") int f2(int a) { return a; } - @ExpectError("No compatible guard with method name 'packageGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'packageGuard' found.") @Specialization(guards = "packageGuard") int f3(int a) { return a; } - @ExpectError("No compatible guard with method name 'privateGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'privateGuard' found.") @Specialization(guards = "privateGuard") int f4(int a) { return a; diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -142,7 +142,7 @@ } @Specialization(guards = "baseGuard") - @ExpectError("No compatible guard with method name 'baseGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No guard with name 'baseGuard' matched the required signature.%") int doSpecialized(String value0) { return 42; } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsWithArgumentsTest.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/MethodGuardsWithArgumentsTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,265 @@ +/* + * 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 static com.oracle.truffle.api.dsl.test.TestHelper.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArguments0Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArguments1Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble0Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble1Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble2Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble3Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsSingle2Factory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +public class MethodGuardsWithArgumentsTest { + + @Test + public void testMArguments0() { + TestRootNode root = createRoot(MArguments0Factory.getInstance()); + Assert.assertEquals(42, executeWith(root)); + } + + abstract static class MArguments0 extends ValueNode { + + static boolean guard() { + return true; + } + + @Specialization(guards = "guard()") + int do1() { + return 42; + } + } + + @Test + public void testMArguments1() { + TestRootNode root = createRoot(MArguments1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root)); + } + + abstract static class MArguments1 extends ValueNode { + + static boolean guard() { + return true; + } + + @Specialization(guards = "guard ()") + int do1() { + return 42; + } + } + + @Test + public void testMArgumentsSingle0() { + TestRootNode root = createRoot(MArguments1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42)); + } + + @NodeChild("a") + abstract static class MArgumentsSingle0 extends ValueNode { + + static boolean guard() { + return true; + } + + @Specialization(guards = "guard()") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsSingle1() { + TestRootNode root = createRoot(MArguments1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42)); + } + + @NodeChild("a") + abstract static class MArgumentsSingle1 extends ValueNode { + + static boolean guard(int a) { + return a == 42; + } + + @Specialization(guards = "guard(a)") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsSingle2() { + TestRootNode root = createRoot(MArgumentsSingle2Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42)); + } + + @NodeChild("a") + abstract static class MArgumentsSingle2 extends ValueNode { + + static boolean guard(int a1, int a2) { + return a1 == 42 && a2 == 42; + } + + @Specialization(guards = "guard(a,a)") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsDouble0() { + TestRootNode root = createRoot(MArgumentsDouble0Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 0)); + } + + @NodeChild("a") + abstract static class MArgumentsDouble0 extends ValueNode { + + static boolean guard(int a1, Object a2) { + return a1 == 42 && a2.equals(new Integer(42)); + } + + @Specialization(guards = "guard(a,a)") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsDouble1() { + TestRootNode root = createRoot(MArgumentsDouble1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 41)); + } + + @NodeChildren({@NodeChild("a"), @NodeChild("b")}) + abstract static class MArgumentsDouble1 extends ValueNode { + + static boolean guard(int a1, double a2) { + return a1 == 42 && a2 == 41; + } + + @Specialization(guards = "guard(a,b)") + int do1(int a, @SuppressWarnings("unused") double b) { + return a; + } + } + + @Test + public void testMArgumentsDouble2() { + TestRootNode root = createRoot(MArgumentsDouble2Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 41.0)); + } + + @NodeChildren({@NodeChild("a"), @NodeChild("b")}) + abstract static class MArgumentsDouble2 extends ValueNode { + + static boolean guard(double a1, int a2) { + return a1 == 41 && a2 == 42; + } + + @Specialization(guards = "guard(b,a)") + int do1(int a, @SuppressWarnings("unused") double b) { + return a; + } + } + + @Test + public void testMArgumentsDouble3() { + TestRootNode root = createRoot(MArgumentsDouble3Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 41.0)); + } + + @NodeChildren({@NodeChild("a"), @NodeChild("b")}) + abstract static class MArgumentsDouble3 extends ValueNode { + + static boolean guard(Object a1, double a2) { + return new Double(41.0).equals(a1) && a2 == 41; + } + + @Specialization(guards = "guard(b,b)") + int do1(int a, @SuppressWarnings("unused") double b) { + return a; + } + } + + abstract static class MArgumentsError0 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("No compatible guard with method name 'guard(' found.%") + @Specialization(guards = "guard(") + int do1() { + return 42; + } + } + + abstract static class MArgumentsError1 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("No compatible guard with method name 'guard)' found.%") + @Specialization(guards = "guard)") + int do1() { + return 42; + } + + } + + abstract static class MArgumentsError2 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("Guard parameter 'a' for guard 'guard' could not be mapped to a declared child node.") + @Specialization(guards = "guard(a)") + int do1() { + return 42; + } + } + + @NodeChild("b") + abstract static class MArgumentsError3 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("Guard parameter 'a' for guard 'guard' could not be mapped to a declared child node.") + @Specialization(guards = "guard(a)") + int do1(int b) { + return b; + } + } + +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -50,7 +50,7 @@ throw new AssertionError(); } - @Specialization() + @Specialization int do2() { return 42; // the generic answer to all questions } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InstrumentationTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -188,7 +188,7 @@ public TestWrapper(RootNode child, ExecutionContext context) { this.child = insert(child); - this.probe = context.getProbe(child.getSourceSection()); + this.probe = context.createProbe(child.getSourceSection()); } public boolean isTaggedAs(SyntaxTag tag) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/BinaryConditionProfileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/BinaryConditionProfileTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,82 @@ +/* + * 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.truffle.api.test.utilities; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.*; +import org.junit.experimental.theories.*; +import org.junit.runner.*; + +import com.oracle.truffle.api.utilities.*; + +@RunWith(Theories.class) +public class BinaryConditionProfileTest { + + @DataPoints public static boolean[] data = new boolean[]{true, false}; + + @Test + public void testInitial() { + BinaryConditionProfile profile = ConditionProfile.createBinaryProfile(); + assertThat(profile.wasTrue(), is(false)); + assertThat(profile.wasFalse(), is(false)); + } + + @Theory + public void testProfileOne(boolean value) { + BinaryConditionProfile profile = ConditionProfile.createBinaryProfile(); + boolean result = profile.profile(value); + + assertThat(result, is(value)); + assertThat(profile.wasTrue(), is(value)); + assertThat(profile.wasFalse(), is(!value)); + } + + @Theory + public void testProfileTwo(boolean value0, boolean value1) { + BinaryConditionProfile profile = ConditionProfile.createBinaryProfile(); + boolean result0 = profile.profile(value0); + boolean result1 = profile.profile(value1); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + assertThat(profile.wasTrue(), is(value0 || value1)); + assertThat(profile.wasFalse(), is(!value0 || !value1)); + } + + @Theory + public void testProfileThree(boolean value0, boolean value1, boolean value2) { + BinaryConditionProfile profile = ConditionProfile.createBinaryProfile(); + boolean result0 = profile.profile(value0); + boolean result1 = profile.profile(value1); + boolean result2 = profile.profile(value2); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + assertThat(result2, is(value2)); + assertThat(profile.wasTrue(), is(value0 || value1 || value2)); + assertThat(profile.wasFalse(), is(!value0 || !value1 || !value2)); + } + +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/BooleanConditionProfileTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/BooleanConditionProfileTest.java Fri Aug 22 15:56:51 2014 +0200 +++ /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. - * 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.test.utilities; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - -import org.junit.*; -import org.junit.experimental.theories.*; -import org.junit.runner.*; - -import com.oracle.truffle.api.utilities.*; - -@RunWith(Theories.class) -public class BooleanConditionProfileTest { - - @DataPoints public static boolean[] data = new boolean[]{true, false}; - - @Test - public void testInitial() { - BooleanConditionProfile profile = new BooleanConditionProfile(); - assertThat(profile.wasTrue(), is(false)); - assertThat(profile.wasFalse(), is(false)); - } - - @Theory - public void testProfileOne(boolean value) { - BooleanConditionProfile profile = new BooleanConditionProfile(); - boolean result = profile.profile(value); - - assertThat(result, is(value)); - assertThat(profile.wasTrue(), is(value)); - assertThat(profile.wasFalse(), is(!value)); - } - - @Theory - public void testProfileTwo(boolean value0, boolean value1) { - BooleanConditionProfile profile = new BooleanConditionProfile(); - boolean result0 = profile.profile(value0); - boolean result1 = profile.profile(value1); - - assertThat(result0, is(value0)); - assertThat(result1, is(value1)); - assertThat(profile.wasTrue(), is(value0 || value1)); - assertThat(profile.wasFalse(), is(!value0 || !value1)); - } - - @Theory - public void testProfileThree(boolean value0, boolean value1, boolean value2) { - BooleanConditionProfile profile = new BooleanConditionProfile(); - boolean result0 = profile.profile(value0); - boolean result1 = profile.profile(value1); - boolean result2 = profile.profile(value2); - - assertThat(result0, is(value0)); - assertThat(result1, is(value1)); - assertThat(result2, is(value2)); - assertThat(profile.wasTrue(), is(value0 || value1 || value2)); - assertThat(profile.wasFalse(), is(!value0 || !value1 || !value2)); - } - -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/CountingConditionProfileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/CountingConditionProfileTest.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,82 @@ +/* + * 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.truffle.api.test.utilities; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.*; +import org.junit.experimental.theories.*; +import org.junit.runner.*; + +import com.oracle.truffle.api.utilities.*; + +@RunWith(Theories.class) +public class CountingConditionProfileTest { + + @DataPoints public static boolean[] data = new boolean[]{true, false}; + + @Test + public void testInitial() { + CountingConditionProfile profile = ConditionProfile.createCountingProfile(); + assertThat(profile.getTrueCount(), is(0)); + assertThat(profile.getFalseCount(), is(0)); + } + + @Theory + public void testProfileOne(boolean value) { + CountingConditionProfile profile = ConditionProfile.createCountingProfile(); + boolean result = profile.profile(value); + + assertThat(result, is(value)); + assertThat(profile.getTrueCount(), is(value ? 1 : 0)); + assertThat(profile.getFalseCount(), is(!value ? 1 : 0)); + } + + @Theory + public void testProfileTwo(boolean value0, boolean value1) { + CountingConditionProfile profile = ConditionProfile.createCountingProfile(); + boolean result0 = profile.profile(value0); + boolean result1 = profile.profile(value1); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0))); + assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0))); + } + + @Theory + public void testProfileThree(boolean value0, boolean value1, boolean value2) { + CountingConditionProfile profile = ConditionProfile.createCountingProfile(); + boolean result0 = profile.profile(value0); + boolean result1 = profile.profile(value1); + boolean result2 = profile.profile(value2); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + assertThat(result2, is(value2)); + assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0) + (value2 ? 1 : 0))); + assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0) + (!value2 ? 1 : 0))); + } + +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/IntegerConditionProfileTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/IntegerConditionProfileTest.java Fri Aug 22 15:56:51 2014 +0200 +++ /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. - * 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.test.utilities; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - -import org.junit.*; -import org.junit.experimental.theories.*; -import org.junit.runner.*; - -import com.oracle.truffle.api.utilities.*; - -@RunWith(Theories.class) -public class IntegerConditionProfileTest { - - @DataPoints public static boolean[] data = new boolean[]{true, false}; - - @Test - public void testInitial() { - IntegerConditionProfile profile = new IntegerConditionProfile(); - assertThat(profile.getTrueCount(), is(0)); - assertThat(profile.getFalseCount(), is(0)); - } - - @Theory - public void testProfileOne(boolean value) { - IntegerConditionProfile profile = new IntegerConditionProfile(); - boolean result = profile.profile(value); - - assertThat(result, is(value)); - assertThat(profile.getTrueCount(), is(value ? 1 : 0)); - assertThat(profile.getFalseCount(), is(!value ? 1 : 0)); - } - - @Theory - public void testProfileTwo(boolean value0, boolean value1) { - IntegerConditionProfile profile = new IntegerConditionProfile(); - boolean result0 = profile.profile(value0); - boolean result1 = profile.profile(value1); - - assertThat(result0, is(value0)); - assertThat(result1, is(value1)); - assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0))); - assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0))); - } - - @Theory - public void testProfileThree(boolean value0, boolean value1, boolean value2) { - IntegerConditionProfile profile = new IntegerConditionProfile(); - boolean result0 = profile.profile(value0); - boolean result1 = profile.profile(value1); - boolean result2 = profile.profile(value2); - - assertThat(result0, is(value0)); - assertThat(result1, is(value1)); - assertThat(result2, is(value2)); - assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0) + (value2 ? 1 : 0))); - assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0) + (!value2 ? 1 : 0))); - } - -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Assumption.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Assumption.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Assumption.java Fri Aug 22 16:03:49 2014 +0200 @@ -34,6 +34,9 @@ * method. The Truffle compiler has special knowledge of this class in order to produce efficient * machine code for checking an assumption in case the assumption object is a compile time constant. * Therefore, assumptions should be stored in final fields in Truffle nodes. + * + * All instances of classes implementing {@code Assumption} must be held in {@code final} fields for + * compiler optimizations to take effect. */ public interface Assumption { @@ -42,14 +45,14 @@ * longer the case. This method is preferred over the {@link #isValid()} method when writing * guest language interpreter code. The catch block should perform a node rewrite (see * {@link Node#replace(Node)}) with a node that no longer relies on the assumption. - * + * * @throws InvalidAssumptionException If the assumption is no longer valid. */ void check() throws InvalidAssumptionException; /** * Checks whether the assumption is still valid. - * + * * @return a boolean value indicating the validity of the assumption */ boolean isValid(); @@ -61,7 +64,7 @@ /** * A name for the assumption that is used for debug output. - * + * * @return the name of the assumption */ String getName(); diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java Fri Aug 22 16:03:49 2014 +0200 @@ -30,7 +30,7 @@ public interface CallTarget { /** - * Calls this target as a root method.. + * Calls this target as a root method. * * @param arguments passed arguments as an object array * @return the return result of the call diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Fri Aug 22 16:03:49 2014 +0200 @@ -45,6 +45,9 @@ protected ExecutionContext() { } + /** + * Sets up the {@link SourceCallback} for this execution context. + */ public void initialize() { setSourceCallback(new SourceCallback() { @@ -99,23 +102,13 @@ } /** - * Return the (possibly newly created) {@link Probe} uniquely associated with a particular - * source code location. A newly created probe carries no tags. + * Return a newly created, untagged, {@link Probe} associated with a particular source section, + * with no requirement that the association be unique. * - * @return a probe uniquely associated with an extent of guest language source code. + * @return a probe associated with an extent of guest language source code. */ - public final Probe getProbe(SourceSection sourceSection) { - return probeManager.getProbe(sourceSection); - } - - /** - * Has a {@link Probe} been created that is uniquely associated with a particular source code - * location. - * - * @return a probe uniquely associated with an extent of guest language source code. - */ - public final boolean hasProbe(SourceSection sourceSection) { - return probeManager.hasProbe(sourceSection); + public final Probe createProbe(SourceSection source) { + return probeManager.createProbe(source); } /** @@ -127,14 +120,6 @@ } /** - * Returns all existing probes with first character on a specified line; empty collection if no - * probes found. - */ - public final Collection findProbesByLine(LineLocation lineLocation) { - return probeManager.findProbesByLine(lineLocation); - } - - /** * Sets a trap that will make a callback at any AST location where a existing probe holds a * specified tag; only one trap may be set at a time. * diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTNodeProber.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTNodeProber.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTNodeProber.java Fri Aug 22 16:03:49 2014 +0200 @@ -27,11 +27,10 @@ import com.oracle.truffle.api.nodes.*; /** - * Implementation of a policy for instrumenting inserting a {@link Probe} at a Truffle AST - * node. + * Methods for inserting a {@link Probe} at a Truffle AST node. *

- * Note that this interface is guest language agnostic, but current extensions are - * language-specific. This will be revisited. + * This interface is guest language agnostic, but current extensions are language-specific. This + * will be revisited. *

* Disclaimer: experimental interface under development. Really! */ diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java Fri Aug 22 16:03:49 2014 +0200 @@ -29,7 +29,8 @@ import com.oracle.truffle.api.nodes.*; /** - * Language-agnostic access to AST-based debugging support. + * Access to AST-based debugging support, which is could be language implementation specific in the + * details chosen to be presented. *

* WARNING: this interface is under development and will change substantially. */ @@ -37,7 +38,7 @@ /** * Prints a textual AST display, one line per node, with nesting. - * + * * @param p * @param node the root node of the display. * @param maxDepth the maximum number of levels to print below the root @@ -47,7 +48,7 @@ /** * Creates a textual AST display, one line per node, with nesting. - * + * * @param node the root node of the display. * @param maxDepth the maximum number of levels to print below the root * @param markNode a node to mark with a textual arrow prefix, if present. @@ -56,7 +57,7 @@ /** * Creates a textual AST display, one line per node, with nesting. - * + * * @param node the root node of the display. * @param maxDepth the maximum number of levels to print below the root */ diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ExecutionEvents.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ExecutionEvents.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ExecutionEvents.java Fri Aug 22 16:03:49 2014 +0200 @@ -28,8 +28,9 @@ import com.oracle.truffle.api.nodes.*; /** - * Normal events during program execution at Truffle AST nodes that are reported via a {@link Probe} - * associated with the node, and made available to the probe's attached {@link Instrument}s. + * Normal events at each Truffle AST {@link Node} that occur during guest language execution, and + * which the {@link Probe} associated with that node, if any, reports to every {@link Instrument} + * attached to the {@link Probe}. *

* Disclaimer: experimental interface under development. */ diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumentable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumentable.java Fri Aug 22 16:03:49 2014 +0200 @@ -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. 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.instrument; + +import com.oracle.truffle.api.*; + +public interface Instrumentable { + + /** + * Optionally applies instrumentation at a Truffle AST node, depending on guest + * language characteristics and use-case policy. Ideally, the parent node of the guest language + * implements this interface. + *

    + *
  • if no instrumentation is to be applied, returns the AST node unmodified;
  • + *
  • if an AST node is to be instrumented, then creates a new Wrapper that decorates + * the AST node. Additionally, this creates a probe on the wrapper that is to be used for + * attaching instruments. This {@link Probe} is notified of all {@link ExecutionEvents} at the + * wrapped AST node.
  • + *
+ * + * @param context The {@link ExecutionContext} of the guest language used to create probes on + * the wrapper. + * @return The probe that was created. + */ + public Probe probe(ExecutionContext context); +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Fri Aug 22 16:03:49 2014 +0200 @@ -45,9 +45,6 @@ * attached instruments seldom changes. The assumption is invalidated when instruments are added or * removed, but some instruments may change their internal state in such a way that the assumption * should also be invalidated. - *

- * Disclaimer: experimental interface under development. In particular, the - * notify methods must be migrated to another interface. * * @see Instrument * @see Wrapper @@ -55,24 +52,34 @@ public interface Probe extends ExecutionEvents, SyntaxTagged { /** - * The source location with which this probe is (presumably uniquely) associated. + * Get the {@link SourceSection} in some Truffle AST associated with this probe. + * + * @return The source associated with this probe. */ SourceSection getSourceLocation(); /** - * Mark this probe as being associated with an AST node in some category useful for debugging - * and other tools. + * Mark this probe as belonging to some tool-related category that can be used to guide tool + * behavior at an associated AST node. For example, a debugger might add the tag + * {@link StandardSyntaxTag#STATEMENT} as a way of configuring where execution should stop when + * stepping. */ void tagAs(SyntaxTag tag); /** - * Adds an instrument to this probe. + * Adds an {@link Instrument} to this probe's collection. No check is made to see if the same + * instrument has already been added. + * + * @param newInstrument The instrument to add to this probe. */ void addInstrument(Instrument newInstrument); /** - * Removes an instrument from this probe. + * Removes the given instrument from the probe's collection. + * + * @param oldInstrument The instrument to remove from this probe. + * @throws RuntimeException if no matching instrument has been attached. */ - void removeInstrument(Instrument oldInstrument); + void removeInstrument(Instrument oldInstrument) throws RuntimeException; } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeListener.java Fri Aug 22 16:03:49 2014 +0200 @@ -39,7 +39,7 @@ * Notifies that a newly created (untagged) {@link Probe} has been inserted into a Truffle AST. * There will be no notification when an existing {@link Probe} is shared by an AST copy. */ - void newProbeInserted(SourceSection location, Probe probe); + void newProbeInserted(SourceSection source, Probe probe); /** * Notifies that a (fully constructed) {@link Probe} has been tagged. A subsequent marking with diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java Fri Aug 22 16:03:49 2014 +0200 @@ -36,12 +36,13 @@ public interface SyntaxTagged { /** - * Is this node tagged as belonging to a particular category of language constructs? + * Is this node tagged as belonging to a particular human-sensible category of language + * constructs? */ boolean isTaggedAs(SyntaxTag tag); /** - * In which categories has this node been tagged (empty set if none). + * In which user-sensible categories has this node been tagged (empty set if none). */ Iterable getSyntaxTags(); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java Fri Aug 22 16:03:49 2014 +0200 @@ -34,9 +34,9 @@ import com.oracle.truffle.api.source.*; /** - * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments. - *

- * Coordinates propagation of Truffle AST {@link ExecutionEvents}. + * Abstract implementation of Truffle {@link Node}s used as AST {@link Probe}s and + * {@link Instrument}s. A {@link Probe} manages its attached {@link Instrument}s by appending them + * to a chain through which {@link ExecutionEvents} are propagated. */ public abstract class InstrumentationNode extends Node implements ExecutionEvents { @@ -44,18 +44,12 @@ void newTagAdded(ProbeImpl probe, SyntaxTag tag); } - /** - * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection} - * extent of guest language source code. - * - * @return a new probe - */ - static ProbeImpl createProbe(SourceSection sourceSection, ProbeCallback probeCallback) { - return new ProbeImpl(sourceSection, probeCallback); + static ProbeImpl createProbe(SourceSection source, ProbeCallback probeCallback) { + return new ProbeImpl(source, probeCallback); } /** - * Next in chain. + * Next instrumentation node in chain. */ @Child protected InstrumentationNode next; @@ -71,7 +65,7 @@ } /** - * Add a probe to the end of this probe chain. + * Add an instrument to the end of this instrument chain. */ private void internalAddInstrument(Instrument newInstrument) { if (next == null) { @@ -81,6 +75,12 @@ } } + /** + * Remove an instrument from this instrument chain. If no matching instrument is found, a + * {@link RuntimeException} is thrown. + * + * @param oldInstrument The {@link Instrument} to remove. + */ private void internalRemoveInstrument(Instrument oldInstrument) { if (next == null) { throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument); @@ -109,6 +109,14 @@ } } + /** + * Informs the instrument that execution is just about to enter an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalEnter(Node, VirtualFrame)} to inform all instruments in the chain. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of entry + */ protected void internalEnter(Node astNode, VirtualFrame frame) { enter(astNode, frame); if (next != null) { @@ -116,6 +124,15 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalEnter(Node, VirtualFrame)} to inform all instruments in the chain. In this + * case, there is no return value. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + */ protected void internalLeave(Node astNode, VirtualFrame frame) { leave(astNode, frame); if (next != null) { @@ -123,6 +140,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, boolean)} to inform all instruments in the chain. + * In this case, a boolean value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The boolean result + */ protected void internalLeave(Node astNode, VirtualFrame frame, boolean result) { leave(astNode, frame, result); if (next != null) { @@ -130,6 +157,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, byte)} to inform all instruments in the chain. In + * this case, a byte value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The byte result + */ protected void internalLeave(Node astNode, VirtualFrame frame, byte result) { leave(astNode, frame, result); if (next != null) { @@ -137,6 +174,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, short)} to inform all instruments in the chain. In + * this case, a short value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The short result + */ protected void internalLeave(Node astNode, VirtualFrame frame, short result) { leave(astNode, frame, result); if (next != null) { @@ -144,6 +191,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, int)} to inform all instruments in the chain. In + * this case, a int value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The int result + */ protected void internalLeave(Node astNode, VirtualFrame frame, int result) { leave(astNode, frame, result); if (next != null) { @@ -151,6 +208,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, long)} to inform all instruments in the chain. In + * this case, a long value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The long result + */ protected void internalLeave(Node astNode, VirtualFrame frame, long result) { leave(astNode, frame, result); if (next != null) { @@ -158,6 +225,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, char)} to inform all instruments in the chain. In + * this case, a char value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The char result + */ protected void internalLeave(Node astNode, VirtualFrame frame, char result) { leave(astNode, frame, result); if (next != null) { @@ -165,6 +242,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, float)} to inform all instruments in the chain. In + * this case, a float value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The float result + */ protected void internalLeave(Node astNode, VirtualFrame frame, float result) { leave(astNode, frame, result); if (next != null) { @@ -172,6 +259,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, double)} to inform all instruments in the chain. In + * this case, a double value was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The double result + */ protected void internalLeave(Node astNode, VirtualFrame frame, double result) { leave(astNode, frame, result); if (next != null) { @@ -179,6 +276,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeave(Node, VirtualFrame, Object)} to inform all instruments in the chain. In + * this case, an Object was returned. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param result The Object result + */ protected void internalLeave(Node astNode, VirtualFrame frame, Object result) { leave(astNode, frame, result); if (next != null) { @@ -186,6 +293,16 @@ } } + /** + * Informs the instrument that execution has just returned from an AST node with which this + * instrumentation node is associated. This will continue to call + * {@link #internalLeaveExceptional(Node, VirtualFrame, Exception)} to inform all instruments in + * the chain. In this case, a exception (sometimes containing a value) was thrown. + * + * @param astNode The {@link Node} that was entered + * @param frame The {@link VirtualFrame} at the time of exit + * @param e The exception + */ protected void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { leaveExceptional(astNode, frame, null); if (next != null) { @@ -195,41 +312,66 @@ /** * Holder of a chain of {@linkplain InstrumentationNode instruments}: manages the - * {@link Assumption} that none of the instruments have changed since last checked. + * {@link Assumption} that no {@link Instrument}s have been added or removed and that none of + * the attached instruments have changed state in a way that would require deopt. *

* An instance is intended to be shared by every clone of the AST node with which it is * originally attached, so it holds no parent pointer. *

- * May be categorized by one or more {@linkplain SyntaxTag tags}, signifying information useful - * for instrumentation about its AST location(s). + * Each probe is associated with a {@link SourceSection}, not necessarily uniquely, although + * such a policy could be enforced for some uses. + *

+ * Each {@link Probe} be categorized by one or more {@linkplain SyntaxTag tags}, signifying + * information useful for instrumentation about its AST location(s). */ static final class ProbeImpl extends InstrumentationNode implements Probe { private final ProbeCallback probeCallback; - /** - * Source information about the AST node (and its clones) to which this probe is attached. - */ - private final SourceSection probedSourceSection; - // TODO (mlvdv) assumption model broken @CompilerDirectives.CompilationFinal private Assumption probeUnchanged; @CompilerDirectives.CompilationFinal private SyntaxTagTrap trap = null; + /** + * The collection of tags for this instrumentation node + */ private final ArrayList tags = new ArrayList<>(); - private ProbeImpl(SourceSection sourceSection, ProbeCallback probeCallback) { + /** + * The region of source code associated with this probe. Note that this is distinct from + * {@link Node#getSourceSection()}, which is {@code null} for all instances of + * {@link InstrumentationNode} since they have no corresponding source of their own. + */ + private final SourceSection source; + + /** + * Constructor. + * + * @param source The {@link SourceSection} associated with this probe. + * @param probeCallback The {@link ProbeCallback} to inform when tags have been added to + * this probe. + */ + private ProbeImpl(SourceSection source, ProbeCallback probeCallback) { this.probeCallback = probeCallback; - this.probedSourceSection = sourceSection; + this.source = source; this.probeUnchanged = Truffle.getRuntime().createAssumption(); this.next = null; } + /** + * Returns the {@link SourceSection} associated with this probe. + */ public SourceSection getSourceLocation() { - return probedSourceSection; + return source; } + /** + * Tags this probe with the given {@link SyntaxTag}. If the tag already exists, the tag is + * not added. + * + * @param tag The tag to add to this probe. + */ @SlowPath public void tagAs(SyntaxTag tag) { assert tag != null; @@ -239,15 +381,32 @@ } } + /** + * Checks if this probe has been tagged with the given tag. + * + * @param tag The {@link SyntaxTag} to check for. + * @return True if this probe has the given tag, false otherwise. + */ public boolean isTaggedAs(SyntaxTag tag) { assert tag != null; return tags.contains(tag); } + /** + * Returns an iterable collection of all syntax tags on this probe. + * + * @return A collection of {@link SyntaxTag}s. + */ public Iterable getSyntaxTags() { return tags; } + /** + * Adds the given {@link Instrument} to this probe's chain of instruments. This method does + * not check to see if the same instrument has already been added. + * + * @param instrument The instrument to add to this probe. + */ @SlowPath public void addInstrument(Instrument instrument) { probeUnchanged.invalidate(); @@ -255,6 +414,12 @@ probeUnchanged = Truffle.getRuntime().createAssumption(); } + /** + * Removes the given instrument from the chain of instruments. If no matching instrument is + * found, a {@link RuntimeException} is thrown. + * + * @param instrument The instrument to remove from this probe. + */ @SlowPath public void removeInstrument(Instrument instrument) { probeUnchanged.invalidate(); @@ -262,6 +427,9 @@ probeUnchanged = Truffle.getRuntime().createAssumption(); } + /** + * Returns this probe. + */ @Override protected Probe getProbe() { return this; diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,135 @@ +/* + * 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.api.instrument.impl; + +import java.util.*; + +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.source.*; + +/** + * A mapping from {@link LineLocation} (a line number in a specific piece of {@link Source} code) to + * a collection of {@link Probe}s whose associated {@link SourceSection} starts on that line. + */ +public class LineLocationToProbeCollectionMap implements ProbeListener { + + /** + * Map: Source line ==> probes associated with source sections starting on the line. + */ + private final Map> lineToProbesMap = new HashMap<>(); + + public LineLocationToProbeCollectionMap() { + } + + public void newProbeInserted(SourceSection source, Probe probe) { + if (source != null && !(source instanceof NullSourceSection)) + this.addProbeToLine(source.getLineLocation(), probe); + } + + public void probeTaggedAs(Probe probe, SyntaxTag tag) { + // This map ignores tags + } + + /** + * Returns the {@link Probe}, if any, associated with source that starts on a specified line; if + * there are more than one, return the one with the first starting character location. + */ + public Probe findLineProbe(LineLocation lineLocation) { + Probe probe = null; + final Collection probes = getProbesAtLine(lineLocation); + for (Probe probeOnLine : probes) { + if (probe == null) { + probe = probeOnLine; + } else if (probeOnLine.getSourceLocation().getCharIndex() < probe.getSourceLocation().getCharIndex()) { + probe = probeOnLine; + } + } + return probe; + } + + /** + * Records creation of a probe whose associated source starts on the given line. + *

+ * If the line already exists in the internal {@link #lineToProbesMap}, this probe will be added + * to the existing collection. If no line already exists in the internal map, then a new key is + * added along with a new collection containing the probe. + *

+ * This class requires that each added line/probe pair hasn't been previously added. However, + * attaching the same probe to a new line location is allowed. + * + * @param line The {@link LineLocation} to attach the probe to. + * @param probe The {@link Probe} to attach for that line location. + */ + protected void addProbeToLine(LineLocation line, Probe probe) { + + if (!lineToProbesMap.containsKey(line)) { + // Key does not exist, add new probe list + final ArrayList newProbeList = new ArrayList<>(2); + newProbeList.add(probe); + lineToProbesMap.put(line, newProbeList); + } else { + // Probe list exists, add to existing + final Collection existingProbeList = lineToProbesMap.get(line); + assert !existingProbeList.contains(probe); + existingProbeList.add(probe); + } + } + + /** + * + * Returns a collection of {@link Probe}s whose associated source begins at the given + * {@link LineLocation}. If there are no probes at that line, an empty list is returned. + * + * @param line The line to check. + * @return A collection of probes at the given line. + */ + public Collection getProbesAtLine(LineLocation line) { + Collection probeList = lineToProbesMap.get(line); + + if (probeList == null) + probeList = new ArrayList<>(1); + + return probeList; + } + + /** + * Convenience method to get probes according to a int line number. Returns a collection of + * {@link Probe}s at the given line number. If there are no probes at that line, a new empty + * list is returned. + * + * @param lineNumber The line number to check. + * @return A iterable collection of probes at the given line. + */ + public Collection getProbesAtLineNumber(int lineNumber) { + ArrayList probes = new ArrayList<>(); + + for (LineLocation line : lineToProbesMap.keySet()) { + if (line.getLineNumber() == lineNumber) + probes.addAll(lineToProbesMap.get(line)); + } + + return probes; + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToSourceSectionCollectionMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToSourceSectionCollectionMap.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,118 @@ +/* + * 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.api.instrument.impl; + +import java.util.*; + +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.source.*; + +/** + * A mapping from {@link LineLocation} (a line number in a specific piece of {@link Source} code) to + * a collection of {@link SourceSection}s that exist on that line. This class assumes that all nodes + * are instrumented as it uses the {@link ProbeListener} interface to determine the source sections + * that exist in the file. + */ +public class LineLocationToSourceSectionCollectionMap implements ProbeListener { + + /** + * Map: Source line ==> source sections that exist on the line. + */ + private final Map> lineToSourceSectionsMap = new HashMap<>(); + + public LineLocationToSourceSectionCollectionMap() { + + } + + public void newProbeInserted(SourceSection sourceSection, Probe probe) { + if (sourceSection != null && !(sourceSection instanceof NullSourceSection)) { + this.addSourceSectionToLine(sourceSection.getLineLocation(), sourceSection); + } + } + + public void probeTaggedAs(Probe probe, SyntaxTag tag) { + // This map ignores tags, but this subclasses can override this method to operate on tags. + } + + /** + * Adds a source section to the given line. + *

+ * If the line already exists in the internal {@link #lineToSourceSectionsMap}, this source + * section will be added to the existing collection. If no line already exists in the internal + * map, then a new key is added along with a new collection containing the source section. + *

+ * This class does not check if a source section has already been added to a line. + * + * @param line The {@link LineLocation} to attach the source section to. + * @param sourceSection The {@link SourceSection} to attach for that line location. + */ + protected void addSourceSectionToLine(LineLocation line, SourceSection sourceSection) { + if (!lineToSourceSectionsMap.containsKey(line)) { + // Key does not exist, add new source section list + final ArrayList newSourceSectionList = new ArrayList<>(2); + newSourceSectionList.add(sourceSection); + lineToSourceSectionsMap.put(line, newSourceSectionList); + } else { + // Source section list exists, add to existing + final Collection existingSourceSectionList = lineToSourceSectionsMap.get(line); + existingSourceSectionList.add(sourceSection); + } + } + + /** + * Returns a collection of {@link SourceSection}s at the given {@link LineLocation}. If there + * are no source sections at that line, a new empty list of size 1 is returned. + * + * @param line The line to check. + * @return A iterable collection of source sections at the given line. + */ + public Collection getSourceSectionsAtLine(LineLocation line) { + Collection sourceSectionList = lineToSourceSectionsMap.get(line); + + if (sourceSectionList == null) + sourceSectionList = new ArrayList<>(1); + + return sourceSectionList; + } + + /** + * Convenience method to get source sections according to a int line number. Returns a + * collection of {@link SourceSection}s at the given line number. If there are no source + * sections at that line, a new empty list is returned. + * + * @param lineNumber The line number to check. + * @return A iterable collection of source sections at the given line. + */ + public Collection getSourceSectionsAtLineNumber(int lineNumber) { + ArrayList sourceSections = new ArrayList<>(); + + for (LineLocation line : lineToSourceSectionsMap.keySet()) { + if (line.getLineNumber() == lineNumber) + sourceSections.addAll(lineToSourceSectionsMap.get(line)); + } + + return sourceSections; + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/ProbeManager.java Fri Aug 22 16:03:49 2014 +0200 @@ -36,20 +36,13 @@ */ public final class ProbeManager { - // TODO (mlvdv) use weak references. - /** - * Map: SourceSection ==> probe associated with that source section in an AST. - */ - private final Map srcToProbe = new HashMap<>(); - - // TODO (mlvdv) use weak references. - /** - * Map: Source line ==> probes associated with source sections starting on the line. - */ - private final Map> lineToProbes = new HashMap<>(); - private final List probeListeners = new ArrayList<>(); + private final List allProbes = new ArrayList<>(); + + /** + * Called when a {@link #tagTrap} is activated in a Probe. + */ private final ProbeCallback probeCallback; /** @@ -74,11 +67,17 @@ }; } + /** + * Adds a {@link ProbeListener} to receive events. + */ public void addProbeListener(ProbeListener listener) { assert listener != null; probeListeners.add(listener); } + /** + * Removes a {@link ProbeListener}. Ignored if listener not found. + */ public void removeProbeListener(ProbeListener removeListener) { final List listeners = new ArrayList<>(probeListeners); for (ProbeListener listener : listeners) { @@ -88,45 +87,32 @@ } } - public Probe getProbe(SourceSection sourceSection) { - assert sourceSection != null; - - ProbeImpl probe = srcToProbe.get(sourceSection); - - if (probe != null) { - return probe; - } - probe = InstrumentationNode.createProbe(sourceSection, probeCallback); + /** + * Creates a new {@link Probe} associated with a {@link SourceSection} of code corresponding to + * a Truffle AST node. + */ + public Probe createProbe(SourceSection source) { + assert source != null; - // Register new probe by unique SourceSection - srcToProbe.put(sourceSection, probe); - - // Register new probe by source line, there may be more than one - // Create line location for map key - final LineLocation lineLocation = sourceSection.getLineLocation(); - - Collection probes = lineToProbes.get(lineLocation); - if (probes == null) { - probes = new ArrayList<>(2); - lineToProbes.put(lineLocation, probes); - } - probes.add(probe); + ProbeImpl probe = InstrumentationNode.createProbe(source, probeCallback); + allProbes.add(probe); for (ProbeListener listener : probeListeners) { - listener.newProbeInserted(sourceSection, probe); + listener.newProbeInserted(source, probe); } return probe; } - public boolean hasProbe(SourceSection sourceSection) { - assert sourceSection != null; - return srcToProbe.get(sourceSection) != null; - } - + /** + * Returns the subset of all {@link Probe}s holding a particular {@link SyntaxTag}, or the whole + * collection if the specified tag is {@code null}. + * + * @return A collection of probes containing the given tag. + */ public Collection findProbesTaggedAs(SyntaxTag tag) { final List probes = new ArrayList<>(); - for (Probe probe : srcToProbe.values()) { + for (Probe probe : allProbes) { if (tag == null || probe.isTaggedAs(tag)) { probes.add(probe); } @@ -134,15 +120,16 @@ return probes; } - public Collection findProbesByLine(LineLocation lineLocation) { - final Collection probes = lineToProbes.get(lineLocation); - if (probes == null) { - return Collections.emptyList(); - } - return new ArrayList<>(probes); - } - - public void setTagTrap(SyntaxTagTrap tagTrap) { + /** + * Sets the current "tag trap", which will cause a callback to be triggered whenever execution + * reaches a Probe (existing or subsequently created) with the specified tag. There can only be + * one tag trap set at a time. + *

+ * + * @param tagTrap The {@link SyntaxTagTrap} to set. + * @throws IllegalStateException if a trap is currently set. + */ + public void setTagTrap(SyntaxTagTrap tagTrap) throws IllegalStateException { assert tagTrap != null; if (this.tagTrap != null) { throw new IllegalStateException("trap already set"); @@ -150,18 +137,23 @@ this.tagTrap = tagTrap; SyntaxTag tag = tagTrap.getTag(); - for (ProbeImpl probe : srcToProbe.values()) { + for (ProbeImpl probe : allProbes) { if (probe.isTaggedAs(tag)) { probe.setTrap(tagTrap); } } } + /** + * Clears the current {@link SyntaxTagTrap}. + * + * @throws IllegalStateException if no trap is currently set. + */ public void clearTagTrap() { if (this.tagTrap == null) { throw new IllegalStateException("no trap set"); } - for (ProbeImpl probe : srcToProbe.values()) { + for (ProbeImpl probe : allProbes) { if (probe.isTaggedAs(tagTrap.getTag())) { probe.setTrap(null); } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BinaryConditionProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BinaryConditionProfile.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,73 @@ +/* + * 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.api.utilities; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; + +/** + * Utility class to speculate on conditions to be never true or to be never false. Condition + * profiles are intended to be used as part of if conditions. + * + * @see ConditionProfile#createBinaryProfile() + */ +public final class BinaryConditionProfile extends ConditionProfile { + + @CompilationFinal private boolean wasTrue; + @CompilationFinal private boolean wasFalse; + + BinaryConditionProfile() { + /* package protected constructor */ + } + + @Override + public boolean profile(boolean value) { + if (value) { + if (!wasTrue) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + wasTrue = true; + } + } else { + if (!wasFalse) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + wasFalse = true; + } + } + return value; + } + + public boolean wasTrue() { + return wasTrue; + } + + public boolean wasFalse() { + return wasFalse; + } + + @Override + public String toString() { + return String.format("%s(wasTrue=%s, wasFalse=%s)@%x", getClass().getSimpleName(), wasTrue, wasFalse, hashCode()); + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BooleanConditionProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BooleanConditionProfile.java Fri Aug 22 15:56:51 2014 +0200 +++ /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. - * 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.utilities; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.*; - -/** - * Utility class to speculate on conditions to be never true or to be never false. Condition - * profiles are intended to be used as part of if conditions. - * - * Example usage: - * - *

- * private final ConditionProfile zero = new BooleanConditionProfile();
- * 
- * int value = ...;
- * if (zero.profile(value == 0)) {
- *   return 0;
- * } else {
- *   return value;
- * }
- *
- * 
- * - * @see ConditionProfile - * @see IntegerConditionProfile - */ -public class BooleanConditionProfile extends ConditionProfile { - - @CompilationFinal private boolean wasTrue; - @CompilationFinal private boolean wasFalse; - - @Override - public boolean profile(boolean value) { - if (value) { - if (!wasTrue) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - wasTrue = true; - } - } else { - if (!wasFalse) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - wasFalse = true; - } - } - return value; - } - - public boolean wasTrue() { - return wasTrue; - } - - public boolean wasFalse() { - return wasFalse; - } - - @Override - public String toString() { - return String.format("%s(wasTrue=%s, wasFalse=%s)@%x", getClass().getSimpleName(), wasTrue, wasFalse, hashCode()); - } -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java Fri Aug 22 16:03:49 2014 +0200 @@ -32,6 +32,9 @@ * invoked first the optimized code is invalidated and the branch where {@link #enter()} is invoked * is enabled for compilation. Otherwise if the {@link #enter()} method was never invoked the branch * will not get compiled. + * + * All {@code BranchProfile} instances must be held in {@code final} fields for compiler + * optimizations to take effect. */ public final class BranchProfile { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java Fri Aug 22 16:03:49 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -24,6 +24,8 @@ */ package com.oracle.truffle.api.utilities; +import com.oracle.truffle.api.*; + /** * Abstract utility class to speculate on conditions. Condition profiles are intended to be used as * part of if conditions. @@ -31,8 +33,8 @@ * Example usage: * *
- * private final ConditionProfile zero = ...;
- *
+ * private final ConditionProfile zero = ConditionProfile.createBinaryProfile();
+ * 
  * int value = ...;
  * if (zero.profile(value == 0)) {
  *   return 0;
@@ -42,11 +44,40 @@
  *
  * 
* - * @see BooleanConditionProfile - * @see IntegerConditionProfile + * All instances of {@code ConditionProfile} (and subclasses) must be held in {@code final} fields + * for compiler optimizations to take effect. + * + * @see #createCountingProfile() + * @see #createBinaryProfile() */ public abstract class ConditionProfile { public abstract boolean profile(boolean value); + /** + * Returns a {@link ConditionProfile} that speculates on conditions to be never + * true or to be never false. Additionally to a binary profile this + * method returns a condition profile that also counts the number of times the condition was + * true and false. This information is reported to the underlying optimization system using + * {@link CompilerDirectives#injectBranchProbability(double, boolean)}. Condition profiles are + * intended to be used as part of if conditions. + * + * @see ConditionProfile + * @see #createBinaryProfile() + */ + public static CountingConditionProfile createCountingProfile() { + return new CountingConditionProfile(); + } + + /** + * REturns a {@link ConditionProfile} that speculates on conditions to be never true or to be + * never false. Condition profiles are intended to be used as part of if conditions. + * + * @see ConditionProfile + * @see ConditionProfile#createBinaryProfile() + */ + public static BinaryConditionProfile createBinaryProfile() { + return new BinaryConditionProfile(); + } + } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CountingConditionProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CountingConditionProfile.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,80 @@ +/* + * 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.api.utilities; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; + +/** + * Utility class to speculate on conditions to be never true or to be never false. Additionally to + * {@link BinaryConditionProfile} this implementation of {@link ConditionProfile} also counts the + * number of times the condition was true and false. This information is reported to the underlying + * optimization system using {@link CompilerDirectives#injectBranchProbability(double, boolean)}. + * Condition profiles are intended to be used as part of if conditions. + * + * @see ConditionProfile#createCountingProfile() + */ +public final class CountingConditionProfile extends ConditionProfile { + + @CompilationFinal private int trueCount; + @CompilationFinal private int falseCount; + + CountingConditionProfile() { + /* package protected constructor */ + } + + @Override + public boolean profile(boolean value) { + if (value) { + if (trueCount == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + } + if (CompilerDirectives.inInterpreter()) { + trueCount++; + } + } else { + if (falseCount == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + } + if (CompilerDirectives.inInterpreter()) { + falseCount++; + } + } + return CompilerDirectives.injectBranchProbability((double) trueCount / (double) (trueCount + falseCount), value); + } + + public int getTrueCount() { + return trueCount; + } + + public int getFalseCount() { + return falseCount; + } + + @Override + public String toString() { + return String.format("%s(trueCount=%s, falseCount=%s)@%x", getClass().getSimpleName(), trueCount, falseCount, hashCode()); + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/IntegerConditionProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/IntegerConditionProfile.java Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +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. 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.utilities; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.*; - -/** - * Utility class to speculate on conditions to be never true or to be never false. Additionally to - * {@link BooleanConditionProfile} this implementation of {@link ConditionProfile} also counts the - * number of times the condition was true and false. This information is reported to the underlying - * optimization system using {@link CompilerDirectives#injectBranchProbability(double, boolean)}. - * Condition profiles are intended to be used as part of if conditions. - * - * Example usage: - * - *
- * private final ConditionProfile zero = new IntegerConditionProfile();
- *
- * int value = ...;
- * if (zero.profile(value == 0)) {
- *   return 0;
- * } else {
- *   return value;
- * }
- *
- * 
- * - * @see ConditionProfile - * @see IntegerConditionProfile - */ -public class IntegerConditionProfile extends ConditionProfile { - - @CompilationFinal private int trueCount; - @CompilationFinal private int falseCount; - - @Override - public boolean profile(boolean value) { - if (value) { - if (trueCount == 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - } - if (CompilerDirectives.inInterpreter()) { - trueCount++; - } - } else { - if (falseCount == 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - } - if (CompilerDirectives.inInterpreter()) { - falseCount++; - } - } - return CompilerDirectives.injectBranchProbability((double) trueCount / (double) (trueCount + falseCount), value); - } - - public int getTrueCount() { - return trueCount; - } - - public int getFalseCount() { - return falseCount; - } - - @Override - public String toString() { - return String.format("%s(trueCount=%s, falseCount=%s)@%x", getClass().getSimpleName(), trueCount, falseCount, hashCode()); - } -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Fri Aug 22 16:03:49 2014 +0200 @@ -322,12 +322,12 @@ /** *
      * variant1 $condition != null
-     * 
+     *
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     * 
+     *
      * variant2 $condition != null
      * $type $name = $value;
      * 
@@ -1590,12 +1590,16 @@ } private boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardExpression guard) { - int signatureIndex = 0; for (Parameter parameter : guard.getResolvedGuard().getParameters()) { if (!parameter.getSpecification().isSignature()) { continue; } + int signatureIndex = source.getNode().getChildExecutions().indexOf(parameter.getSpecification().getExecution()); + if (signatureIndex == -1) { + continue; + } + TypeGuard typeGuard = group.findTypeGuard(signatureIndex); if (typeGuard != null) { TypeData requiredType = typeGuard.getType(); @@ -1609,8 +1613,6 @@ return true; } } - - signatureIndex++; } return false; } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Fri Aug 22 16:03:49 2014 +0200 @@ -530,7 +530,7 @@ public static boolean isEnclosedIn(Element enclosedIn, Element element) { if (element == null) { return false; - } else if (enclosedIn.equals(element)) { + } else if (typeEquals(enclosedIn.asType(), element.asType())) { return true; } else { return isEnclosedIn(enclosedIn, element.getEnclosingElement()); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java Fri Aug 22 16:03:49 2014 +0200 @@ -27,18 +27,43 @@ public final class GuardExpression { private GuardData resolvedGuard; + private NodeExecutionData[] resolvedChildren; private final String guardName; private final boolean negated; + private final String[] childNames; - public GuardExpression(String expression) { - if (expression.startsWith("!")) { - guardName = expression.substring(1, expression.length()); + public GuardExpression(String expression, boolean allowArguments) { + String exp = expression; + if (exp.startsWith("!")) { + exp = exp.substring(1, exp.length()); negated = true; } else { - guardName = expression; negated = false; } + + int argumentStart = exp.indexOf('('); + int endIndex = exp.lastIndexOf(')'); + if (allowArguments && argumentStart != -1 && endIndex != -1) { + guardName = exp.substring(0, argumentStart).trim(); + String arguments = exp.substring(argumentStart + 1, endIndex); + String[] children = arguments.split(","); + for (int i = 0; i < children.length; i++) { + children[i] = children[i].trim(); + } + if (children.length == 1 && children[0].isEmpty()) { + childNames = new String[0]; + } else { + childNames = children; + } + } else { + guardName = exp; + childNames = null; + } + } + + public String[] getChildNames() { + return childNames; } public boolean isResolved() { @@ -49,18 +74,32 @@ return guardName; } - public void setGuard(GuardData guard) { + public NodeExecutionData[] getResolvedChildren() { + return resolvedChildren; + } + + public void setResolvedChildren(NodeExecutionData[] resolvedChildren) { + this.resolvedChildren = resolvedChildren; + } + + public void setResolvedGuard(GuardData guard) { this.resolvedGuard = guard; } @Override public boolean equals(Object obj) { - if (obj instanceof GuardExpression) { + if (this == obj) { + return true; + } else if (obj instanceof GuardExpression) { GuardExpression other = (GuardExpression) obj; if (isResolved() && other.isResolved()) { - return resolvedGuard.equals(other.resolvedGuard) && negated == other.negated; + return resolvedGuard.equals(other.resolvedGuard) && negated == other.negated && Arrays.equals(resolvedChildren, other.resolvedChildren); } else { - return guardName.equals(other.guardName) && negated == other.negated; + boolean equal = guardName.equals(other.guardName) && negated == other.negated; + if (childNames != null && other.childNames != null) { + equal &= Arrays.equals(childNames, other.childNames); + } + return equal; } } return false; @@ -68,18 +107,13 @@ @Override public int hashCode() { - return Objects.hash(guardName, negated, resolvedGuard); + return Objects.hash(guardName, negated, resolvedGuard, resolvedChildren); } public final boolean implies(GuardExpression other) { - if (other == this) { + if (equals(other)) { return true; } - if (getGuardName().equals(other.getGuardName())) { - if (isNegated() == other.isNegated()) { - return true; - } - } if (isResolved() && other.isResolved()) { for (GuardExpression implies : getResolvedGuard().getImpliesExpressions()) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Fri Aug 22 16:03:49 2014 +0200 @@ -30,7 +30,6 @@ import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; -import com.oracle.truffle.dsl.processor.parser.*; public class NodeData extends Template implements Comparable { @@ -208,6 +207,30 @@ return true; } + public NodeExecutionData findExecutionByExpression(String childNameExpression) { + String childName = childNameExpression; + int index = -1; + + int start = childName.indexOf('['); + int end = childName.lastIndexOf(']'); + if (start != -1 && end != -1 && start < end) { + try { + index = Integer.parseInt(childName.substring(start + 1, end)); + childName = childName.substring(0, start); + childName = NodeExecutionData.createName(childName, index); + } catch (NumberFormatException e) { + // ignore + } + } + + for (NodeExecutionData execution : childExecutions) { + if (execution.getName().equals(childName) && (execution.getIndex() == -1 || execution.getIndex() == index)) { + return execution; + } + } + return null; + } + public List getNodeDeclaringChildren() { List nodeChildren = new ArrayList<>(); for (NodeData child : getEnclosingNodes()) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,96 @@ +/* + * 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.model; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; + +public class NodeExecutionData { + + private final NodeChildData child; + private final String name; + private final int index; + private final boolean shortCircuit; + + public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) { + this.child = child; + this.index = index; + this.shortCircuit = shortCircuit; + this.name = createName(); + } + + private String createName() { + return createName(child.getName(), index); + } + + public TypeMirror getNodeType() { + TypeMirror type; + if (child.getCardinality() == Cardinality.MANY && child.getNodeType().getKind() == TypeKind.ARRAY) { + type = ((ArrayType) child.getNodeType()).getComponentType(); + } else { + type = child.getNodeType(); + } + return type; + } + + public String getName() { + return name; + } + + public NodeChildData getChild() { + return child; + } + + public int getIndex() { + return index; + } + + public boolean isIndexed() { + return index > -1; + } + + public boolean isShortCircuit() { + return shortCircuit; + } + + public String getShortCircuitId() { + return createShortCircuitId(child, index); + } + + public static String createShortCircuitId(NodeChildData child, int varArgsIndex) { + String shortCircuitName = child.getName(); + if (child.getCardinality().isMany()) { + shortCircuitName = shortCircuitName + "[" + varArgsIndex + "]"; + } + return shortCircuitName; + } + + public static String createName(String childName, int index) { + if (index > -1) { + return childName + index; + } + return childName; + } + +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Fri Aug 22 16:03:49 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.MethodSpec.TypeDef; -import com.oracle.truffle.dsl.processor.parser.*; public class ParameterSpec { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Fri Aug 22 16:03:49 2014 +0200 @@ -163,6 +163,17 @@ return foundParameters; } + public List findByExecutionData(NodeExecutionData execution) { + List foundParameters = new ArrayList<>(); + for (Parameter parameter : getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + if (spec != null && spec.getExecution() != null && spec.getExecution().equals(execution) && parameter.getSpecification().isSignature()) { + foundParameters.add(parameter); + } + } + return foundParameters; + } + public Parameter findParameter(String valueName) { for (Parameter param : getReturnTypeAndParameters()) { if (param.getLocalName().equals(valueName)) { diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethodParser.java Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +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.model; - -import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.java.*; - -public abstract class TemplateMethodParser { - - private final ProcessorContext context; - - protected final T template; - - private boolean emitErrors = true; - private boolean parseNullOnError = false; - private boolean useVarArgs = false; - - public TemplateMethodParser(ProcessorContext context, T template) { - this.template = template; - this.context = context; - } - - protected void setUseVarArgs(boolean useVarArgs) { - this.useVarArgs = useVarArgs; - } - - public boolean isUseVarArgs() { - return useVarArgs; - } - - public boolean isEmitErrors() { - return emitErrors; - } - - public void setParseNullOnError(boolean nullOnError) { - this.parseNullOnError = nullOnError; - } - - public boolean isParseNullOnError() { - return parseNullOnError; - } - - public void setEmitErrors(boolean emitErrors) { - this.emitErrors = emitErrors; - } - - public ProcessorContext getContext() { - return context; - } - - public TypeSystemData getTypeSystem() { - return template.getTypeSystem(); - } - - public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror); - - public abstract E create(TemplateMethod method, boolean invalid); - - public abstract boolean isParsable(ExecutableElement method); - - public Class getAnnotationType() { - return null; - } - - public final List parse(List elements) { - List methods = new ArrayList<>(); - methods.addAll(ElementFilter.methodsIn(elements)); - - List parsedMethods = new ArrayList<>(); - boolean valid = true; - int naturalOrder = 0; - for (ExecutableElement method : methods) { - if (!isParsable(method)) { - continue; - } - - Class annotationType = getAnnotationType(); - AnnotationMirror mirror = null; - if (annotationType != null) { - mirror = ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); - } - - E parsedMethod = parse(naturalOrder, method, mirror); - - if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) { - parsedMethod.addError("Method annotated with @%s must not be private.", getAnnotationType().getSimpleName()); - parsedMethods.add(parsedMethod); - valid = false; - continue; - } - - if (parsedMethod != null) { - parsedMethods.add(parsedMethod); - } else { - valid = false; - } - naturalOrder++; - } - Collections.sort(parsedMethods); - - if (!valid && parseNullOnError) { - return null; - } - return parsedMethods; - } - - private E parse(int naturalOrder, ExecutableElement method, AnnotationMirror annotation) { - MethodSpec methodSpecification = createSpecification(method, annotation); - if (methodSpecification == null) { - return null; - } - - methodSpecification.applyTypeDefinitions("types"); - - String id = method.getSimpleName().toString(); - TypeMirror returnType = method.getReturnType(); - List parameterTypes = new ArrayList<>(); - for (VariableElement var : method.getParameters()) { - parameterTypes.add(var.asType()); - } - - return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); - } - - private E parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, List parameterTypes) { - ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); - Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1); - if (returnTypeMirror == null) { - if (emitErrors) { - E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); - String expectedReturnType = returnTypeSpec.toSignatureString(true); - String actualReturnType = ElementUtils.getSimpleName(returnType); - - String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, - methodSpecification.toSignatureString(method.getSimpleName().toString())); - invalidMethod.addError(message); - return invalidMethod; - } else { - return null; - } - } - - List parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method != null ? method.isVarArgs() : false); - if (parameters == null) { - if (isEmitErrors() && method != null) { - E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); - String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(method), - methodSpecification.toSignatureString(method.getSimpleName().toString())); - invalidMethod.addError(message); - return invalidMethod; - } else { - return null; - } - } - - return create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, parameters), false); - } - - private static String createActualSignature(ExecutableElement method) { - StringBuilder b = new StringBuilder("("); - String sep = ""; - if (method != null) { - for (VariableElement var : method.getParameters()) { - b.append(sep); - b.append(ElementUtils.getSimpleName(var.asType())); - sep = ", "; - } - } - b.append(")"); - return b.toString(); - } - - /* - * Parameter parsing tries to parse required arguments starting from offset 0 with increasing - * offset until it finds a signature end that matches the required specification. If there is no - * end matching the required arguments, parsing fails. Parameters prior to the parsed required - * ones are cut and used to parse the optional parameters. - */ - private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { - List parsedRequired = null; - int offset = 0; - for (; offset <= parameterTypes.size(); offset++) { - List parameters = new ArrayList<>(); - parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); - parsedRequired = parseParametersRequired(spec, parameters, varArgs); - if (parsedRequired != null) { - break; - } - } - - if (parsedRequired == null) { - return null; - } - - if (parsedRequired.isEmpty() && offset == 0) { - offset = parameterTypes.size(); - } - List potentialOptionals = parameterTypes.subList(0, offset); - List parsedOptionals = parseParametersOptional(spec, potentialOptionals); - if (parsedOptionals == null) { - return null; - } - - List finalParameters = new ArrayList<>(); - finalParameters.addAll(parsedOptionals); - finalParameters.addAll(parsedRequired); - return finalParameters; - } - - private List parseParametersOptional(MethodSpec spec, List types) { - List parsedParams = new ArrayList<>(); - - int typeStartIndex = 0; - List specifications = spec.getOptional(); - outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { - ParameterSpec specification = specifications.get(specIndex); - for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { - TypeMirror actualType = types.get(typeIndex); - Parameter optionalParam = matchParameter(specification, actualType, -1, -1); - if (optionalParam != null) { - parsedParams.add(optionalParam); - typeStartIndex = typeIndex + 1; - continue outer; - } - } - } - - if (typeStartIndex < types.size()) { - // not enough types found - return null; - } - return parsedParams; - } - - private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { - List parsedParams = new ArrayList<>(); - List specifications = spec.getRequired(); - boolean specVarArgs = spec.isVariableRequiredParameters(); - int typeIndex = 0; - int specificationIndex = 0; - - ParameterSpec specification; - while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { - TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); - if (actualType == null) { - if (spec.isIgnoreAdditionalSpecifications()) { - break; - } - return null; - } - - int typeVarArgsIndex = typeVarArgs ? typeIndex - types.size() + 1 : -1; - int specVarArgsIndex = specVarArgs ? specificationIndex - specifications.size() + 1 : -1; - - if (typeVarArgsIndex >= 0 && specVarArgsIndex >= 0) { - // both specifications and types have a variable number of arguments - // we would get into an endless loop if we would continue - break; - } - - Parameter resolvedParameter = matchParameter(specification, actualType, specVarArgsIndex, typeVarArgsIndex); - if (resolvedParameter == null) { - return null; - } - parsedParams.add(resolvedParameter); - typeIndex++; - specificationIndex++; - } - - if (typeIndex < types.size()) { - // additional types available - if (spec.isIgnoreAdditionalParameters()) { - return parsedParams; - } else { - return null; - } - } - - return parsedParams; - } - - private static ParameterSpec nextSpecification(List specifications, int specIndex, boolean varArgs) { - if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { - return specifications.get(specifications.size() - 1); - } else if (specIndex < specifications.size()) { - return specifications.get(specIndex); - } else { - return null; - } - } - - private static TypeMirror nextActualType(List types, int typeIndex, boolean varArgs) { - if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { - // unpack varargs array argument - TypeMirror actualType = types.get(types.size() - 1); - if (actualType.getKind() == TypeKind.ARRAY) { - actualType = ((ArrayType) actualType).getComponentType(); - } - return actualType; - } else if (typeIndex < types.size()) { - return types.get(typeIndex); - } else { - return null; - } - } - - private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) { - TypeMirror resolvedType = mirror; - if (hasError(resolvedType)) { - return null; - } - - if (!specification.matches(resolvedType)) { - return null; - } - - TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); - if (resolvedTypeData != null) { - return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); - } else { - return new Parameter(specification, resolvedType, specificationIndex, varArgsIndex); - } - } - - public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { - return parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes); - } -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -35,9 +35,9 @@ public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) { super(context, node); - setEmitErrors(false); setParseNullOnError(false); - setUseVarArgs(true); + getParser().setEmitErrors(false); + getParser().setUseVarArgs(true); } @Override diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -35,14 +35,14 @@ public class GuardParser extends NodeMethodParser { - private final Set guardNames; - private final TemplateMethod compatibleSource; + private final GuardExpression expression; + private final TemplateMethod guardedMethod; - public GuardParser(ProcessorContext context, NodeData node, TemplateMethod compatibleSource, Set guardNames) { + public GuardParser(ProcessorContext context, NodeData node, TemplateMethod compatibleSource, GuardExpression expression) { super(context, node); - this.guardNames = guardNames; - this.compatibleSource = compatibleSource; - setEmitErrors(false); + this.expression = expression; + this.guardedMethod = compatibleSource; + getParser().setEmitErrors(false); setParseNullOnError(false); } @@ -55,21 +55,35 @@ public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null); spec.setIgnoreAdditionalSpecifications(true); - if (compatibleSource != null) { - spec.getRequired().clear(); - for (Parameter parameter : compatibleSource.getRequiredParameters()) { - List typeMirrors = ElementUtils.getAssignableTypes(getContext(), parameter.getType()); - Set typeIds = new HashSet<>(); - for (TypeMirror typeMirror : typeMirrors) { - typeIds.add(ElementUtils.getUniqueIdentifier(typeMirror)); + spec.getRequired().clear(); + + if (expression.getResolvedChildren() != null) { + for (NodeExecutionData execution : expression.getResolvedChildren()) { + List foundInGuardedMethod = guardedMethod.findByExecutionData(execution); + for (Parameter guardedParameter : foundInGuardedMethod) { + spec.addRequired(createParameterSpec(guardedParameter)); } - - spec.addRequired(new ParameterSpec(parameter.getSpecification(), typeMirrors, typeIds)); + } + } else { + for (Parameter parameter : guardedMethod.getRequiredParameters()) { + spec.addRequired(createParameterSpec(parameter)); } } + return spec; } + private ParameterSpec createParameterSpec(Parameter parameter) { + List typeMirrors = ElementUtils.getAssignableTypes(getContext(), parameter.getType()); + Set typeIds = new HashSet<>(); + for (TypeMirror typeMirror : typeMirrors) { + typeIds.add(ElementUtils.getUniqueIdentifier(typeMirror)); + } + typeIds.retainAll(getTypeSystem().getTypeIdentifiers()); + + return new ParameterSpec(parameter.getSpecification(), typeMirrors, typeIds); + } + @Override protected List nodeTypeMirrors(NodeData nodeData) { Set typeMirrors = new LinkedHashSet<>(); @@ -90,7 +104,7 @@ @Override public boolean isParsable(ExecutableElement method) { - return guardNames == null || guardNames.contains(method.getSimpleName().toString()); + return true; } @Override @@ -102,7 +116,7 @@ } List guardExpressions = new ArrayList<>(); for (String string : impliesExpressions) { - guardExpressions.add(new GuardExpression(string)); + guardExpressions.add(new GuardExpression(string, false)); } return new GuardData(method, guardExpressions); } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,288 @@ +/* + * 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.parser; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public final class MethodSpecParser { + + private boolean emitErrors = true; + private boolean useVarArgs = false; + + private final Template template; + + public MethodSpecParser(Template template) { + this.template = template; + } + + public Template getTemplate() { + return template; + } + + public TypeSystemData getTypeSystem() { + return template.getTypeSystem(); + } + + public boolean isEmitErrors() { + return emitErrors; + } + + public boolean isUseVarArgs() { + return useVarArgs; + } + + public void setEmitErrors(boolean emitErrors) { + this.emitErrors = emitErrors; + } + + public void setUseVarArgs(boolean useVarArgs) { + this.useVarArgs = useVarArgs; + } + + public TemplateMethod parse(MethodSpec methodSpecification, ExecutableElement method, AnnotationMirror annotation, int naturalOrder) { + if (methodSpecification == null) { + return null; + } + + methodSpecification.applyTypeDefinitions("types"); + + String id = method.getSimpleName().toString(); + TypeMirror returnType = method.getReturnType(); + List parameterTypes = new ArrayList<>(); + for (VariableElement var : method.getParameters()) { + parameterTypes.add(var.asType()); + } + + return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); + } + + public TemplateMethod parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, + List parameterTypes) { + ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); + Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1); + if (returnTypeMirror == null) { + if (emitErrors) { + TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()); + String expectedReturnType = returnTypeSpec.toSignatureString(true); + String actualReturnType = ElementUtils.getSimpleName(returnType); + + String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, + methodSpecification.toSignatureString(method.getSimpleName().toString())); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; + } + } + + List parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method != null ? method.isVarArgs() : false); + if (parameters == null) { + if (isEmitErrors() && method != null) { + TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()); + String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(method), + methodSpecification.toSignatureString(method.getSimpleName().toString())); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; + } + } + + return new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, parameters); + } + + private static String createActualSignature(ExecutableElement method) { + StringBuilder b = new StringBuilder("("); + String sep = ""; + if (method != null) { + for (VariableElement var : method.getParameters()) { + b.append(sep); + b.append(ElementUtils.getSimpleName(var.asType())); + sep = ", "; + } + } + b.append(")"); + return b.toString(); + } + + /* + * Parameter parsing tries to parse required arguments starting from offset 0 with increasing + * offset until it finds a signature end that matches the required specification. If there is no + * end matching the required arguments, parsing fails. Parameters prior to the parsed required + * ones are cut and used to parse the optional parameters. + */ + private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { + List parsedRequired = null; + int offset = 0; + for (; offset <= parameterTypes.size(); offset++) { + List parameters = new ArrayList<>(); + parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); + parsedRequired = parseParametersRequired(spec, parameters, varArgs); + if (parsedRequired != null) { + break; + } + } + + if (parsedRequired == null) { + return null; + } + + if (parsedRequired.isEmpty() && offset == 0) { + offset = parameterTypes.size(); + } + List potentialOptionals = parameterTypes.subList(0, offset); + List parsedOptionals = parseParametersOptional(spec, potentialOptionals); + if (parsedOptionals == null) { + return null; + } + + List finalParameters = new ArrayList<>(); + finalParameters.addAll(parsedOptionals); + finalParameters.addAll(parsedRequired); + return finalParameters; + } + + private List parseParametersOptional(MethodSpec spec, List types) { + List parsedParams = new ArrayList<>(); + + int typeStartIndex = 0; + List specifications = spec.getOptional(); + outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { + ParameterSpec specification = specifications.get(specIndex); + for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { + TypeMirror actualType = types.get(typeIndex); + Parameter optionalParam = matchParameter(specification, actualType, -1, -1); + if (optionalParam != null) { + parsedParams.add(optionalParam); + typeStartIndex = typeIndex + 1; + continue outer; + } + } + } + + if (typeStartIndex < types.size()) { + // not enough types found + return null; + } + return parsedParams; + } + + private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { + List parsedParams = new ArrayList<>(); + List specifications = spec.getRequired(); + boolean specVarArgs = spec.isVariableRequiredParameters(); + int typeIndex = 0; + int specificationIndex = 0; + + ParameterSpec specification; + while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { + TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); + if (actualType == null) { + if (spec.isIgnoreAdditionalSpecifications()) { + break; + } + return null; + } + + int typeVarArgsIndex = typeVarArgs ? typeIndex - types.size() + 1 : -1; + int specVarArgsIndex = specVarArgs ? specificationIndex - specifications.size() + 1 : -1; + + if (typeVarArgsIndex >= 0 && specVarArgsIndex >= 0) { + // both specifications and types have a variable number of arguments + // we would get into an endless loop if we would continue + break; + } + + Parameter resolvedParameter = matchParameter(specification, actualType, specVarArgsIndex, typeVarArgsIndex); + if (resolvedParameter == null) { + return null; + } + parsedParams.add(resolvedParameter); + typeIndex++; + specificationIndex++; + } + + if (typeIndex < types.size()) { + // additional types available + if (spec.isIgnoreAdditionalParameters()) { + return parsedParams; + } else { + return null; + } + } + + return parsedParams; + } + + private static ParameterSpec nextSpecification(List specifications, int specIndex, boolean varArgs) { + if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { + return specifications.get(specifications.size() - 1); + } else if (specIndex < specifications.size()) { + return specifications.get(specIndex); + } else { + return null; + } + } + + private static TypeMirror nextActualType(List types, int typeIndex, boolean varArgs) { + if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { + // unpack varargs array argument + TypeMirror actualType = types.get(types.size() - 1); + if (actualType.getKind() == TypeKind.ARRAY) { + actualType = ((ArrayType) actualType).getComponentType(); + } + return actualType; + } else if (typeIndex < types.size()) { + return types.get(typeIndex); + } else { + return null; + } + } + + private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) { + TypeMirror resolvedType = mirror; + if (hasError(resolvedType)) { + return null; + } + + if (!specification.matches(resolvedType)) { + return null; + } + + TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); + if (resolvedTypeData != null) { + return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); + } else { + return new Parameter(specification, resolvedType, specificationIndex, varArgsIndex); + } + } + +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeExecutionData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeExecutionData.java Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +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.parser; - -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.model.*; -import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; - -public class NodeExecutionData { - - private final NodeChildData child; - private final String name; - private final int index; - private final boolean shortCircuit; - - public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) { - this.child = child; - this.index = index; - this.shortCircuit = shortCircuit; - this.name = createName(); - } - - private String createName() { - if (isIndexed()) { - return child.getName() + index; - } - return child.getName(); - } - - public TypeMirror getNodeType() { - TypeMirror type; - if (child.getCardinality() == Cardinality.MANY && child.getNodeType().getKind() == TypeKind.ARRAY) { - type = ((ArrayType) child.getNodeType()).getComponentType(); - } else { - type = child.getNodeType(); - } - return type; - } - - public String getName() { - return name; - } - - public NodeChildData getChild() { - return child; - } - - public int getIndex() { - return index; - } - - public boolean isIndexed() { - return index > -1; - } - - public boolean isShortCircuit() { - return shortCircuit; - } - - public String getShortCircuitId() { - return createShortCircuitId(child, index); - } - - public static String createShortCircuitId(NodeChildData child, int varArgsIndex) { - String shortCircuitName = child.getName(); - if (child.getCardinality().isMany()) { - shortCircuitName = shortCircuitName + "[" + varArgsIndex + "]"; - } - return shortCircuitName; - } - -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -190,12 +190,18 @@ continue; } TypeElement typeElement = ElementUtils.fromTypeMirror(importGuardClass); - if (!typeElement.getModifiers().contains(Modifier.PUBLIC)) { + + // hack to reload type is necessary for incremental compiling in eclipse. + // otherwise methods inside of import guard types are just not found. + typeElement = ElementUtils.fromTypeMirror(context.reloadType(typeElement.asType())); + + if (typeElement.getEnclosingElement().getKind().isClass() && !typeElement.getModifiers().contains(Modifier.PUBLIC)) { node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' must be public.", ElementUtils.getQualifiedName(importGuardClass)); continue; } List importMethods = ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(typeElement)); + for (ExecutableElement importMethod : importMethods) { if (!importMethod.getModifiers().contains(Modifier.PUBLIC) || !importMethod.getModifiers().contains(Modifier.STATIC)) { continue; @@ -883,53 +889,70 @@ } private void initializeGuards(List elements, NodeData node) { - Map> guards = new HashMap<>(); + Map> potentialGuards = new HashMap<>(); for (SpecializationData specialization : node.getSpecializations()) { for (GuardExpression exp : specialization.getGuards()) { - guards.put(exp.getGuardName(), null); + potentialGuards.put(exp.getGuardName(), null); } } - GuardParser parser = new GuardParser(context, node, null, guards.keySet()); - List resolvedGuards = parser.parse(elements); - for (GuardData guard : resolvedGuards) { - List groupedGuards = guards.get(guard.getMethodName()); - if (groupedGuards == null) { - groupedGuards = new ArrayList<>(); - guards.put(guard.getMethodName(), groupedGuards); + TypeMirror booleanType = context.getType(boolean.class); + for (ExecutableElement potentialGuard : ElementFilter.methodsIn(elements)) { + if (potentialGuard.getModifiers().contains(Modifier.PRIVATE)) { + continue; + } + String methodName = potentialGuard.getSimpleName().toString(); + if (!potentialGuards.containsKey(methodName)) { + continue; } - groupedGuards.add(guard); + + if (!ElementUtils.typeEquals(potentialGuard.getReturnType(), booleanType)) { + continue; + } + + List potentialMethods = potentialGuards.get(methodName); + if (potentialMethods == null) { + potentialMethods = new ArrayList<>(); + potentialGuards.put(methodName, potentialMethods); + } + potentialMethods.add(potentialGuard); } for (SpecializationData specialization : node.getSpecializations()) { for (GuardExpression exp : specialization.getGuards()) { - resolveGuardExpression(node, specialization, guards, exp); + resolveGuardExpression(node, specialization, potentialGuards, exp); } } } - private void resolveGuardExpression(NodeData node, TemplateMethod source, Map> guards, GuardExpression expression) { - List availableGuards = guards.get(expression.getGuardName()); + private void resolveGuardExpression(NodeData node, TemplateMethod source, Map> guards, GuardExpression expression) { + List availableGuards = guards.get(expression.getGuardName()); if (availableGuards == null) { - source.addError("No compatible guard with method name '%s' found. Please note that all signature types of the method guard must be declared in the type system.", expression.getGuardName()); + source.addError("No compatible guard with method name '%s' found.", expression.getGuardName()); return; } - List guardMethods = new ArrayList<>(); - for (GuardData guard : availableGuards) { - guardMethods.add(guard.getMethod()); + + String[] childNames = expression.getChildNames(); + if (childNames != null) { + NodeExecutionData[] resolvedExecutions = new NodeExecutionData[childNames.length]; + for (int i = 0; i < childNames.length; i++) { + String childName = childNames[i]; + NodeExecutionData execution = node.findExecutionByExpression(childName); + if (execution == null) { + source.addError("Guard parameter '%s' for guard '%s' could not be mapped to a declared child node.", childName, expression.getGuardName()); + return; + } + resolvedExecutions[i] = execution; + } + expression.setResolvedChildren(resolvedExecutions); } - GuardParser parser = new GuardParser(context, node, source, null); - List matchingGuards = parser.parse(guardMethods); + + GuardParser parser = new GuardParser(context, node, source, expression); + List matchingGuards = parser.parse(availableGuards); if (!matchingGuards.isEmpty()) { GuardData guard = matchingGuards.get(0); // use the shared instance of the guard data - for (GuardData guardData : availableGuards) { - if (guardData.getMethod() == guard.getMethod()) { - expression.setGuard(guardData); - return; - } - } - throw new AssertionError("Should not reach here."); + expression.setResolvedGuard(guard); } else { MethodSpec spec = parser.createSpecification(source.getMethod(), source.getMarkerAnnotation()); spec.applyTypeDefinitions("types"); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Fri Aug 22 16:03:49 2014 +0200 @@ -424,16 +424,15 @@ } public boolean isTypeGuardUsedInAnyGuardBelow(ProcessorContext context, SpecializationData source, TypeGuard typeGuard) { + NodeExecutionData execution = source.getNode().getChildExecutions().get(typeGuard.getSignatureIndex()); for (GuardExpression guard : guards) { - Parameter guardParameter = guard.getResolvedGuard().getSignatureParameter(typeGuard.getSignatureIndex()); - if (guardParameter == null) { - // guardParameters are optional - continue; - } + List guardParameters = guard.getResolvedGuard().findByExecutionData(execution); Parameter sourceParameter = source.getSignatureParameter(typeGuard.getSignatureIndex()); - if (sourceParameter.getTypeSystemType().needsCastTo(guardParameter.getType())) { - return true; + for (Parameter guardParameter : guardParameters) { + if (sourceParameter.getTypeSystemType().needsCastTo(guardParameter.getType())) { + return true; + } } } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -84,7 +84,7 @@ List guardDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); List guardExpressions = new ArrayList<>(); for (String guardDef : guardDefs) { - guardExpressions.add(new GuardExpression(guardDef)); + guardExpressions.add(new GuardExpression(guardDef, true)); } specialization.setGuards(guardExpressions); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,142 @@ +/* + * 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.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public abstract class TemplateMethodParser { + + protected final T template; + private final ProcessorContext context; + private final MethodSpecParser parser; + + private boolean parseNullOnError; + + public TemplateMethodParser(ProcessorContext context, T template) { + this.template = template; + this.context = context; + this.parser = new MethodSpecParser(template); + } + + public void setParseNullOnError(boolean parseNullOnError) { + this.parseNullOnError = parseNullOnError; + } + + public boolean isParseNullOnError() { + return parseNullOnError; + } + + public MethodSpecParser getParser() { + return parser; + } + + public ProcessorContext getContext() { + return context; + } + + public TypeSystemData getTypeSystem() { + return template.getTypeSystem(); + } + + public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror); + + public abstract E create(TemplateMethod method, boolean invalid); + + public abstract boolean isParsable(ExecutableElement method); + + public Class getAnnotationType() { + return null; + } + + public final List parse(List elements) { + List methods = new ArrayList<>(); + methods.addAll(ElementFilter.methodsIn(elements)); + + List parsedMethods = new ArrayList<>(); + boolean valid = true; + int naturalOrder = 0; + for (ExecutableElement method : methods) { + if (!isParsable(method)) { + continue; + } + + Class annotationType = getAnnotationType(); + AnnotationMirror mirror = null; + if (annotationType != null) { + mirror = ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); + } + + E parsedMethod = parse(naturalOrder, method, mirror); + + if (method.getModifiers().contains(Modifier.PRIVATE) && parser.isEmitErrors()) { + parsedMethod.addError("Method annotated with @%s must not be private.", getAnnotationType().getSimpleName()); + parsedMethods.add(parsedMethod); + valid = false; + continue; + } + + if (parsedMethod != null) { + parsedMethods.add(parsedMethod); + } else { + valid = false; + } + naturalOrder++; + } + Collections.sort(parsedMethods); + + if (!valid && isParseNullOnError()) { + return null; + } + return parsedMethods; + } + + private E parse(int naturalOrder, ExecutableElement method, AnnotationMirror annotation) { + MethodSpec methodSpecification = createSpecification(method, annotation); + if (methodSpecification == null) { + return null; + } + + TemplateMethod templateMethod = parser.parse(methodSpecification, method, annotation, naturalOrder); + if (templateMethod != null) { + return create(templateMethod, templateMethod.hasErrors()); + } + return null; + } + + public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { + TemplateMethod method = parser.parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes); + if (method != null) { + return create(method, method.hasErrors()); + } + return null; + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLCheckVariableEqualityInstrument.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLCheckVariableEqualityInstrument.java Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.sl.test.instrument; - -import java.io.*; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.controlflow.*; -import com.oracle.truffle.sl.runtime.*; - -/** - * This sample instrument provides an example of a naive way to check if two numbers in SL are - * equivalent using their variable names. This instrument is designed to be attached to an - * {@link SLReturnNode}, but provides no guards ensuring this. - */ -public class SLCheckVariableEqualityInstrument extends Instrument { - - private final String varName1; - private final String varName2; - private final PrintStream output; - - /** - * Constructor - * - * @param varName1 The name of the first variable to compare - * @param varName2 The name of the second variable to compare - * @param output The {@link PrintStream} from the context used to print results. See - * {@link SLContext#getOutput()} for more info. - */ - public SLCheckVariableEqualityInstrument(String varName1, String varName2, PrintStream output) { - this.varName1 = varName1; - this.varName2 = varName2; - this.output = output; - } - - /** - * In the instrumentation test, this instrument is attached to a return statement. Since returns - * are handled via exceptions in Simple, we need to override the leaveExceptional method. This - * method does very limited error checking and simply prints "true" if the passed-in variables - * match or "false" if they do not. - */ - @Override - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - FrameSlot f1 = frame.getFrameDescriptor().findFrameSlot(varName1); - FrameSlot f2 = frame.getFrameDescriptor().findFrameSlot(varName2); - - if (f1 == null || f2 == null) - output.println("false"); - else { - try { - output.println(frame.getLong(f1) == frame.getLong(f2)); - } catch (FrameSlotTypeException e1) { - e1.printStackTrace(); - } - } - - } -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestNodeProber.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestNodeProber.java Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +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.truffle.sl.test.instrument; - -import static com.oracle.truffle.api.instrument.StandardSyntaxTag.*; - -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.nodes.controlflow.*; -import com.oracle.truffle.sl.nodes.instrument.*; -import com.oracle.truffle.sl.nodes.local.*; -import com.oracle.truffle.sl.runtime.*; - -/** - * This sample AST Node Prober for simple is used to instrument the nodes that we are interested in - * testing. This prober wraps return nodes and assignment nodes. For the purposes of this example, - * this is appropriate, but ideally there would be only one node prober responsible for - * instrumenting all the nodes of interest instead of a selective one like this one. - * - */ -public final class SLInstrumentTestNodeProber implements SLNodeProber { - private final SLContext slContext; - - public SLInstrumentTestNodeProber(SLContext slContext) { - this.slContext = slContext; - } - - /** - * Not implemented, only returns the astNode that was passed in. - */ - public Node probeAs(Node astNode, SyntaxTag tag, Object... args) { - // TODO dp: Currently does nothing in the general case - return astNode; - } - - /** - * If the passed in node is a {@link SLStatementWrapper}, then this simply tags it as a - * statement. If the passed in node is a {@link SLReturnNode}, then it is instrumented and - * tagged as a statement for testing. Only SLReturnNodes are wrapped. - */ - public SLStatementNode probeAsStatement(SLStatementNode node) { - assert node != null; - - SLStatementWrapper wrapper = null; - if (node instanceof SLStatementWrapper) { - wrapper = (SLStatementWrapper) node; - wrapper.tagAs(STATEMENT); - return wrapper; - } else if (node instanceof SLReturnNode) { - wrapper = new SLStatementWrapper(slContext, node); - wrapper.tagAs(STATEMENT); - return wrapper; - } - return node; - } - - /** - * Not implemented. Returns the passed in node. - */ - public SLExpressionNode probeAsCall(SLExpressionNode node, String callName) { - return node; - } - - /** - * If the passed in node is a {@link SLExpressionWrapper}, then this simply tags it as an - * assignment. If the passed in node is a {@link SLWriteLocalVariableNode}, then it is - * instrumented and tagged as a assignment for testing. Only SLWriteLocalVariableNode are - * wrapped. - */ - public SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName) { - assert node != null; - - SLExpressionWrapper wrapper = null; - if (node instanceof SLExpressionWrapper) { - wrapper = (SLExpressionWrapper) node; - wrapper.tagAs(ASSIGNMENT); - return wrapper; - } else if (node instanceof SLWriteLocalVariableNode) { - wrapper = new SLExpressionWrapper(slContext, node); - wrapper.tagAs(ASSIGNMENT); - return wrapper; - } - return node; - } - -} \ No newline at end of file diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Fri Aug 22 16:03:49 2014 +0200 @@ -37,12 +37,11 @@ import org.junit.runners.model.*; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.instrument.*; import com.oracle.truffle.sl.parser.*; import com.oracle.truffle.sl.runtime.*; -import com.oracle.truffle.sl.test.*; import com.oracle.truffle.sl.test.instrument.SLInstrumentTestRunner.InstrumentTestCase; /** @@ -58,8 +57,7 @@ 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 VISITOR_ASSIGNMENT_COUNT_SUFFIX = "_assnCount"; - private static final String VISITOR_VARIABLE_COMPARE_SUFFIX = "_varCompare"; + private static final String ASSIGNMENT_VALUE_SUFFIX = "_assnCount"; private static final String LF = System.getProperty("line.separator"); private static SLContext slContext; @@ -128,7 +126,8 @@ protected static List createTests(final Class c) throws IOException, InitializationError { SLInstrumentTestSuite suite = c.getAnnotation(SLInstrumentTestSuite.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())); + throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLInstrumentTestSuite.class.getSimpleName(), c.getName(), + SLInstrumentTestRunner.class.getSimpleName())); } String[] paths = suite.value(); @@ -200,57 +199,29 @@ PrintStream printer = new PrintStream(out); try { // We use the name of the file to determine what visitor to attach to it. - if (testCase.baseName.endsWith(VISITOR_ASSIGNMENT_COUNT_SUFFIX) || testCase.baseName.endsWith(VISITOR_VARIABLE_COMPARE_SUFFIX)) { - NodeVisitor nodeVisitor = null; + if (testCase.baseName.endsWith(ASSIGNMENT_VALUE_SUFFIX)) { + // Set up the execution context for Simple and register our two listeners slContext = new SLContext(new BufferedReader(new StringReader(testCase.testInput)), printer); - final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName); - SLASTProber prober = new SLASTProber(); - - // Note that the visitor looks for an attachment point via line number - if (testCase.baseName.endsWith(VISITOR_ASSIGNMENT_COUNT_SUFFIX)) { - nodeVisitor = new NodeVisitor() { - - public boolean visit(Node node) { - if (node instanceof SLExpressionWrapper) { - SLExpressionWrapper wrapper = (SLExpressionWrapper) node; - int lineNum = wrapper.getSourceSection().getLineLocation().getLineNumber(); - if (lineNum == 4) { - wrapper.getProbe().addInstrument(new SLPrintAssigmentValueInstrument(slContext.getOutput())); - } - } - return true; - } - }; - - // Note that the visitor looks for an attachment point via line number - } else if (testCase.baseName.endsWith(VISITOR_VARIABLE_COMPARE_SUFFIX)) { - nodeVisitor = new NodeVisitor() { - - public boolean visit(Node node) { - if (node instanceof SLStatementWrapper) { - SLStatementWrapper wrapper = (SLStatementWrapper) node; - int lineNum = wrapper.getSourceSection().getLineLocation().getLineNumber(); - - if (lineNum == 6) { - wrapper.getProbe().addInstrument(new SLCheckVariableEqualityInstrument("i", "count", slContext.getOutput())); - } - } - return true; - } - }; - } - - prober.addNodeProber(new SLInstrumentTestNodeProber(slContext)); - Parser.parseSL(slContext, source, prober); + final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName); + Parser.parseSL(slContext, source); List functionList = slContext.getFunctionRegistry().getFunctions(); // Since only functions can be global in SL, this guarantees that we instrument // everything of interest. Parsing must occur before accepting the visitors since - // parsing is what creates our instrumentation points. + // the visitor which creates our instrumentation points expects a complete AST. + for (SLFunction function : functionList) { RootCallTarget rootCallTarget = function.getCallTarget(); - rootCallTarget.getRootNode().accept(nodeVisitor); + rootCallTarget.getRootNode().accept(new SLInstrumenter(slContext)); + } + + // We iterate over all tags the SLInsturmenter tagged as assignments and attach our + // test instrument to those. + for (Probe probe : slContext.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) { + if (probe.isTaggedAs(StandardSyntaxTag.ASSIGNMENT)) { + probe.addInstrument(new SLPrintAssigmentValueInstrument(printer)); + } } SLFunction main = slContext.getFunctionRegistry().lookup("main"); @@ -272,7 +243,7 @@ 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); + SLInstrumentTestRunner suite = new SLInstrumentTestRunner(testClass); if (args.length > 0) { suite.filter(new NameFilter(args[0])); } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.output --- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.output Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.output Fri Aug 22 16:03:49 2014 +0200 @@ -1,3 +1,5 @@ +100 +0 1 2 3 diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.sl --- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.sl Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_assnCount.sl Fri Aug 22 16:03:49 2014 +0200 @@ -8,5 +8,4 @@ function main() { count = loop(100); - println(count); } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.output --- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.output Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -true -100 diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.sl --- a/graal/com.oracle.truffle.sl.test/tests_instrumentation/Instrumentation_varCompare.sl Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -function loop(count) { - i = 0; - while (i < count) { - i = i + 1; - } - return i; -} - -function main() { - count = loop(100); - println(count); -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Fri Aug 22 16:03:49 2014 +0200 @@ -152,7 +152,7 @@ if (sourceCallback != null) { sourceCallback.startLoading(source); } - Parser.parseSL(context, source, null); + Parser.parseSL(context, source); if (sourceCallback != null) { sourceCallback.endLoading(source); } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java Fri Aug 22 16:03:49 2014 +0200 @@ -50,6 +50,6 @@ private static void doDefineFunction(SLContext context, String code) { Source source = Source.fromText(code, "[defineFunction]"); /* The same parsing code as for parsing the initial source. */ - Parser.parseSL(context, source, null); + Parser.parseSL(context, source); } } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java Fri Aug 22 16:03:49 2014 +0200 @@ -29,8 +29,6 @@ public final class SLContextFactory { - private static SLASTProber astProber; - private SLContextFactory() { } @@ -39,12 +37,6 @@ final SLContext slContext = new SLContext(new BufferedReader(new InputStreamReader(System.in)), System.out); slContext.initialize(); slContext.setVisualizer(new SLDefaultVisualizer()); - astProber = new SLASTProber(); - slContext.setASTNodeProber(astProber); return slContext; } - - public static void addNodeProber(SLNodeProber nodeProber) { - astProber.addNodeProber(nodeProber); - } } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java Fri Aug 22 16:03:49 2014 +0200 @@ -24,10 +24,13 @@ 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.instrument.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; +import com.oracle.truffle.sl.nodes.instrument.*; import com.oracle.truffle.sl.runtime.*; /** @@ -87,4 +90,20 @@ public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException { return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame)); } + + @Override + public Probe probe(ExecutionContext context) { + Node parent = getParent(); + + if (parent == null) + throw new IllegalStateException("Cannot probe a node without a parent"); + + if (parent instanceof SLExpressionWrapper) + return ((SLExpressionWrapper) parent).getProbe(); + + SLExpressionWrapper wrapper = new SLExpressionWrapper((SLContext) context, this); + this.replace(wrapper); + wrapper.insertChild(); + return wrapper.getProbe(); + } } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java Fri Aug 22 16:03:49 2014 +0200 @@ -22,9 +22,13 @@ */ package com.oracle.truffle.sl.nodes; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; +import com.oracle.truffle.sl.nodes.instrument.*; +import com.oracle.truffle.sl.runtime.*; /** * The base class of all Truffle nodes for SL. All nodes (even expressions) can be used as @@ -32,7 +36,7 @@ * local variables. */ @NodeInfo(language = "Simple Language", description = "The abstract base node for all statements") -public abstract class SLStatementNode extends Node { +public abstract class SLStatementNode extends Node implements Instrumentable { public SLStatementNode(SourceSection src) { super(src); @@ -46,4 +50,20 @@ public SLStatementNode getNonWrapperNode() { return this; } + + @Override + public Probe probe(ExecutionContext context) { + Node parent = getParent(); + + if (parent == null) + throw new IllegalStateException("Cannot probe a node without a parent"); + + if (parent instanceof SLStatementWrapper) + return ((SLStatementWrapper) parent).getProbe(); + + SLStatementWrapper wrapper = new SLStatementWrapper((SLContext) context, this); + this.replace(wrapper); + wrapper.insertChild(); + return wrapper.getProbe(); + } } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Fri Aug 22 16:03:49 2014 +0200 @@ -48,11 +48,11 @@ /** * Profiling information, collected by the interpreter, capturing the profiling information of * the condition. This allows the compiler to generate better code for conditions that are - * always true or always false. Additionally the {@link IntegerConditionProfile} implementation - * (as opposed to {@link BooleanConditionProfile} implementation) transmits the probability of + * always true or always false. Additionally the {@link CountingConditionProfile} implementation + * (as opposed to {@link BinaryConditionProfile} implementation) transmits the probability of * the condition to be true to the compiler. */ - private final ConditionProfile condition = new IntegerConditionProfile(); + private final ConditionProfile condition = ConditionProfile.createCountingProfile(); public SLIfNode(SourceSection src, SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) { super(src); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTProber.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLASTProber.java Fri Aug 22 15:56:51 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +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.nodes.instrument; - -import java.util.*; - -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.*; - -/** - * SLASTProber contains the collection of {@link SLNodeProber}s and methods to attach the probers to - * nodes. - */ -public final class SLASTProber implements ASTProber, SLNodeProber { - - private ArrayList nodeProbers = new ArrayList<>(); - - public SLASTProber() { - } - - /** - * Adds a {@link SLNodeProber} to this SLASTProber. Probes must be of type {@link SLNodeProber} - * and must not already have been added. - * - * @param nodeProber the {@link SLNodeProber} to add. - */ - public void addNodeProber(ASTNodeProber nodeProber) { - if (nodeProber instanceof SLNodeProber) { - assert !nodeProbers.contains(nodeProber); - nodeProbers.add((SLNodeProber) nodeProber); - } else { - throw new IllegalArgumentException("invalid prober for SL implementation"); - } - } - - /** - * Unimplemented, does nothing. - */ - public Node probeAs(Node astNode, SyntaxTag tag, Object... args) { - return astNode; - } - - /** - * Attaches the current probers to the given {@link SLStatementNode} as a statement. - * - * @param node The {@link SLStatementNode} to attach the stored set of probers to. - */ - @Override - public SLStatementNode probeAsStatement(SLStatementNode node) { - SLStatementNode result = node; - for (SLNodeProber nodeProber : nodeProbers) { - result = nodeProber.probeAsStatement(result); - } - return result; - } - - /** - * Attaches the current probers to the given {@link SLExpressionNode} as a call. This will wrap - * the passed in node in an {@link SLExpressionWrapper}, tag it as a call and attach an - * instrument to it. - * - * @param node The {@link SLExpressionNode} to attach the stored set of probers to. - * @param callName The name of the call ??? - * - */ - @Override - public SLExpressionNode probeAsCall(SLExpressionNode node, String callName) { - SLExpressionNode result = node; - for (SLNodeProber nodeProber : nodeProbers) { - result = nodeProber.probeAsCall(node, callName); - } - return result; - } - - /** - * Attaches the current probers to the given {@link SLExpressionNode} as an assignment. This - * will wrap the passed in node in an {@link SLExpressionWrapper}, tag it as an assignment and - * attach an instrument to it. - * - * @param node The {@link SLExpressionNode} to attached the stored set of probers to. - * @param localName The name of the assignment ??? - * - */ - @Override - public SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName) { - SLExpressionNode result = node; - for (SLNodeProber nodeProber : nodeProbers) { - result = nodeProber.probeAsLocalAssignment(result, localName); - } - return result; - } - - public ASTNodeProber getCombinedNodeProber() { - return nodeProbers.isEmpty() ? null : this; - } - -} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java Fri Aug 22 16:03:49 2014 +0200 @@ -46,11 +46,19 @@ private final Probe probe; + /** + * Constructor. + * + * @param context The current Simple execution context + * @param child The {@link SLExpressionNode} that this wrapper is wrapping + */ public SLExpressionWrapper(SLContext context, SLExpressionNode child) { super(child.getSourceSection()); assert !(child instanceof SLExpressionWrapper); - this.child = insert(child); - this.probe = context.getProbe(child.getSourceSection()); + this.probe = context.createProbe(child.getSourceSection()); + this.child = child; + // The child should only be inserted after a replace, so we defer inserting the child to the + // creator of the wrapper. } @Override @@ -145,4 +153,11 @@ public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException { return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame)); } + + /** + * Sets the parent pointer of this wrapper's child. + */ + public void insertChild() { + insert(this.child); + } } diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLInstrumenter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLInstrumenter.java Fri Aug 22 16:03:49 2014 +0200 @@ -0,0 +1,80 @@ +/* + * 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.truffle.sl.nodes.instrument; + +import static com.oracle.truffle.api.instrument.StandardSyntaxTag.*; + +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.nodes.controlflow.*; +import com.oracle.truffle.sl.nodes.local.*; +import com.oracle.truffle.sl.runtime.*; + +/** + * This is a general purpose visitor which traverses a completely parsed Simple AST and instruments + * all the nodes within it. This visitor is designed to visit the tree immediately after it has been + * parsed. + * + */ +public class SLInstrumenter implements NodeVisitor { + + private final SLContext context; + + public SLInstrumenter(SLContext context) { + this.context = context; + } + + /** + * Instruments and tags all relevant {@link SLStatementNode}s and {@link SLExpressionNode}s. + * Currently, only SLStatementNodes that are not SLExpressionNodes are tagged as statements. + */ + public boolean visit(Node node) { + // We have to distinguish between SLExpressionNode and SLStatementNode since some of the + // generated factories have methods that require SLExpressionNodes as parameters. Since + // SLExpressionNodes are a subclass of SLStatementNode, we check if something is an + // SLExpressionNode first. + if (node instanceof SLExpressionNode && node.getParent() != null) { + SLExpressionNode expressionNode = (SLExpressionNode) node; + if (expressionNode.getSourceSection() != null) { + Probe probe = expressionNode.probe(context); + // probe.tagAs(STATEMENT); + + if (node instanceof SLWriteLocalVariableNode) + probe.tagAs(ASSIGNMENT); + } + } else if (node instanceof SLStatementNode && node.getParent() != null) { + + SLStatementNode statementNode = (SLStatementNode) node; + if (statementNode.getSourceSection() != null) { + Probe probe = statementNode.probe(context); + probe.tagAs(STATEMENT); + + if (node instanceof SLWhileNode) + probe.tagAs(START_LOOP); + } + } + + return true; + } +} diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java Fri Aug 22 16:03:49 2014 +0200 @@ -48,8 +48,10 @@ public SLStatementWrapper(SLContext context, SLStatementNode child) { super(child.getSourceSection()); assert !(child instanceof SLStatementWrapper); - this.child = insert(child); - this.probe = context.getProbe(child.getSourceSection()); + this.probe = context.createProbe(child.getSourceSection()); + this.child = child; + // The child should only be inserted after a replace, so we defer inserting the child to the + // creator of the wrapper. } @Override @@ -94,6 +96,12 @@ probe.leaveExceptional(child, frame, e); throw (e); } + } + /** + * Sets the parent pointer of this wrapper's child. + */ + public void insertChild() { + insert(this.child); } } diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame Fri Aug 22 16:03:49 2014 +0200 @@ -33,7 +33,6 @@ import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.nodes.instrument.*; import com.oracle.truffle.sl.runtime.*; // Checkstyle: stop @@ -52,9 +51,9 @@ public final Errors errors; private final SLNodeFactory factory; -->declarations - public Parser(SLContext context, Source source, SLNodeProber astProber) { + public Parser(SLContext context, Source source) { this.scanner = new Scanner(source.getInputStream()); - this.factory = new SLNodeFactory(context, source, astProber); + this.factory = new SLNodeFactory(context, source); errors = new Errors(); } @@ -135,8 +134,8 @@ -->initialization }; - public static void parseSL(SLContext context, Source source, SLNodeProber astProber) { - Parser parser = new Parser(context, source, astProber); + 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"); diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Fri Aug 22 16:03:49 2014 +0200 @@ -30,7 +30,6 @@ import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.nodes.instrument.*; import com.oracle.truffle.sl.runtime.*; // Checkstyle: stop @@ -53,10 +52,10 @@ public final Scanner scanner; public final Errors errors; private final SLNodeFactory factory; - - public Parser(SLContext context, Source source, SLNodeProber astProber) { + + public Parser(SLContext context, Source source) { this.scanner = new Scanner(source.getInputStream()); - this.factory = new SLNodeFactory(context, source, astProber); + this.factory = new SLNodeFactory(context, source); errors = new Errors(); } @@ -134,43 +133,43 @@ void Function() { Expect(4); Expect(1); - Token identifierToken = t; + Token identifierToken = t; Expect(5); - int bodyStartPos = t.charPos; - factory.startFunction(identifierToken, bodyStartPos); + int bodyStartPos = t.charPos; + factory.startFunction(identifierToken, bodyStartPos); if (la.kind == 1) { Get(); - factory.addFormalParameter(t); + factory.addFormalParameter(t); while (la.kind == 6) { Get(); Expect(1); - factory.addFormalParameter(t); + factory.addFormalParameter(t); } } Expect(7); SLStatementNode body = Block(false); - factory.finishFunction(body); + factory.finishFunction(body); } SLStatementNode Block(boolean inLoop) { SLStatementNode result; factory.startBlock(); - List body = new ArrayList<>(); + List body = new ArrayList<>(); Expect(8); - int start = t.charPos; + int start = t.charPos; while (StartOf(1)) { SLStatementNode s = Statement(inLoop); - body.add(s); + body.add(s); } Expect(9); - int length = (t.charPos + t.val.length()) - start; - result = factory.finishBlock(body, start, length); + int length = (t.charPos + t.val.length()) - start; + result = factory.finishBlock(body, start, length); return result; } SLStatementNode Statement(boolean inLoop) { SLStatementNode result; - result = null; + result = null; switch (la.kind) { case 13: { result = WhileStatement(); @@ -178,13 +177,13 @@ } case 10: { Get(); - if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } + 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"); } + if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } Expect(11); break; } @@ -209,29 +208,29 @@ SLStatementNode WhileStatement() { SLStatementNode result; Expect(13); - Token whileToken = t; + Token whileToken = t; Expect(5); SLExpressionNode condition = Expression(); Expect(7); SLStatementNode body = Block(true); - result = factory.createWhile(whileToken, condition, body); + result = factory.createWhile(whileToken, condition, body); return result; } SLStatementNode IfStatement(boolean inLoop) { SLStatementNode result; Expect(14); - Token ifToken = t; + Token ifToken = t; Expect(5); SLExpressionNode condition = Expression(); Expect(7); SLStatementNode thenPart = Block(inLoop); - SLStatementNode elsePart = null; + SLStatementNode elsePart = null; if (la.kind == 15) { Get(); elsePart = Block(inLoop); } - result = factory.createIf(ifToken, condition, thenPart, elsePart); + result = factory.createIf(ifToken, condition, thenPart, elsePart); return result; } @@ -239,11 +238,11 @@ SLStatementNode result; Expect(16); Token returnToken = t; - SLExpressionNode value = null; + SLExpressionNode value = null; if (StartOf(2)) { value = Expression(); } - result = factory.createReturn(returnToken, value); + result = factory.createReturn(returnToken, value); Expect(11); return result; } @@ -253,9 +252,9 @@ result = LogicTerm(); while (la.kind == 17) { Get(); - Token op = t; + Token op = t; SLExpressionNode right = LogicTerm(); - result = factory.createBinary(op, result, right); + result = factory.createBinary(op, result, right); } return result; } @@ -265,9 +264,9 @@ result = LogicFactor(); while (la.kind == 18) { Get(); - Token op = t; + Token op = t; SLExpressionNode right = LogicFactor(); - result = factory.createBinary(op, result, right); + result = factory.createBinary(op, result, right); } return result; } @@ -302,9 +301,9 @@ break; } } - Token op = t; + Token op = t; SLExpressionNode right = Arithmetic(); - result = factory.createBinary(op, result, right); + result = factory.createBinary(op, result, right); } return result; } @@ -318,9 +317,9 @@ } else { Get(); } - Token op = t; + Token op = t; SLExpressionNode right = Term(); - result = factory.createBinary(op, result, right); + result = factory.createBinary(op, result, right); } return result; } @@ -334,56 +333,56 @@ } else { Get(); } - Token op = t; + Token op = t; SLExpressionNode right = Factor(); - result = factory.createBinary(op, result, right); + result = factory.createBinary(op, result, right); } return result; } SLExpressionNode Factor() { SLExpressionNode result; - result = null; + result = null; if (la.kind == 1) { Get(); - Token nameToken = t; + Token nameToken = t; if (la.kind == 5) { Get(); List parameters = new ArrayList<>(); - SLExpressionNode parameter; + SLExpressionNode parameter; if (StartOf(2)) { parameter = Expression(); - parameters.add(parameter); + parameters.add(parameter); while (la.kind == 6) { Get(); parameter = Expression(); - parameters.add(parameter); + parameters.add(parameter); } } Expect(7); - Token finalToken = t; - result = factory.createCall(nameToken, parameters, finalToken); + Token finalToken = t; + result = factory.createCall(nameToken, parameters, finalToken); } else if (la.kind == 29) { Get(); SLExpressionNode value = Expression(); - result = factory.createAssignment(nameToken, value); + result = factory.createAssignment(nameToken, value); } else if (StartOf(4)) { - result = factory.createRead(nameToken); + result = factory.createRead(nameToken); } else SynErr(32); } else if (la.kind == 2) { Get(); - result = factory.createStringLiteral(t); + result = factory.createStringLiteral(t); } else if (la.kind == 3) { Get(); - result = factory.createNumericLiteral(t); + result = factory.createNumericLiteral(t); } else if (la.kind == 5) { Get(); - int start = t.charPos; + int start = t.charPos; result = Expression(); - SLExpressionNode expr = result; + SLExpressionNode expr = result; Expect(7); - int length = (t.charPos + t.val.length()) - start; - result = factory.createParenExpression(expr, start, length); + int length = (t.charPos + t.val.length()) - start; + result = factory.createParenExpression(expr, start, length); } else SynErr(33); return result; } @@ -408,8 +407,8 @@ }; - public static void parseSL(SLContext context, Source source, SLNodeProber astProber) { - Parser parser = new Parser(context, source, astProber); + 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"); diff -r f90dcdbbb75e -r 433ece7d941d graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Fri Aug 22 16:03:49 2014 +0200 @@ -32,7 +32,6 @@ 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.instrument.*; import com.oracle.truffle.sl.nodes.local.*; import com.oracle.truffle.sl.runtime.*; @@ -75,12 +74,9 @@ /* State while parsing a block. */ private LexicalScope lexicalScope; - private final SLNodeProber prober; - - public SLNodeFactory(SLContext context, Source source, SLNodeProber prober) { + public SLNodeFactory(SLContext context, Source source) { this.context = context; this.source = source; - this.prober = prober; } public void startFunction(Token nameToken, int bodyStartPos) { @@ -156,114 +152,69 @@ } /** - * Returns a {@link SLBreakNode} for the given token. This node will be instrumented, tagged as - * a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was - * initialized in this class. ({@link #prober} != null) + * Returns an {@link SLBreakNode} for the given token. * - * @param breakToken The token containing the break node's info - * @return either: - *
    - *
  • An un-instrumented SLBreakNode if there is no prober
  • - *
  • An {@link SLStatementWrapper} instrumenting this node.
  • - *
+ * @param breakToken The token containing the break node's info. + * @return A SLBreakNode for the given token. */ public SLStatementNode createBreak(Token breakToken) { final SLBreakNode breakNode = new SLBreakNode(srcFromToken(breakToken)); - if (prober != null) { - return prober.probeAsStatement(breakNode); - } return breakNode; } /** - * Returns a {@link SLContinueNode} for the given token. This node will be instrumented, tagged - * as a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was - * initialized in this class. ({@link #prober} != null) + * Returns an {@link SLContinueNode} for the given token. * - * @param continueToken The token containing the continue node's info - * @return either: - *
    - *
  • An un-instrumented SLContinueNode if there is no prober
  • - *
  • An {@link SLStatementWrapper} instrumenting this node.
  • - *
+ * @param continueToken The token containing the continue node's info. + * @return A SLContinueNode built using the given token. */ public SLStatementNode createContinue(Token continueToken) { final SLContinueNode continueNode = new SLContinueNode(srcFromToken(continueToken)); - if (prober != null) { - return prober.probeAsStatement(continueNode); - } return continueNode; } /** - * Returns a {@link SLWhileNode} for the given token. This node will be instrumented, tagged as - * a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was - * initialized in this class. ({@link #prober} != null) + * Returns an {@link SLWhileNode} for the given parameters. * * @param whileToken The token containing the while node's info * @param conditionNode The conditional node for this while loop * @param bodyNode The body of the while loop - * @return either: - *
    - *
  • An un-instrumented SLWhileNode if there is no prober
  • - *
  • An {@link SLStatementWrapper} instrumenting this node.
  • - *
+ * @return A SLWhileNode built using the given parameters. */ public SLStatementNode createWhile(Token whileToken, SLExpressionNode conditionNode, SLStatementNode bodyNode) { final int start = whileToken.charPos; final int end = bodyNode.getSourceSection().getCharEndIndex(); final SLWhileNode whileNode = new SLWhileNode(source.createSection(whileToken.val, start, end - start), conditionNode, bodyNode); - if (prober != null) { - return prober.probeAsStatement(whileNode); - } return whileNode; } /** - * Returns a {@link SLIfNode} for the given token. This node will be instrumented, tagged as a - * statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was - * initialized in this class. ({@link #prober} != null) + * Returns an {@link SLIfNode} for the given parameters. * * @param ifToken The token containing the if node's info * @param conditionNode The condition node of this if statement * @param thenPartNode The then part of the if * @param elsePartNode The else part of the if - * @return either: - *
    - *
  • An un-instrumented SLIfNode if there is no prober
  • - *
  • An {@link SLStatementWrapper} instrumenting this node.
  • - *
+ * @return An SLIfNode for the given parameters. */ public SLStatementNode createIf(Token ifToken, SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) { final int start = ifToken.charPos; final int end = elsePartNode == null ? thenPartNode.getSourceSection().getCharEndIndex() : elsePartNode.getSourceSection().getCharEndIndex(); final SLIfNode ifNode = new SLIfNode(source.createSection(ifToken.val, start, end - start), conditionNode, thenPartNode, elsePartNode); - if (prober != null) { - return prober.probeAsStatement(ifNode); - } return ifNode; } /** - * Returns a {@link SLReturnNode} for the given token. This node will be instrumented, tagged as - * a statement and wrapped in an {@link SLStatementWrapper} if an {@link SLASTProber} was - * initialized in this class. ({@link #prober} != null) + * Returns an {@link SLReturnNode} for the given parameters. * * @param t The token containing the return node's info * @param valueNode The value of the return - * @return either: - *
    - *
  • An un-instrumented SLReturnNode if there is no prober
  • - *
  • An {@link SLStatementWrapper} instrumenting this node.
  • - *
+ * @return An SLReturnNode for the given parameters. */ public SLStatementNode createReturn(Token t, SLExpressionNode valueNode) { final int start = t.charPos; final int length = valueNode == null ? t.val.length() : valueNode.getSourceSection().getCharEndIndex() - start; final SLReturnNode returnNode = new SLReturnNode(source.createSection(t.val, start, length), valueNode); - if (prober != null) { - return prober.probeAsStatement(returnNode); - } return returnNode; } @@ -274,7 +225,7 @@ * @param opToken The operator of the binary expression * @param leftNode The left node of the expression * @param rightNode The right node of the expression - * @return A subclass of SLExpressionNode for the operation given by opToken. + * @return A subclass of SLExpressionNode using the given parameters based on the given opToken. */ public SLExpressionNode createBinary(Token opToken, SLExpressionNode leftNode, SLExpressionNode rightNode) { int start = leftNode.getSourceSection().getCharIndex(); @@ -311,54 +262,33 @@ } /** - * Returns a {@link SLInvokeNode} for the given token. This node will be instrumented, tagged as - * a call and wrapped in an {@link SLExpressionWrapper} if an {@link SLASTProber} was - * initialized in this class. ({@link #prober} != null) + * Returns an {@link SLInvokeNode} for the given parameters. * * @param nameToken The name of the function being called * @param parameterNodes The parameters of the function call * @param finalToken A token used to determine the end of the sourceSelection for this call - * @return either: - *
    - *
  • An un-instrumented SLInvokeNode if there is no prober
  • - *
  • An {@link SLExpressionWrapper} instrumenting this node.
  • - *
+ * @return An SLInvokeNode for the given parameters. */ public SLExpressionNode createCall(Token nameToken, List parameterNodes, Token finalToken) { final int startPos = nameToken.charPos; final int endPos = finalToken.charPos + finalToken.val.length(); final SourceSection src = source.createSection(nameToken.val, startPos, endPos - startPos); SLExpressionNode functionNode = createRead(nameToken); - if (prober != null) { - SLExpressionNode wrappedNode = prober.probeAsCall(functionNode, nameToken.val); - return SLInvokeNode.create(src, wrappedNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()])); - } return SLInvokeNode.create(src, functionNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()])); } /** - * Returns a {@link SLWriteLocalVariableNode} for the given token. This node will be - * instrumented, tagged as an assignment and wrapped in an {@link SLExpressionWrapper} if an - * {@link SLASTProber} was initialized in this class. ({@link #prober} != null) + * Returns an {@link SLWriteLocalVariableNode} for the given parameters. * * @param nameToken The name of the variable being assigned * @param valueNode The value to be assigned - * @return either: - *
    - *
  • An un-instrumented SLWriteLocalVariableNode if there is no prober
  • - *
  • An {@link SLExpressionWrapper} instrumenting this node.
  • - *
+ * @return An SLExpressionNode for the given parameters. */ public SLExpressionNode createAssignment(Token nameToken, SLExpressionNode valueNode) { FrameSlot frameSlot = frameDescriptor.findOrAddFrameSlot(nameToken.val); lexicalScope.locals.put(nameToken.val, frameSlot); final int start = nameToken.charPos; final int length = valueNode.getSourceSection().getCharEndIndex() - start; - if (prober != null) { - SLWriteLocalVariableNode writeNode = SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), valueNode, frameSlot); - final SLExpressionNode wrappedNode = prober.probeAsLocalAssignment(writeNode, nameToken.val); - return wrappedNode; - } return SLWriteLocalVariableNodeFactory.create(source.createSection("=", start, length), valueNode, frameSlot); } diff -r f90dcdbbb75e -r 433ece7d941d 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 Fri Aug 22 15:56:51 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Fri Aug 22 16:03:49 2014 +0200 @@ -33,7 +33,6 @@ import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.builtins.*; import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.nodes.instrument.*; import com.oracle.truffle.sl.nodes.local.*; import com.oracle.truffle.sl.parser.*; @@ -52,7 +51,6 @@ private final PrintStream output; private final SLFunctionRegistry functionRegistry; private SourceCallback sourceCallback = null; - private SLASTProber astProber; public SLContext(BufferedReader input, PrintStream output) { this.input = input; @@ -154,7 +152,7 @@ sourceCallback.startLoading(source); } - Parser.parseSL(this, source, astProber); + Parser.parseSL(this, source); if (sourceCallback != null) { sourceCallback.endLoading(source); @@ -166,13 +164,4 @@ } main.getCallTarget().call(); } - - /** - * Sets the {@link SLASTProber} for the executeMain method. - * - * @param astProber The prober to use for adding instrumentation for this context. - */ - public void setASTNodeProber(SLASTProber astProber) { - this.astProber = astProber; - } } diff -r f90dcdbbb75e -r 433ece7d941d mx/mx_graal.py --- a/mx/mx_graal.py Fri Aug 22 15:56:51 2014 +0200 +++ b/mx/mx_graal.py Fri Aug 22 16:03:49 2014 +0200 @@ -459,10 +459,14 @@ _handle_missing_VM(build, vmToCheck if vmToCheck else 'graal') if installJars: - _installDistInJdks(mx.distribution('GRAAL')) - _installDistInJdks(mx.distribution('GRAAL_LOADER')) - _installDistInJdks(mx.distribution('TRUFFLE')) - _installDistInJdks(mx.distribution('GRAAL_TRUFFLE')) + def _installDistInJdksIfExists(dist): + if exists(dist.path): + _installDistInJdks(dist) + + _installDistInJdksIfExists(mx.distribution('GRAAL')) + _installDistInJdksIfExists(mx.distribution('GRAAL_LOADER')) + _installDistInJdksIfExists(mx.distribution('TRUFFLE')) + _installDistInJdksIfExists(mx.distribution('GRAAL_TRUFFLE')) if vmToCheck is not None: jvmCfg = _vmCfgInJdk(jdk) @@ -546,7 +550,7 @@ os.unlink(javaSource) os.unlink(javaClass) -def _copyToJdk(src, dst): +def _copyToJdk(src, dst, permissions=JDK_UNIX_PERMISSIONS_FILE): name = os.path.basename(src) dstLib = join(dst, name) if mx.get_env('SYMLINK_GRAAL_JAR', None) == 'true': @@ -556,17 +560,14 @@ if not os.path.islink(dstLib) or not os.path.realpath(dstLib) == src: if exists(dstLib): os.remove(dstLib) - os.symlink(src, dstLib) + os.symlink(src, dstLib) else: # do a copy and then a move to get atomic updating (on Unix) fd, tmp = tempfile.mkstemp(suffix='', prefix=name, dir=dst) shutil.copyfile(src, tmp) os.close(fd) shutil.move(tmp, dstLib) - os.chmod(dstLib, JDK_UNIX_PERMISSIONS_FILE) - -def _installDistInJdksExt(dist): - _installDistInJdks(dist, True) + os.chmod(dstLib, permissions) def _installDistInJdks(dist, ext=False): """ @@ -685,17 +686,19 @@ # extract latest release tag for graal try: tags = [x.split() for x in subprocess.check_output(['hg', '-R', _graal_home, 'tags']).split('\n') if x.startswith("graal-")] - current_revision = subprocess.check_output(['hg', '-R', _graal_home, 'id', '-i']).strip() + current_id = subprocess.check_output(['hg', '-R', _graal_home, 'log', '--template', '{rev}\n', '--rev', 'tip']).strip() except: # not a mercurial repository or hg commands are not available. tags = None - if tags and current_revision: + if tags and current_id: sorted_tags = sorted(tags, key=lambda e: [int(x) for x in e[0][len("graal-"):].split('.')], reverse=True) most_recent_tag_name, most_recent_tag_revision = sorted_tags[0] + most_recent_tag_id = most_recent_tag_revision[:most_recent_tag_revision.index(":")] most_recent_tag_version = most_recent_tag_name[len("graal-"):] - if current_revision == most_recent_tag_revision: + # tagged commit is one-off with commit that tags it + if int(current_id) - int(most_recent_tag_id) <= 1: cached_graal_version = most_recent_tag_version else: major, minor = map(int, most_recent_tag_version.split('.')) @@ -771,7 +774,7 @@ if build is None or len(build) == 0: continue - jdk = _jdk(build, create=True, installJars=not opts2.java) + jdk = _jdk(build, create=True, installJars=vm != 'original' and not opts2.java) if vm == 'original': if build != 'product': @@ -987,6 +990,10 @@ 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)) + if vm == 'original': + truffle_jar = mx.archive(['@TRUFFLE'])[0] + args = ['-Xbootclasspath/p:' + truffle_jar] + args + args = mx.java().processArgs(args) return (pfx, exe, vm, args, cwd) diff -r f90dcdbbb75e -r 433ece7d941d mx/projects --- a/mx/projects Fri Aug 22 15:56:51 2014 +0200 +++ b/mx/projects Fri Aug 22 16:03:49 2014 +0200 @@ -128,14 +128,14 @@ project@com.oracle.nfi@sourceDirs=src project@com.oracle.nfi@dependencies= project@com.oracle.nfi@checkstyle=com.oracle.graal.graph -project@com.oracle.nfi@javaCompliance=1.8 +project@com.oracle.nfi@javaCompliance=1.7 # nfi.test project@com.oracle.nfi.test@subDir=graal project@com.oracle.nfi.test@sourceDirs=test project@com.oracle.nfi.test@dependencies=com.oracle.nfi,com.oracle.graal.compiler.common,JUNIT project@com.oracle.nfi.test@checkstyle=com.oracle.graal.graph -project@com.oracle.nfi.test@javaCompliance=1.8 +project@com.oracle.nfi.test@javaCompliance=1.7 # graal.api.collections project@com.oracle.graal.api.collections@subDir=graal diff -r f90dcdbbb75e -r 433ece7d941d mxtool/mx.py --- a/mxtool/mx.py Fri Aug 22 15:56:51 2014 +0200 +++ b/mxtool/mx.py Fri Aug 22 16:03:49 2014 +0200 @@ -2516,9 +2516,10 @@ log('Compiling {} failed'.format(t.proj.name)) abort('{} Java compilation tasks failed'.format(len(failed))) - for dist in sorted_dists(): - if dist not in updatedAnnotationProcessorDists: - archive(['@' + dist.name]) + if args.java: + for dist in sorted_dists(): + if dist not in updatedAnnotationProcessorDists: + archive(['@' + dist.name]) if suppliedParser: return args diff -r f90dcdbbb75e -r 433ece7d941d src/gpu/hsail/vm/gpu_hsail.cpp --- a/src/gpu/hsail/vm/gpu_hsail.cpp Fri Aug 22 15:56:51 2014 +0200 +++ b/src/gpu/hsail/vm/gpu_hsail.cpp Fri Aug 22 16:03:49 2014 +0200 @@ -140,6 +140,8 @@ jint num_tlabs, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS) { ResourceMark rm(THREAD); objArrayOop argsArray = (objArrayOop) JNIHandles::resolve(args); + // Note this length does not include the iteration variable since it is replaced by the HSA workitemid + int argsArrayLength = argsArray->length(); assert(THREAD->is_Java_thread(), "must be a JavaThread"); // We avoid HSAILAllocationInfo logic if kernel does not allocate @@ -296,7 +298,8 @@ KlassHandle methKlass = mh->method_holder(); Thread* THREAD = Thread::current(); JavaValue result(T_VOID); - JavaCallArguments javaArgs; + // Add the iteration variable to the HSA args length + JavaCallArguments javaArgs(argsArrayLength + 1); // re-resolve the args_handle here objArrayOop resolvedArgsArray = (objArrayOop) JNIHandles::resolve(args); @@ -344,8 +347,11 @@ // The kernel entrypoint is always run for the time being const char* entryPointName = "&run"; jlong okra_kernel; - jint okra_status = _okra_create_kernel(_device_context, code, entryPointName, (void**)&okra_kernel); - guarantee(okra_status==0, "_okra_create_kernel failed"); + { + TraceTime t("generate kernel ", TraceGPUInteraction); + jint okra_status = _okra_create_kernel(_device_context, code, entryPointName, (void**)&okra_kernel); + guarantee(okra_status==0, "_okra_create_kernel failed"); + } return (jlong) okra_kernel; GPU_END diff -r f90dcdbbb75e -r 433ece7d941d src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSlider.java --- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSlider.java Fri Aug 22 15:56:51 2014 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSlider.java Fri Aug 22 16:03:49 2014 +0200 @@ -283,8 +283,8 @@ @Override public void mouseDragged(MouseEvent e) { - // Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1); - // scrollRectToVisible(r); + Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1); + scrollRectToVisible(r); if (state == State.DragBar) { float firstX = this.getStartXPosition(model.getFirstPosition()); diff -r f90dcdbbb75e -r 433ece7d941d src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Fri Aug 22 15:56:51 2014 +0200 +++ b/src/share/vm/graal/graalRuntime.cpp Fri Aug 22 16:03:49 2014 +0200 @@ -487,7 +487,7 @@ } JRT_END -JRT_ENTRY(void, GraalRuntime::log_object(JavaThread* thread, oopDesc* obj, jint flags)) +JRT_LEAF(void, GraalRuntime::log_object(JavaThread* thread, oopDesc* obj, jint flags)) bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); bool addr = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); @@ -600,7 +600,7 @@ } JRT_END -JRT_ENTRY(void, GraalRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) +JRT_LEAF(void, GraalRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) union { jlong l; jdouble d; @@ -728,7 +728,8 @@ JVM_ENTRY(jboolean, JVM_ParseGraalOptions(JNIEnv *env, jclass c)) HandleMark hm; KlassHandle hotSpotOptionsClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c))); - return GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK_false); + bool result = GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK_false); + return result; JVM_END jint GraalRuntime::check_arguments(TRAPS) { @@ -774,7 +775,7 @@ return CITime || CITimeEach; } -void GraalRuntime::check_required_value(const char* name, int name_len, const char* value, TRAPS) { +void GraalRuntime::check_required_value(const char* name, size_t name_len, const char* value, TRAPS) { if (value == NULL) { char buf[200]; jio_snprintf(buf, sizeof(buf), "Must use '-G:%.*s=' format for %.*s option", name_len, name, name_len, name); @@ -790,7 +791,7 @@ if (first == '+' || first == '-') { name = arg + 1; name_len = strlen(name); - recognized = set_option(hotSpotOptionsClass, name, (int)name_len, arg, CHECK); + recognized = set_option_bool(hotSpotOptionsClass, name, name_len, first, CHECK); } else { char* sep = strchr(arg, '='); name = arg; @@ -801,13 +802,13 @@ } else { name_len = strlen(name); } - recognized = set_option(hotSpotOptionsClass, name, (int)name_len, value, CHECK); + recognized = set_option(hotSpotOptionsClass, name, name_len, value, CHECK); } if (!recognized) { bool throw_err = hotSpotOptionsClass.is_null(); if (!hotSpotOptionsClass.is_null()) { - set_option_helper(hotSpotOptionsClass, name, (int)name_len, Handle(), ' ', Handle(), 0L); + set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), ' ', Handle(), 0L); if (!HAS_PENDING_EXCEPTION) { throw_err = true; } @@ -823,7 +824,7 @@ void GraalRuntime::parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS) { const char* home = Arguments::get_java_home(); - int path_len = (int)strlen(home) + (int)strlen("/lib/graal.options") + 1; + size_t path_len = strlen(home) + strlen("/lib/graal.options") + 1; char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len); char sep = os::file_separator()[0]; sprintf(path, "%s%clib%cgraal.options", home, sep, sep); @@ -868,7 +869,7 @@ } } -jlong GraalRuntime::parse_primitive_option_value(char spec, const char* name, int name_len, const char* value, TRAPS) { +jlong GraalRuntime::parse_primitive_option_value(char spec, const char* name, size_t name_len, const char* value, TRAPS) { check_required_value(name, name_len, value, CHECK_(0L)); union { jint i; @@ -905,11 +906,11 @@ THROW_MSG_(vmSymbols::java_lang_InternalError(), buf, 0L); } -void GraalRuntime::set_option_helper(KlassHandle hotSpotOptionsClass, char* name, int name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) { +void GraalRuntime::set_option_helper(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) { Thread* THREAD = Thread::current(); Handle name_handle; if (name != NULL) { - if ((int) strlen(name) > name_len) { + if (strlen(name) > name_len) { // Temporarily replace '=' with NULL to create the Java string for the option name char save = name[name_len]; name[name_len] = '\0'; @@ -919,7 +920,7 @@ return; } } else { - assert((int) strlen(name) == name_len, "must be"); + assert(strlen(name) == name_len, "must be"); name_handle = java_lang_String::create_from_str(name, CHECK); } } diff -r f90dcdbbb75e -r 433ece7d941d src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Fri Aug 22 15:56:51 2014 +0200 +++ b/src/share/vm/graal/graalRuntime.hpp Fri Aug 22 16:03:49 2014 +0200 @@ -52,7 +52,7 @@ * @param value string value to parse * @throws InternalError if value could not be parsed according to spec */ - static jlong parse_primitive_option_value(char spec, const char* name, int name_len, const char* value, TRAPS); + static jlong parse_primitive_option_value(char spec, const char* name, size_t name_len, const char* value, TRAPS); /** * Loads default option value overrides from a /lib/graal.options if it exists. Each @@ -70,6 +70,21 @@ static void parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS); /** + * Searches for a Boolean Graal option denoted by a given name and sets it value. + * + * The definition of this method is in graalRuntime.inline.hpp + * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp. + * + * @param hotSpotOptionsClass the HotSpotOptions klass or NULL if only checking for valid option + * @param name option name + * @param name_len length of option name + * @param value '+' to set the option, '-' to reset the option + * @returns true if the option was found + * @throws InternalError if there was a problem setting the option's value + */ + static bool set_option_bool(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, char value, TRAPS); + + /** * Searches for a Graal option denoted by a given name and sets it value. * * The definition of this method is in graalRuntime.inline.hpp @@ -81,12 +96,12 @@ * @returns true if the option was found * @throws InternalError if there was a problem setting the option's value */ - static bool set_option(KlassHandle hotSpotOptionsClass, char* name, int name_len, const char* value, TRAPS); + static bool set_option(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, const char* value, TRAPS); /** * Raises an InternalError for an option that expects a value but was specified without a "=" prefix. */ - static void check_required_value(const char* name, int name_len, const char* value, TRAPS); + static void check_required_value(const char* name, size_t name_len, const char* value, TRAPS); /** * Java call to HotSpotOptions.setOption(String name, OptionValue option, char spec, String stringValue, long primitiveValue) @@ -94,7 +109,7 @@ * @param name option name * @param name_len length of option name */ - static void set_option_helper(KlassHandle hotSpotOptionsClass, char* name, int name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue); + static void set_option_helper(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue); /** * Instantiates a service object, calls its default constructor and returns it. diff -r f90dcdbbb75e -r 433ece7d941d src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Fri Aug 22 15:56:51 2014 +0200 +++ b/src/share/vm/runtime/os.cpp Fri Aug 22 16:03:49 2014 +0200 @@ -1269,6 +1269,8 @@ #endif #ifdef GRAAL "%/lib/graal-loader.jar:" +#endif +#ifndef NO_TRUFFLE_JAR "%/lib/truffle.jar:" #endif "%/classes";