*
*
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java
--- a/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java Sat Jul 18 18:03:36 2015 +0200
@@ -61,12 +61,12 @@
*
* {@literal @}TypeSystem(types = {boolean.class, int.class, double.class})
* public abstract class ExampleTypeSystem {
- *
+ *
* {@literal @}TypeCheck
* public boolean isInteger(Object value) {
* return value instanceof Integer || value instanceof Double;
* }
- *
+ *
* {@literal @}TypeCast
* public double asInteger(Object value) {
* return ((Number)value).doubleValue();
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java Sat Jul 18 18:03:36 2015 +0200
@@ -38,7 +38,7 @@
static final FrameDescriptor UNUSED_FRAMEDESCRIPTOR = new FrameDescriptor();
@Override
- protected Object invoke(Object symbol, Object... arr) throws IOException {
+ protected Object invoke(TruffleLanguage lang, Object symbol, Object... arr) throws IOException {
if (symbol instanceof String) {
return symbol;
}
@@ -49,7 +49,7 @@
return symbol;
}
Node executeMain = Message.createExecute(arr.length).createNode();
- CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(executeMain, (TruffleObject) symbol, arr));
+ CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, executeMain, (TruffleObject) symbol, arr));
VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(arr, UNUSED_FRAMEDESCRIPTOR);
Object ret = callTarget.call(frame);
if (ret instanceof TruffleObject) {
@@ -57,20 +57,20 @@
Object isBoxedResult;
try {
Node isBoxed = Message.IS_BOXED.createNode();
- CallTarget isBoxedTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(isBoxed, tret));
+ CallTarget isBoxedTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, isBoxed, tret));
isBoxedResult = isBoxedTarget.call(frame);
} catch (IllegalArgumentException ex) {
isBoxedResult = false;
}
if (Boolean.TRUE.equals(isBoxedResult)) {
Node unbox = Message.UNBOX.createNode();
- CallTarget unboxTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(unbox, tret));
+ CallTarget unboxTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, unbox, tret));
Object unboxResult = unboxTarget.call(frame);
return unboxResult;
} else {
try {
Node isNull = Message.IS_NULL.createNode();
- CallTarget isNullTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(isNull, tret));
+ CallTarget isNullTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, isNull, tret));
Object isNullResult = isNullTarget.call(frame);
if (Boolean.TRUE.equals(isNullResult)) {
return null;
@@ -88,7 +88,8 @@
private final TruffleObject function;
private final Object[] args;
- public TemporaryRoot(Node foreignAccess, TruffleObject function, Object... args) {
+ public TemporaryRoot(TruffleLanguage lang, Node foreignAccess, TruffleObject function, Object... args) {
+ super(lang.getClass(), null, null);
this.foreignAccess = foreignAccess;
this.function = function;
this.args = args;
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/package-info.java
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/package-info.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/package-info.java Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 free software; you can redistribute 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
+ * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version 2 along with this work;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
*
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com
+ * if you need additional information or have any questions.
*/
/**
@@ -28,15 +25,15 @@
* {@link com.oracle.truffle.api.TruffleLanguage Truffle languages}.
*
* Languages can exchange primitive Java type wrapper objects (e.g., {@link java.lang.Integer},
- * {@link java.lang.Double}, {@link java.lang.String}, etc) as well as any type
- * implementing {@link com.oracle.truffle.api.interop.TruffleObject}. Foreign objects are
- * precisely those implementing {@link com.oracle.truffle.api.interop.TruffleObject}.
+ * {@link java.lang.Double}, {@link java.lang.String}, etc) as well as any type implementing
+ * {@link com.oracle.truffle.api.interop.TruffleObject}. Foreign objects are precisely those
+ * implementing {@link com.oracle.truffle.api.interop.TruffleObject}.
*
- * To use a {@link com.oracle.truffle.api.interop.TruffleObject} from a different language,
- * you need to ask the language to build appropriate AST for a given
+ * To use a {@link com.oracle.truffle.api.interop.TruffleObject} from a different language, you need
+ * to ask the language to build appropriate AST for a given
* {@link com.oracle.truffle.api.interop.Message} with
- * {@link com.oracle.truffle.api.interop.Message#createNode}. The message can then
- * be executed with {@link com.oracle.truffle.api.interop.ForeignAccess#execute}.
+ * {@link com.oracle.truffle.api.interop.Message#createNode}. The message can then be executed with
+ * {@link com.oracle.truffle.api.interop.ForeignAccess#execute}.
*/
package com.oracle.truffle.api.interop;
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -65,7 +65,7 @@
@Children private final TestArgumentNode[] children;
TestRootNode(TestArgumentNode[] children) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.children = children;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -60,7 +60,7 @@
private final CallTarget secondTarget;
DualCallNode(CallTarget firstTarget, CallTarget secondTarget) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.firstTarget = firstTarget;
this.secondTarget = secondTarget;
}
@@ -76,7 +76,7 @@
private final int value;
public ConstantRootNode(int value) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.value = value;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -76,7 +76,7 @@
@Child private TestChildNode right;
public TestRootNode(TestChildNode left, TestChildNode right) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.left = left;
this.right = right;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -71,7 +71,7 @@
@Children private final TestChildNode[] children;
public TestRootNode(TestChildNode[] children) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.children = children;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -65,7 +65,7 @@
@Children private final TestChildNode[] children;
public TestRootNode(TestChildNode[] children) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.children = children;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -63,7 +63,7 @@
@Child TestChildNode right;
public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
- super(null, descriptor);
+ super(TestingLanguage.class, null, descriptor);
this.left = left;
this.right = right;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -87,7 +87,7 @@
@Child TestChildNode right;
public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
- super(null, descriptor);
+ super(TestingLanguage.class, null, descriptor);
this.left = left;
this.right = right;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InterfaceChildFieldTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InterfaceChildFieldTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InterfaceChildFieldTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -81,7 +81,7 @@
@Child private TestChildInterface child;
public TestRootNode(TestChildInterface child) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.child = child;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -84,7 +84,7 @@
@Children private final ValueNode[] children;
public TestRootNode(ValueNode[] children) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.children = children;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -62,7 +62,7 @@
@Child TestChildNode right;
public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
- super(null, descriptor);
+ super(TestingLanguage.class, null, descriptor);
this.left = left;
this.right = right;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -60,7 +60,7 @@
class TestRootNode extends RootNode {
public TestRootNode() {
- super(null);
+ super(TestingLanguage.class, null, null);
}
@Override
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 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;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.debug.DebugSupportProvider;
+import com.oracle.truffle.api.instrument.ToolSupportProvider;
+import com.oracle.truffle.api.source.Source;
+import java.io.IOException;
+
+public final class TestingLanguage extends TruffleLanguage {
+ public static final TruffleLanguage INSTANCE = new TestingLanguage();
+
+ private TestingLanguage() {
+ super(null);
+ }
+
+ @Override
+ protected Object eval(Source code) throws IOException {
+ throw new IOException();
+ }
+
+ @Override
+ protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+ return null;
+ }
+
+ @Override
+ protected Object getLanguageGlobal() {
+ return null;
+ }
+
+ @Override
+ protected boolean isObjectOfLanguage(Object object) {
+ return false;
+ }
+
+ @Override
+ protected ToolSupportProvider getToolSupport() {
+ return null;
+ }
+
+ @Override
+ protected DebugSupportProvider getDebugSupport() {
+ return null;
+ }
+
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -84,7 +84,7 @@
@Child private ValueNode child;
public TestRootNode(ValueNode child) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.child = child;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -59,7 +59,7 @@
}
private static RootNode createTestRootNode() {
- return new RootNode() {
+ return new RootNode(TestingLanguage.class, null, null) {
@Override
public Object execute(VirtualFrame frame) {
return 42;
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Sat Jul 18 18:03:36 2015 +0200
@@ -27,6 +27,7 @@
import com.oracle.truffle.api.instrument.*;
import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.TestingLanguage;
/**
* Tests instrumentation where a client can attach a node that gets attached into the AST.
@@ -147,7 +148,7 @@
* tests run in the same environment.
*/
public TestRootNode(TestLanguageNode body) {
- super(null);
+ super(TestingLanguage.class, null, null);
this.body = body;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/NodeUtilTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/NodeUtilTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/NodeUtilTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -31,6 +31,7 @@
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.TestingLanguage;
public class NodeUtilTest {
@@ -84,6 +85,10 @@
private int visited;
+ public TestRootNode() {
+ super(TestingLanguage.class, null, null);
+ }
+
@Override
public Object execute(VirtualFrame frame) {
return null;
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java Sat Jul 18 18:03:36 2015 +0200
@@ -28,6 +28,7 @@
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.TestingLanguage;
/**
* Tests optional method for ensuring that a node replacement is type safe. Ordinary node
@@ -81,6 +82,10 @@
private int executed;
+ public TestRootNode() {
+ super(TestingLanguage.class, null, null);
+ }
+
@Override
public Object execute(VirtualFrame frame) {
executed++;
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java Sat Jul 18 18:03:36 2015 +0200
@@ -1,50 +1,62 @@
/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 free software; you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 only, as published by the Free Software Foundation.
*
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
+ * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version 2 along with this work;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
*
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com
+ * if you need additional information or have any questions.
*/
/**
- *
This package contains basic tests of the Truffle API and serves at the same
- * time as an introduction to the Truffle API for language implementors. Every test gives an example on how to use the construct explained in the class description.
+ *
+ * This package contains basic tests of the Truffle API and serves at the same time as an
+ * introduction to the Truffle API for language implementors. Every test gives an example on how to
+ * use the construct explained in the class description.
+ *
*
*
- * Truffle is a language implementation framework. A guest language method is represented as a tree of executable nodes.
- * The framework provides mechanisms for those trees to call each other. Additionally it contains dedicated data structures for storing data local to a tree invocation.
+ * Truffle is a language implementation framework. A guest language method is represented as a tree
+ * of executable nodes. The framework provides mechanisms for those trees to call each other.
+ * Additionally it contains dedicated data structures for storing data local to a tree invocation.
*
*
*
* This introduction to Truffle contains items in the following recommended order:
*
*
- *
How to get access to the Truffle runtime? {@link com.oracle.truffle.api.test.TruffleRuntimeTest}
+ *
How to get access to the Truffle runtime?
+ * {@link com.oracle.truffle.api.test.TruffleRuntimeTest}
*
How to create a root node? {@link com.oracle.truffle.api.test.RootNodeTest}
- *
How to create a child node and link it with its parent? {@link com.oracle.truffle.api.test.ChildNodeTest}
- *
How to create an array of child nodes? {@link com.oracle.truffle.api.test.ChildrenNodesTest}
- *
Why are final fields in node classes important? {@link com.oracle.truffle.api.test.FinalFieldTest}
- *
How to replace one node with another node and what for? {@link com.oracle.truffle.api.test.ReplaceTest}
- *
How to let one Truffle tree invoke another one? {@link com.oracle.truffle.api.test.CallTest}
- *
How to pass arguments when executing a tree? {@link com.oracle.truffle.api.test.ArgumentsTest}
- *
How to use frames and frame slots to store values local to an activation? {@link com.oracle.truffle.api.test.FrameTest}
- *
How to use type specialization and speculation for frame slots? {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}
- *
How to use type specialization and speculation for node return values? {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}
- *
How to "instrument" an AST with nodes that can provide access to runtime state from external tools {@code com.oracle.truffle.api.test.instrument.InstrumentationTest}
+ *
How to create a child node and link it with its parent?
+ * {@link com.oracle.truffle.api.test.ChildNodeTest}
+ *
How to create an array of child nodes? {@link com.oracle.truffle.api.test.ChildrenNodesTest}
+ *
+ *
Why are final fields in node classes important?
+ * {@link com.oracle.truffle.api.test.FinalFieldTest}
+ *
How to replace one node with another node and what for?
+ * {@link com.oracle.truffle.api.test.ReplaceTest}
+ *
How to let one Truffle tree invoke another one? {@link com.oracle.truffle.api.test.CallTest}
+ *
+ *
How to pass arguments when executing a tree?
+ * {@link com.oracle.truffle.api.test.ArgumentsTest}
+ *
How to use frames and frame slots to store values local to an activation?
+ * {@link com.oracle.truffle.api.test.FrameTest}
+ *
How to use type specialization and speculation for frame slots?
+ * {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}
+ *
How to use type specialization and speculation for node return values?
+ * {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}
+ *
How to "instrument" an AST with nodes that can provide access to runtime state from external
+ * tools {@code com.oracle.truffle.api.test.instrument.InstrumentationTest}
*
*
*
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.source.*;
+import java.io.IOException;
+
+public abstract class Breakpoint {
+
+ /**
+ * A general model of the states occupied by a breakpoint during its lifetime.
+ */
+ public enum State {
+
+ /**
+ * Not attached, enabled.
+ *
+ * Created for a source location but not yet attached: perhaps just created and the source
+ * hasn't been loaded yet; perhaps source has been loaded, but the line location isn't
+ * probed so a breakpoint cannot be attached. Can be either enabled or disabled.
+ */
+ ENABLED_UNRESOLVED("Enabled/Unresolved"),
+
+ /**
+ * Not attached, disabled.
+ *
+ * Created for a source location but not yet attached: perhaps just created and the source
+ * hasn't been loaded yet; perhaps source has been loaded, but the line location isn't
+ * probed so a breakpoint cannot be attached.
+ */
+ DISABLED_UNRESOLVED("Disabled/Unresolved"),
+
+ /**
+ * Attached, instrument enabled.
+ *
+ * Is currently implemented by some {@link Instrument}, which is attached to a {@link Probe}
+ * at a specific node in the AST, and the breakpoint is enabled.
+ */
+ ENABLED("Enabled"),
+
+ /**
+ * Attached, instrument disabled.
+ *
+ * Is currently implemented by some {@link Instrument}, which is attached to a {@link Probe}
+ * at a specific node in the AST, and the breakpoint is disabled.
+ */
+ DISABLED("Disabled"),
+
+ /**
+ * Not attached, instrument is permanently disabled.
+ */
+ DISPOSED("Disposed");
+
+ private final String name;
+
+ State(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ }
+
+ private final boolean isOneShot;
+
+ private int ignoreCount;
+
+ private int hitCount;
+
+ private State state;
+
+ Breakpoint(State state, int ignoreCount, boolean isOneShot) {
+ this.state = state;
+ this.isOneShot = isOneShot;
+ this.ignoreCount = ignoreCount;
+ }
+
+ /**
+ * Enables or disables this breakpoint's AST instrumentation. The breakpoint is enabled by
+ * default.
+ *
+ * @param enabled true to activate the instrumentation, false to
+ * deactivate the instrumentation so that it has no effect.
+ */
+ public abstract void setEnabled(boolean enabled);
+
+ /**
+ * Is this breakpoint active?
+ */
+ public abstract boolean isEnabled();
+
+ /**
+ * Sets the condition on this breakpoint, {@code null} to make it unconditional.
+ *
+ * @param expr if non{@code -null}, a boolean expression, expressed in the guest language, to be
+ * evaluated in the lexical context at the breakpoint location.
+ * @throws IOException if condition is invalid
+ * @throws UnsupportedOperationException if the breakpoint does not support conditions
+ */
+ public abstract void setCondition(String expr) throws IOException;
+
+ /**
+ * Gets the string, expressed in the Guest Language, that defines the current condition on this
+ * breakpoint; {@code null} if this breakpoint is currently unconditional.
+ */
+ public String getCondition() {
+ return null;
+ }
+
+ /**
+ * Does this breakpoint remove itself after first activation?
+ */
+ public final boolean isOneShot() {
+ return isOneShot;
+ }
+
+ /**
+ * Gets the number of hits left to be ignored before halting.
+ */
+ public final int getIgnoreCount() {
+ return ignoreCount;
+ }
+
+ /**
+ * Change the threshold for when this breakpoint should start causing a break. When both an
+ * ignore count and a {@linkplain #setCondition(String) condition} are specified, the condition
+ * is evaluated first: if {@code false} it is not considered to be a hit. In other words, the
+ * ignore count is for successful conditions only.
+ */
+ public final void setIgnoreCount(int ignoreCount) {
+ this.ignoreCount = ignoreCount;
+ }
+
+ /**
+ * Number of times this breakpoint has reached, with one exception; if the breakpoint has a
+ * condition that evaluates to {@code false}, it does not count as a hit.
+ */
+ public final int getHitCount() {
+ return hitCount;
+ }
+
+ /**
+ * Disables this breakpoint and removes any associated instrumentation; it becomes permanently
+ * inert.
+ */
+ public abstract void dispose();
+
+ /**
+ * Gets a human-sensible description of this breakpoint's location in a {@link Source}.
+ */
+ public abstract String getLocationDescription();
+
+ public final State getState() {
+ return state;
+ }
+
+ final void assertState(State s) {
+ assert state == s;
+ }
+
+ final void setState(State state) {
+ this.state = state;
+ }
+
+ /**
+ * Assumes that all conditions for causing the break have been satisfied, so increments the
+ * hit count. Then checks if the ignore count has been exceeded, and if so
+ * returns {@code true}. If not, it still counts as a hit but should be ignored.
+ *
+ * @return whether to proceed
+ */
+ final boolean incrHitCountCheckIgnore() {
+ return ++hitCount > ignoreCount;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+ sb.append(" state=");
+ sb.append(getState() == null ? "" : getState().getName());
+ if (isOneShot()) {
+ sb.append(", " + "One-Shot");
+ }
+ if (getCondition() != null) {
+ sb.append(", condition=\"" + getCondition() + "\"");
+ }
+ return sb.toString();
+ }
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugSupportProvider.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugSupportProvider.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugSupportProvider.java Sat Jul 18 18:03:36 2015 +0200
@@ -33,15 +33,6 @@
* Access to language-specific information and execution services to enable debugging.
*/
public interface DebugSupportProvider extends ToolSupportProvider {
-
- /**
- * Runs source code.
- *
- * @param source code
- * @throws DebugSupportException if unable to run successfully
- */
- void run(Source source) throws DebugSupportException;
-
/**
* Runs source code in a halted execution context, or at top level.
*
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.impl.Accessor;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.vm.TruffleVM;
+
+/**
+ * Language-agnostic engine for running Truffle languages under debugging control.
+ */
+public final class Debugger {
+
+ private static final boolean TRACE = false;
+ private static final String TRACE_PREFIX = "DEBUG ENGINE: ";
+
+ private static final PrintStream OUT = System.out;
+
+ private static final SyntaxTag STEPPING_TAG = StandardSyntaxTag.STATEMENT;
+ private static final SyntaxTag CALL_TAG = StandardSyntaxTag.CALL;
+
+ private static void trace(String format, Object... args) {
+ if (TRACE) {
+ OUT.println(TRACE_PREFIX + String.format(format, args));
+ }
+ }
+
+ private final TruffleVM vm;
+ private Source lastSource;
+
+ interface BreakpointCallback {
+
+ /**
+ * Passes control to the debugger with execution suspended.
+ */
+ void haltedAt(Node astNode, MaterializedFrame mFrame, String haltReason);
+ }
+
+ interface WarningLog {
+
+ /**
+ * Logs a warning that is kept until the start of the next execution.
+ */
+ void addWarning(String warning);
+ }
+
+ /**
+ * Implementation of line-oriented breakpoints.
+ */
+ private final LineBreakpointFactory lineBreaks;
+
+ /**
+ * Implementation of tag-oriented breakpoints.
+ */
+ private final TagBreakpointFactory tagBreaks;
+
+ /**
+ * Head of the stack of executions.
+ */
+ private DebugExecutionContext debugContext;
+
+ Debugger(TruffleVM vm) {
+ this.vm = vm;
+
+ Source.setFileCaching(true);
+
+ // Initialize execution context stack
+ debugContext = new DebugExecutionContext(null, null);
+ prepareContinue();
+ debugContext.contextTrace("START EXEC DEFAULT");
+
+ final BreakpointCallback breakpointCallback = new BreakpointCallback() {
+
+ @TruffleBoundary
+ public void haltedAt(Node astNode, MaterializedFrame mFrame, String haltReason) {
+ debugContext.halt(astNode, mFrame, true, haltReason);
+ }
+ };
+
+ final WarningLog warningLog = new WarningLog() {
+
+ public void addWarning(String warning) {
+ assert debugContext != null;
+ debugContext.logWarning(warning);
+ }
+ };
+
+ this.lineBreaks = new LineBreakpointFactory(this, breakpointCallback, warningLog);
+ this.tagBreaks = new TagBreakpointFactory(this, breakpointCallback, warningLog);
+ }
+
+ TruffleVM vm() {
+ return vm;
+ }
+
+ /**
+ * Sets a breakpoint to halt at a source line.
+ *
+ * @param ignoreCount number of hits to ignore before halting
+ * @param lineLocation where to set the breakpoint (source, line number)
+ * @param oneShot breakpoint disposes itself after fist hit, if {@code true}
+ * @return a new breakpoint, initially enabled
+ * @throws IOException if the breakpoint can not be set.
+ */
+ @TruffleBoundary
+ public Breakpoint setLineBreakpoint(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException {
+ return lineBreaks.create(ignoreCount, lineLocation, oneShot);
+ }
+
+ /**
+ * Sets a breakpoint to halt at any node holding a specified {@link SyntaxTag}.
+ *
+ * @param ignoreCount number of hits to ignore before halting
+ * @param oneShot if {@code true} breakpoint removes it self after a hit
+ * @return a new breakpoint, initially enabled
+ * @throws IOException if the breakpoint already set
+ */
+ @TruffleBoundary
+ public Breakpoint setTagBreakpoint(int ignoreCount, SyntaxTag tag, boolean oneShot) throws IOException {
+ return tagBreaks.create(ignoreCount, tag, oneShot);
+ }
+
+ /**
+ * Gets all existing breakpoints, whatever their status, in natural sorted order. Modification
+ * save.
+ */
+ @TruffleBoundary
+ public Collection getBreakpoints() {
+ final Collection result = new ArrayList<>();
+ result.addAll(lineBreaks.getAll());
+ result.addAll(tagBreaks.getAll());
+ return result;
+ }
+
+ /**
+ * Prepare to execute in Continue mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node to which an enabled breakpoint is attached,
+ * or:
+ *
execution completes.
+ *
+ *
+ */
+ @TruffleBoundary
+ void prepareContinue() {
+ debugContext.setStrategy(new Continue());
+ }
+
+ /**
+ * Prepare to execute in StepInto mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
User breakpoints are disabled.
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+ * STATMENT}, or:
+ *
execution completes.
+ *
+ *
StepInto mode persists only through one resumption (i.e. {@code stepIntoCount} steps),
+ * and reverts by default to Continue mode.
+ *
+ *
+ * @param stepCount the number of times to perform StepInto before halting
+ * @throws IllegalArgumentException if the specified number is {@code <= 0}
+ */
+ @TruffleBoundary
+ void prepareStepInto(int stepCount) {
+ if (stepCount <= 0) {
+ throw new IllegalArgumentException();
+ }
+ debugContext.setStrategy(new StepInto(stepCount));
+ }
+
+ /**
+ * Prepare to execute in StepOut mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
User breakpoints are enabled.
+ *
Execution will continue until either:
+ *
+ *
execution arrives at the nearest enclosing call site on the stack, or
+ *
execution completes.
+ *
+ *
StepOut mode persists only through one resumption, and reverts by default to Continue
+ * mode.
+ *
+ */
+ @TruffleBoundary
+ void prepareStepOut() {
+ debugContext.setStrategy(new StepOut());
+ }
+
+ /**
+ * Prepare to execute in StepOver mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+ * STATEMENT} when not nested in one or more function/method calls, or:
+ *
execution arrives at a node to which a breakpoint is attached and when nested in one or
+ * more function/method calls, or:
+ *
execution completes.
+ *
+ *
StepOver mode persists only through one resumption (i.e. {@code stepOverCount} steps),
+ * and reverts by default to Continue mode.
+ *
+ *
+ * @param stepCount the number of times to perform StepInto before halting
+ * @throws IllegalArgumentException if the specified number is {@code <= 0}
+ */
+ @TruffleBoundary
+ void prepareStepOver(int stepCount) {
+ if (stepCount <= 0) {
+ throw new IllegalArgumentException();
+ }
+ debugContext.setStrategy(new StepOver(stepCount));
+ }
+
+ /**
+ * Creates a language-specific factory to produce instances of {@link AdvancedInstrumentRoot}
+ * that, when executed, computes the result of a textual expression in the language; used to
+ * create an
+ * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+ * Advanced Instrument}.
+ *
+ * @param expr a guest language expression
+ * @param resultListener optional listener for the result of each evaluation.
+ * @return a new factory
+ * @throws IOException if the factory cannot be created, for example if the expression is badly
+ * formed.
+ */
+ AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Probe probe, String expr, AdvancedInstrumentResultListener resultListener) throws IOException {
+ try {
+ Class extends TruffleLanguage> langugageClass = ACCESSOR.findLanguage(probe);
+ TruffleLanguage l = ACCESSOR.findLanguage(vm, langugageClass);
+ DebugSupportProvider dsp = ACCESSOR.getDebugSupport(l);
+ return dsp.createAdvancedInstrumentRootFactory(expr, resultListener);
+ } catch (DebugSupportException ex) {
+ throw new IOException(ex);
+ }
+ }
+
+ /**
+ * A mode of user navigation from a current code location to another, e.g "step in" vs.
+ * "step over".
+ */
+ private abstract class StepStrategy {
+
+ private DebugExecutionContext context;
+ protected final String strategyName;
+
+ protected StepStrategy() {
+ this.strategyName = getClass().getSimpleName();
+ }
+
+ final String getName() {
+ return strategyName;
+ }
+
+ /**
+ * Reconfigure the debugger so that when execution continues the program will halt at the
+ * location specified by this strategy.
+ */
+ final void enable(DebugExecutionContext c, int stackDepth) {
+ this.context = c;
+ setStrategy(stackDepth);
+ }
+
+ /**
+ * Return the debugger to the default navigation mode.
+ */
+ final void disable() {
+ unsetStrategy();
+ }
+
+ @TruffleBoundary
+ final void halt(Node astNode, MaterializedFrame mFrame, boolean before) {
+ context.halt(astNode, mFrame, before, this.getClass().getSimpleName());
+ }
+
+ @TruffleBoundary
+ final void replaceStrategy(StepStrategy newStrategy) {
+ context.setStrategy(newStrategy);
+ }
+
+ @TruffleBoundary
+ protected final void strategyTrace(String action, String format, Object... args) {
+ if (TRACE) {
+ context.contextTrace("%s (%s) %s", action, strategyName, String.format(format, args));
+ }
+ }
+
+ @TruffleBoundary
+ protected final void suspendUserBreakpoints() {
+ lineBreaks.setActive(false);
+ tagBreaks.setActive(false);
+ }
+
+ @SuppressWarnings("unused")
+ protected final void restoreUserBreakpoints() {
+ lineBreaks.setActive(true);
+ tagBreaks.setActive(true);
+ }
+
+ /**
+ * Reconfigure the debugger so that when execution continues, it will do so using this mode
+ * of navigation.
+ */
+ protected abstract void setStrategy(int stackDepth);
+
+ /**
+ * Return to the debugger to the default mode of navigation.
+ */
+ protected abstract void unsetStrategy();
+ }
+
+ /**
+ * Strategy: the null stepping strategy.
+ *
+ *
User breakpoints are enabled.
+ *
Execution continues until either:
+ *
+ *
execution arrives at a node with attached user breakpoint, or:
execution arrives at a node with attached user breakpoint, or:
+ *
execution returns to a CALL node and the call stack is smaller than when
+ * execution started, or:
+ *
execution completes.
+ *
+ *
+ *
+ * @see Debugger#prepareStepOut()
+ */
+ private final class StepOut extends StepStrategy {
+
+ @Override
+ protected void setStrategy(final int stackDepth) {
+ Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
+
+ @TruffleBoundary
+ @Override
+ public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+ // HALT:
+ final int currentStackDepth = currentStackDepth();
+ strategyTrace("TRAP AFTER", "stackDepth: start=%d current=%d", stackDepth, currentStackDepth);
+ if (currentStackDepth < stackDepth) {
+ halt(node, mFrame, false);
+ }
+ strategyTrace("RESUME AFTER", "");
+ }
+ });
+ }
+
+ @Override
+ protected void unsetStrategy() {
+ Probe.setAfterTagTrap(null);
+ }
+ }
+
+ /**
+ * Strategy: per-statement stepping, so long as not nested in method calls (i.e. at original
+ * stack depth).
+ *
+ *
User breakpoints are enabled.
+ *
Execution continues until either:
+ *
+ *
execution arrives at a STATEMENT node with stack depth no more than when started
+ * or:
+ *
the program completes.
+ *
+ *
+ */
+ private final class StepOver extends StepStrategy {
+ private int unfinishedStepCount;
+
+ StepOver(int stepCount) {
+ this.unfinishedStepCount = stepCount;
+ }
+
+ @Override
+ protected void setStrategy(final int stackDepth) {
+ Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
+
+ @Override
+ public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+ final int currentStackDepth = currentStackDepth();
+ if (currentStackDepth <= stackDepth) {
+ // HALT: stack depth unchanged or smaller; treat like StepInto
+ --unfinishedStepCount;
+ if (TRACE) {
+ strategyTrace("TRAP BEFORE", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+ }
+ // Test should run in fast path
+ if (unfinishedStepCount <= 0) {
+ halt(node, mFrame, true);
+ }
+ } else {
+ // CONTINUE: Stack depth increased; don't count as a step
+ strategyTrace("STEP INTO", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+ // Stop treating like StepInto, start treating like StepOut
+ replaceStrategy(new StepOverNested(unfinishedStepCount, stackDepth));
+ }
+ strategyTrace("RESUME BEFORE", "");
+ }
+ });
+
+ Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
+
+ @Override
+ public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+ final int currentStackDepth = currentStackDepth();
+ if (currentStackDepth < stackDepth) {
+ // HALT: just "stepped out"
+ --unfinishedStepCount;
+ strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth: start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+ // Should run in fast path
+ if (unfinishedStepCount <= 0) {
+ halt(node, mFrame, false);
+ }
+ strategyTrace("RESUME AFTER", "");
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void unsetStrategy() {
+ Probe.setBeforeTagTrap(null);
+ Probe.setAfterTagTrap(null);
+ }
+ }
+
+ /**
+ * Strategy: per-statement stepping, not into method calls, in effect while at increased stack
+ * depth
+ *
+ *
User breakpoints are enabled.
+ *
Execution continues until either:
+ *
+ *
execution arrives at a STATEMENT node with stack depth no more than when started
+ * or:
+ *
the program completes or:
+ *
+ *
+ */
+ private final class StepOverNested extends StepStrategy {
+ private int unfinishedStepCount;
+ private final int startStackDepth;
+
+ StepOverNested(int stepCount, int startStackDepth) {
+ this.unfinishedStepCount = stepCount;
+ this.startStackDepth = startStackDepth;
+ }
+
+ @Override
+ protected void setStrategy(final int stackDepth) {
+ Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
+
+ @Override
+ public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+ final int currentStackDepth = currentStackDepth();
+ if (currentStackDepth <= startStackDepth) {
+ // At original step depth (or smaller) after being nested
+ --unfinishedStepCount;
+ strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+ if (unfinishedStepCount <= 0) {
+ halt(node, mFrame, false);
+ }
+ // TODO (mlvdv) fixme for multiple steps
+ strategyTrace("RESUME BEFORE", "");
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void unsetStrategy() {
+ Probe.setBeforeTagTrap(null);
+ }
+ }
+
+ /**
+ * Information and debugging state for a single Truffle execution (which make take place over
+ * one or more suspended executions). This holds interaction state, for example what is
+ * executing (e.g. some {@link Source}), what the execution mode is ("stepping" or
+ * "continuing"). When not running, this holds a cache of the Truffle stack for this particular
+ * execution, effectively hiding the Truffle stack for any currently suspended executions (down
+ * the stack).
+ */
+ private final class DebugExecutionContext {
+
+ // Previous halted context in stack
+ private final DebugExecutionContext predecessor;
+
+ // The current execution level; first is 0.
+ private final int level; // Number of contexts suspended below
+ private final Source source;
+ private final int contextStackBase; // Where the stack for this execution starts
+ private final List warnings = new ArrayList<>();
+
+ private boolean running;
+
+ /**
+ * The stepping strategy currently configured in the debugger.
+ */
+ private StepStrategy strategy;
+
+ /**
+ * Where halted; null if running.
+ */
+ private Node haltedNode;
+
+ /**
+ * Where halted; null if running.
+ */
+ private MaterializedFrame haltedFrame;
+
+ private DebugExecutionContext(Source executionSource, DebugExecutionContext previousContext) {
+ this.source = executionSource;
+ this.predecessor = previousContext;
+ this.level = previousContext == null ? 0 : previousContext.level + 1;
+
+ // "Base" is the number of stack frames for all nested (halted) executions.
+ this.contextStackBase = currentStackDepth();
+ this.running = true;
+ contextTrace("NEW CONTEXT");
+ }
+
+ /**
+ * Sets up a strategy for the next resumption of execution.
+ *
+ * @param stepStrategy
+ */
+ void setStrategy(StepStrategy stepStrategy) {
+ if (this.strategy == null) {
+ this.strategy = stepStrategy;
+ this.strategy.enable(this, currentStackDepth());
+ if (TRACE) {
+ contextTrace("SET MODE -->" + stepStrategy.getName());
+ }
+ } else {
+ strategy.disable();
+ strategy = stepStrategy;
+ strategy.enable(this, currentStackDepth());
+ contextTrace("SWITCH MODE %s-->%s", strategy.getName(), stepStrategy.getName());
+ }
+ }
+
+ void clearStrategy() {
+ if (strategy != null) {
+ final StepStrategy oldStrategy = strategy;
+ strategy.disable();
+ strategy = null;
+ contextTrace("CLEAR MODE %s-->", oldStrategy.getName());
+ }
+ }
+
+ /**
+ * Handle a program halt, caused by a breakpoint, stepping strategy, or other cause.
+ *
+ * @param astNode the guest language node at which execution is halted
+ * @param mFrame the current execution frame where execution is halted
+ * @param before {@code true} if halted before the node, else after.
+ */
+ @TruffleBoundary
+ void halt(Node astNode, MaterializedFrame mFrame, boolean before, String haltReason) {
+ assert running;
+ assert haltedNode == null;
+ assert haltedFrame == null;
+
+ haltedNode = astNode;
+ haltedFrame = mFrame;
+ running = false;
+
+ clearStrategy();
+
+ // Clean up, just in cased the one-shot breakpoints got confused
+ lineBreaks.disposeOneShots();
+
+ final int contextStackDepth = currentStackDepth() - contextStackBase;
+ if (TRACE) {
+ final String reason = haltReason == null ? "" : haltReason + "";
+ final String where = before ? "BEFORE" : "AFTER";
+ contextTrace("HALT %s : (%s) stack base=%d", where, reason, contextStackBase);
+ contextTrace("CURRENT STACK:");
+ // printStack(OUT);
+ }
+
+ final List recentWarnings = new ArrayList<>(warnings);
+ warnings.clear();
+
+ try {
+ // Pass control to the debug client with current execution suspended
+ ACCESSOR.dispatchEvent(vm, new SuspendedEvent(Debugger.this, astNode, mFrame, recentWarnings, contextStackDepth));
+ // Debug client finished normally, execution resumes
+ // Presume that the client has set a new strategy (or default to Continue)
+ running = true;
+ } catch (KillException e) {
+ contextTrace("KILL");
+ throw e;
+ } finally {
+ haltedNode = null;
+ haltedFrame = null;
+ }
+
+ }
+
+ void logWarning(String warning) {
+ warnings.add(warning);
+ }
+
+ /*
+ * private void printStack(PrintStream stream) { getFrames(); if (frames == null) {
+ * stream.println(""); } else { final Visualizer visualizer =
+ * provider.getVisualizer(); for (FrameDebugDescription frameDesc : frames) { final
+ * StringBuilder sb = new StringBuilder(" frame " + Integer.toString(frameDesc.index()));
+ * sb.append(":at " + visualizer.displaySourceLocation(frameDesc.node())); sb.append(":in '"
+ * + visualizer.displayMethodName(frameDesc.node()) + "'"); stream.println(sb.toString()); }
+ * } }
+ */
+
+ void contextTrace(String format, Object... args) {
+ if (TRACE) {
+ final String srcName = (source != null) ? source.getName() : "no source";
+ Debugger.trace("<%d> %s (%s)", level, String.format(format, args), srcName);
+ }
+ }
+ }
+
+ // TODO (mlvdv) wish there were fast-path access to stack depth
+ /**
+ * Depth of current Truffle stack, including nested executions. Includes the top/current frame,
+ * which the standard iterator does not count: {@code 0} if no executions.
+ */
+ @TruffleBoundary
+ private static int currentStackDepth() {
+ final int[] count = {0};
+ Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() {
+ @Override
+ public Void visitFrame(FrameInstance frameInstance) {
+ count[0] = count[0] + 1;
+ return null;
+ }
+ });
+ return count[0] == 0 ? 0 : count[0] + 1;
+
+ }
+
+ void executionStarted(Source source) {
+ Source execSource = source;
+ if (execSource == null) {
+ execSource = lastSource;
+ } else {
+ lastSource = execSource;
+ }
+ // Push a new execution context onto stack
+ debugContext = new DebugExecutionContext(execSource, debugContext);
+ prepareContinue();
+ debugContext.contextTrace("START EXEC ");
+ ACCESSOR.dispatchEvent(vm, new ExecutionEvent(this));
+ }
+
+ void executionEnded() {
+ lineBreaks.disposeOneShots();
+ tagBreaks.disposeOneShots();
+ debugContext.clearStrategy();
+ debugContext.contextTrace("END EXEC ");
+ // Pop the stack of execution contexts.
+ debugContext = debugContext.predecessor;
+ }
+
+ private static final class AccessorDebug extends Accessor {
+ @Override
+ protected Closeable executionStart(TruffleVM vm, Debugger[] fillIn, Source s) {
+ final Debugger d;
+ if (fillIn[0] == null) {
+ d = fillIn[0] = new Debugger(vm);
+ } else {
+ d = fillIn[0];
+ }
+ d.executionStarted(s);
+ return new Closeable() {
+ @Override
+ public void close() throws IOException {
+ d.executionEnded();
+ }
+ };
+ }
+
+ @Override
+ protected Class extends TruffleLanguage> findLanguage(Probe probe) {
+ return super.findLanguage(probe);
+ }
+
+ @Override
+ protected TruffleLanguage findLanguage(TruffleVM vm, Class extends TruffleLanguage> languageClass) {
+ return super.findLanguage(vm, languageClass);
+ }
+
+ @Override
+ protected DebugSupportProvider getDebugSupport(TruffleLanguage l) {
+ return super.getDebugSupport(l);
+ }
+
+ @Override
+ protected void dispatchEvent(TruffleVM vm, Object event) {
+ super.dispatchEvent(vm, event);
+ }
+ }
+
+ // registers into Accessor.DEBUG
+ private static final AccessorDebug ACCESSOR = new AccessorDebug();
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ExecutionEvent.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ExecutionEvent.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.api.vm.TruffleVM.Builder;
+
+/**
+ * This event is delivered to all {@link Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer)
+ * registered event handlers} when an execution is about to be started. The event is the intended
+ * place to initialize debugger - e.g. set
+ * {@link Debugger#setLineBreakpoint(int, com.oracle.truffle.api.source.LineLocation, boolean)
+ * breakpoints} or specify to execution should halt on the {@link #prepareStepInto() first possible
+ * occurence}. Methods in this event can only be used while the handlers process the event. Then the
+ * state of the event becomes invalid and subsequent calls to the event methods yield
+ * {@link IllegalStateException}. One can however obtain reference to {@link Debugger} instance and
+ * keep it to further manipulate with debugging capabilities of the {@link TruffleVM} when it is
+ * running.
+ */
+public final class ExecutionEvent {
+ private final Debugger debugger;
+
+ ExecutionEvent(Debugger prepares) {
+ this.debugger = prepares;
+ }
+
+ /**
+ * Debugger associated with the execution. This debuger remains valid after the event is
+ * processed, it is possible and suggested to keep a reference to it and use it any time later
+ * when evaluating sources in the {@link TruffleVM}.
+ *
+ * @return instance of debugger associated with the just starting execution and any subsequent
+ * ones in the same {@link TruffleVM}.
+ */
+ public Debugger getDebugger() {
+ return debugger;
+ }
+
+ /**
+ * Prepare to execute in Continue mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node to which an enabled breakpoint is attached,
+ * or:
+ *
execution completes.
+ *
+ *
+ */
+ public void prepareContinue() {
+ debugger.prepareContinue();
+ }
+
+ /**
+ * Prepare to execute in StepInto mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
User breakpoints are disabled.
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+ * STATMENT}, or:
+ *
execution completes.
+ *
+ *
StepInto mode persists only through one resumption (i.e. {@code stepIntoCount} steps),
+ * and reverts by default to Continue mode.
+ *
+ *
+ * @throws IllegalArgumentException if the specified number is {@code <= 0}
+ */
+ public void prepareStepInto() {
+ debugger.prepareStepInto(1);
+ }
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpoint.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpoint.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import com.oracle.truffle.api.source.*;
+
+// TODO (mlvdv) generic?
+/**
+ * A breakpoint associated with a {@linkplain LineLocation source line location}.
+ *
+ * @see Debugger
+ */
+abstract class LineBreakpoint extends Breakpoint {
+
+ LineBreakpoint(State state, int ignoreCount, boolean isOneShot) {
+ super(state, ignoreCount, isOneShot);
+ }
+
+ /**
+ * Gets the {@linkplain LineLocation source line location} that specifies where this breakpoint
+ * will trigger.
+ */
+ public abstract LineLocation getLineLocation();
+
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import static com.oracle.truffle.api.debug.Breakpoint.State.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.debug.Debugger.BreakpointCallback;
+import com.oracle.truffle.api.debug.Debugger.WarningLog;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.utilities.*;
+
+//TODO (mlvdv) some common functionality could be factored out of this and TagBreakpointSupport
+
+/**
+ * Support class for creating and managing all existing ordinary (user visible) line breakpoints.
+ *
+ * Notes:
+ *
+ *
Line breakpoints can only be set at nodes tagged as {@link StandardSyntaxTag#STATEMENT}.
+ *
A newly created breakpoint looks for probes matching the location, attaches to them if found
+ * by installing an {@link Instrument} that calls back to the breakpoint.
+ *
When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
+ * copied along with the rest of the AST and will call back to the same breakpoint.
+ *
When notification is received of a new Node being tagged as a statement, and if a
+ * breakpoint's line location matches the Probe's line location, then the breakpoint will attach a
+ * new Instrument at the probe to activate the breakpoint at that location.
+ *
A breakpoint may have multiple Instruments deployed, one attached to each Probe that matches
+ * the breakpoint's line location; this might happen when a source is reloaded.
+ *
+ *
+ */
+final class LineBreakpointFactory {
+
+ private static final boolean TRACE = false;
+ private static final PrintStream OUT = System.out;
+
+ private static final String BREAKPOINT_NAME = "LINE BREAKPOINT";
+
+ private static void trace(String format, Object... args) {
+ if (TRACE) {
+ OUT.println(String.format("%s: %s", BREAKPOINT_NAME, String.format(format, args)));
+ }
+ }
+
+ private static final Comparator> BREAKPOINT_COMPARATOR = new Comparator>() {
+
+ @Override
+ public int compare(Entry entry1, Entry entry2) {
+ final LineLocation line1 = entry1.getKey();
+ final LineLocation line2 = entry2.getKey();
+ final int nameOrder = line1.getSource().getShortName().compareTo(line2.getSource().getShortName());
+ if (nameOrder != 0) {
+ return nameOrder;
+ }
+ return Integer.compare(line1.getLineNumber(), line2.getLineNumber());
+ }
+ };
+
+ private final Debugger executionSupport;
+ private final BreakpointCallback breakpointCallback;
+ private final WarningLog warningLog;
+
+ /**
+ * Map: Source lines ==> attached breakpoints. There may be no more than one line breakpoint
+ * associated with a line.
+ */
+ private final Map lineToBreakpoint = new HashMap<>();
+
+ /**
+ * A map of {@link LineLocation} to a collection of {@link Probe}s. This list must be
+ * initialized and filled prior to being used by this class.
+ */
+ private final LineToProbesMap lineToProbesMap;
+
+ /**
+ * Globally suspends all line breakpoint activity when {@code false}, ignoring whether
+ * individual breakpoints are enabled.
+ */
+ @CompilationFinal private boolean breakpointsActive = true;
+ private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
+
+ LineBreakpointFactory(Debugger executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
+ this.executionSupport = executionSupport;
+ this.breakpointCallback = breakpointCallback;
+ this.warningLog = warningLog;
+
+ lineToProbesMap = new LineToProbesMap();
+ lineToProbesMap.install();
+
+ Probe.addProbeListener(new DefaultProbeListener() {
+
+ @Override
+ public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
+ if (tag == StandardSyntaxTag.STATEMENT) {
+ final SourceSection sourceSection = probe.getProbedSourceSection();
+ if (sourceSection != null) {
+ final LineLocation lineLocation = sourceSection.getLineLocation();
+ if (lineLocation != null) {
+ // A Probe with line location tagged STATEMENT we haven't seen before.
+ final LineBreakpointImpl breakpoint = lineToBreakpoint.get(lineLocation);
+ if (breakpoint != null) {
+ try {
+ breakpoint.attach(probe);
+ } catch (IOException e) {
+ warningLog.addWarning(BREAKPOINT_NAME + " failure attaching to newly tagged Probe: " + e.getMessage());
+ if (TRACE) {
+ OUT.println(BREAKPOINT_NAME + " failure: " + e.getMessage());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Globally enables line breakpoint activity; all breakpoints are ignored when set to
+ * {@code false}. When set to {@code true}, the enabled/disabled status of each breakpoint
+ * determines whether it will trigger when flow of execution reaches it.
+ *
+ * @param breakpointsActive
+ */
+ void setActive(boolean breakpointsActive) {
+ if (this.breakpointsActive != breakpointsActive) {
+ breakpointsActiveUnchanged.invalidate();
+ this.breakpointsActive = breakpointsActive;
+ }
+ }
+
+ /**
+ * Gets all current line breakpoints,regardless of status; sorted and modification safe.
+ */
+ List getAll() {
+ ArrayList> entries = new ArrayList<>(lineToBreakpoint.entrySet());
+ Collections.sort(entries, BREAKPOINT_COMPARATOR);
+
+ final ArrayList breakpoints = new ArrayList<>(entries.size());
+ for (Entry entry : entries) {
+ breakpoints.add(entry.getValue());
+ }
+ return breakpoints;
+ }
+
+ /**
+ * Creates a new line breakpoint if one doesn't already exist. If one does exist, then resets
+ * the ignore count.
+ *
+ * @param lineLocation where to set the breakpoint
+ * @param ignoreCount number of initial hits before the breakpoint starts causing breaks.
+ * @param oneShot whether the breakpoint should dispose itself after one hit
+ * @return a possibly new breakpoint
+ * @throws IOException if a breakpoint already exists at the location and the ignore count is
+ * the same
+ */
+ LineBreakpoint create(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException {
+
+ LineBreakpointImpl breakpoint = lineToBreakpoint.get(lineLocation);
+
+ if (breakpoint == null) {
+ breakpoint = new LineBreakpointImpl(ignoreCount, lineLocation, oneShot);
+
+ if (TRACE) {
+ trace("NEW " + breakpoint.getShortDescription());
+ }
+
+ lineToBreakpoint.put(lineLocation, breakpoint);
+
+ for (Probe probe : lineToProbesMap.findProbes(lineLocation)) {
+ if (probe.isTaggedAs(StandardSyntaxTag.STATEMENT)) {
+ breakpoint.attach(probe);
+ break;
+ }
+ }
+ } else {
+ if (ignoreCount == breakpoint.getIgnoreCount()) {
+ throw new IOException(BREAKPOINT_NAME + " already set at line " + lineLocation);
+ }
+ breakpoint.setIgnoreCount(ignoreCount);
+ if (TRACE) {
+ trace("CHANGED ignoreCount %s", breakpoint.getShortDescription());
+ }
+ }
+ return breakpoint;
+ }
+
+ /**
+ * Returns the {@link LineBreakpoint} for a given line. There should only ever be one breakpoint
+ * per line.
+ *
+ * @param lineLocation The {@link LineLocation} to get the breakpoint for.
+ * @return The breakpoint for the given line.
+ */
+ LineBreakpoint get(LineLocation lineLocation) {
+ return lineToBreakpoint.get(lineLocation);
+ }
+
+ /**
+ * Removes the associated instrumentation for all one-shot breakpoints only.
+ */
+ void disposeOneShots() {
+ List breakpoints = new ArrayList<>(lineToBreakpoint.values());
+ for (LineBreakpointImpl breakpoint : breakpoints) {
+ if (breakpoint.isOneShot()) {
+ breakpoint.dispose();
+ }
+ }
+ }
+
+ /**
+ * Removes all knowledge of a breakpoint, presumed disposed.
+ */
+ private void forget(LineBreakpointImpl breakpoint) {
+ lineToBreakpoint.remove(breakpoint.getLineLocation());
+ }
+
+ /**
+ * Concrete representation of a line breakpoint, implemented by attaching an instrument to a
+ * probe at the designated source location.
+ */
+ private final class LineBreakpointImpl extends LineBreakpoint implements AdvancedInstrumentResultListener {
+
+ private static final String SHOULD_NOT_HAPPEN = "LineBreakpointImpl: should not happen";
+
+ private final LineLocation lineLocation;
+
+ // Cached assumption that the global status of line breakpoint activity has not changed.
+ private Assumption breakpointsActiveAssumption;
+
+ // Whether this breakpoint is enable/disabled
+ @CompilationFinal private boolean isEnabled;
+ private Assumption enabledUnchangedAssumption;
+
+ private String conditionExpr;
+
+ /**
+ * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
+ * {@code null} if not attached.
+ */
+ private List instruments = new ArrayList<>();
+
+ public LineBreakpointImpl(int ignoreCount, LineLocation lineLocation, boolean oneShot) {
+ super(ENABLED_UNRESOLVED, ignoreCount, oneShot);
+ this.lineLocation = lineLocation;
+
+ this.breakpointsActiveAssumption = LineBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+ this.isEnabled = true;
+ this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged");
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return isEnabled;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (enabled != isEnabled) {
+ switch (getState()) {
+ case ENABLED:
+ assert !enabled : SHOULD_NOT_HAPPEN;
+ doSetEnabled(false);
+ changeState(DISABLED);
+ break;
+ case ENABLED_UNRESOLVED:
+ assert !enabled : SHOULD_NOT_HAPPEN;
+ doSetEnabled(false);
+ changeState(DISABLED_UNRESOLVED);
+ break;
+ case DISABLED:
+ assert enabled : SHOULD_NOT_HAPPEN;
+ doSetEnabled(true);
+ changeState(ENABLED);
+ break;
+ case DISABLED_UNRESOLVED:
+ assert enabled : SHOULD_NOT_HAPPEN;
+ doSetEnabled(true);
+ changeState(DISABLED_UNRESOLVED);
+ break;
+ case DISPOSED:
+ assert false : "breakpoint disposed";
+ break;
+ default:
+ assert false : SHOULD_NOT_HAPPEN;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void setCondition(String expr) throws IOException {
+ if (this.conditionExpr != null || expr != null) {
+ // De-instrument the Probes instrumented by this breakpoint
+ final ArrayList probes = new ArrayList<>();
+ for (Instrument instrument : instruments) {
+ probes.add(instrument.getProbe());
+ instrument.dispose();
+ }
+ instruments.clear();
+ this.conditionExpr = expr;
+ // Re-instrument the probes previously instrumented
+ for (Probe probe : probes) {
+ attach(probe);
+ }
+ }
+ }
+
+ @Override
+ public String getCondition() {
+ return conditionExpr;
+ }
+
+ @Override
+ public void dispose() {
+ if (getState() != DISPOSED) {
+ for (Instrument instrument : instruments) {
+ instrument.dispose();
+ }
+ changeState(DISPOSED);
+ LineBreakpointFactory.this.forget(this);
+ }
+ }
+
+ private void attach(Probe newProbe) throws IOException {
+ if (getState() == DISPOSED) {
+ throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
+ }
+ Instrument newInstrument = null;
+ if (conditionExpr == null) {
+ newInstrument = Instrument.create(new UnconditionalLineBreakInstrumentListener(), BREAKPOINT_NAME);
+ } else {
+ newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+ }
+ newProbe.attach(newInstrument);
+ instruments.add(newInstrument);
+ changeState(isEnabled ? ENABLED : DISABLED);
+ }
+
+ private void doSetEnabled(boolean enabled) {
+ if (this.isEnabled != enabled) {
+ enabledUnchangedAssumption.invalidate();
+ this.isEnabled = enabled;
+ }
+ }
+
+ private String getShortDescription() {
+ return BREAKPOINT_NAME + "@" + getLineLocation().getShortDescription();
+ }
+
+ private void changeState(State after) {
+ if (TRACE) {
+ trace("STATE %s-->%s %s", getState().getName(), after.getName(), getShortDescription());
+ }
+ setState(after);
+ }
+
+ private void doBreak(Node node, VirtualFrame vFrame) {
+ if (incrHitCountCheckIgnore()) {
+ breakpointCallback.haltedAt(node, vFrame.materialize(), BREAKPOINT_NAME);
+ }
+ }
+
+ /**
+ * Receives notification from the attached instrument that execution is about to enter node
+ * where the breakpoint is set. Designed so that when in the fast path, there is either an
+ * unconditional "halt" call to the debugger or nothing.
+ */
+ private void nodeEnter(Node astNode, VirtualFrame vFrame) {
+
+ // Deopt if the global active/inactive flag has changed
+ try {
+ this.breakpointsActiveAssumption.check();
+ } catch (InvalidAssumptionException ex) {
+ this.breakpointsActiveAssumption = LineBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+ }
+
+ // Deopt if the enabled/disabled state of this breakpoint has changed
+ try {
+ this.enabledUnchangedAssumption.check();
+ } catch (InvalidAssumptionException ex) {
+ this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption("LineBreakpoint enabled state unchanged");
+ }
+
+ if (LineBreakpointFactory.this.breakpointsActive && this.isEnabled) {
+ if (isOneShot()) {
+ dispose();
+ }
+ LineBreakpointImpl.this.doBreak(astNode, vFrame);
+ }
+ }
+
+ public void notifyResult(Node node, VirtualFrame vFrame, Object result) {
+ final boolean condition = (Boolean) result;
+ if (TRACE) {
+ trace("breakpoint condition = %b %s", condition, getShortDescription());
+ }
+ if (condition) {
+ nodeEnter(node, vFrame);
+ }
+ }
+
+ @TruffleBoundary
+ public void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex) {
+ warningLog.addWarning(String.format("Exception in %s: %s", getShortDescription(), ex.getMessage()));
+ if (TRACE) {
+ trace("breakpoint failure = %s %s", ex.toString(), getShortDescription());
+ }
+ // Take the breakpoint if evaluation fails.
+ nodeEnter(node, vFrame);
+ }
+
+ @Override
+ public String getLocationDescription() {
+ return "Line: " + lineLocation.getShortDescription();
+ }
+
+ @Override
+ public LineLocation getLineLocation() {
+ return lineLocation;
+ }
+
+ private final class UnconditionalLineBreakInstrumentListener extends DefaultStandardInstrumentListener {
+
+ @Override
+ public void enter(Probe probe, Node node, VirtualFrame vFrame) {
+ LineBreakpointImpl.this.nodeEnter(node, vFrame);
+ }
+ }
+ }
+
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineToProbesMap.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineToProbesMap.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.DefaultProbeListener;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * An {@link InstrumentationTool} that builds a map of every {@link Probe} attached to some AST,
+ * indexed by {@link Source} and line number.
+ */
+final class LineToProbesMap extends InstrumentationTool {
+
+ private static final boolean TRACE = false;
+ private static final PrintStream OUT = System.out;
+
+ private static void trace(String msg) {
+ OUT.println("LineToProbesMap: " + msg);
+ }
+
+ /**
+ * Map: Source line ==> probes associated with source sections starting on the line.
+ */
+ private final Map> lineToProbesMap = new HashMap<>();
+
+ private final ProbeListener probeListener;
+
+ /**
+ * Create a map of {@link Probe}s that collects information on all probes added to subsequently
+ * created ASTs (once installed).
+ */
+ public LineToProbesMap() {
+ this.probeListener = new LineToProbesListener();
+ }
+
+ @Override
+ protected boolean internalInstall() {
+ Probe.addProbeListener(probeListener);
+ return true;
+ }
+
+ @Override
+ protected void internalReset() {
+ lineToProbesMap.clear();
+ }
+
+ @Override
+ protected void internalDispose() {
+ Probe.removeProbeListener(probeListener);
+ }
+
+ /**
+ * Returns the {@link Probe}, if any, associated with a specific line of guest language code; if
+ * more than one, return the one with the first starting character location.
+ */
+ public Probe findFirstProbe(LineLocation lineLocation) {
+ Probe probe = null;
+ final Collection probes = findProbes(lineLocation);
+ for (Probe probesOnLine : probes) {
+ if (probe == null) {
+ probe = probesOnLine;
+ } else if (probesOnLine.getProbedSourceSection().getCharIndex() < probe.getProbedSourceSection().getCharIndex()) {
+ probe = probesOnLine;
+ }
+ }
+ return probe;
+ }
+
+ /**
+ * Returns all {@link Probe}s whose associated source begins at the given {@link LineLocation},
+ * an empty list if none.
+ */
+ public Collection findProbes(LineLocation line) {
+ final Collection probes = lineToProbesMap.get(line);
+ if (probes == null) {
+ return Collections.emptyList();
+ }
+ return Collections.unmodifiableCollection(probes);
+ }
+
+ private class LineToProbesListener extends DefaultProbeListener {
+
+ @Override
+ public void newProbeInserted(Probe probe) {
+ final SourceSection sourceSection = probe.getProbedSourceSection();
+ if (sourceSection != null && sourceSection.getSource() != null) {
+ final LineLocation lineLocation = sourceSection.getLineLocation();
+ if (TRACE) {
+ trace("ADD " + lineLocation.getShortDescription() + " ==> " + probe.getShortDescription());
+ }
+ Collection probes = lineToProbesMap.get(lineLocation);
+ if (probes == null) {
+ probes = new ArrayList<>(2);
+ lineToProbesMap.put(lineLocation, probes);
+ } else {
+ assert !probes.contains(probe);
+ }
+ probes.add(probe);
+ }
+ }
+ }
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.FrameInstance;
+import com.oracle.truffle.api.frame.FrameInstanceVisitor;
+import com.oracle.truffle.api.frame.MaterializedFrame;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.api.vm.TruffleVM.Builder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This event is delivered to all {@link Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer)
+ * registered event handlers} when an execution is suspended on a
+ * {@link Debugger#setLineBreakpoint(int, com.oracle.truffle.api.source.LineLocation, boolean)
+ * breakpoint} or during {@link #prepareStepInto(int) stepping}. Methods in this event can only be
+ * used while the handlers process the event. Then the state of the event becomes invalid and
+ * subsequent calls to the event methods yield {@link IllegalStateException}.
+ *
+ */
+public final class SuspendedEvent {
+ private final List recentWarnings;
+ private final MaterializedFrame mFrame;
+ private final Node astNode;
+ private final List frames;
+ private final Debugger debugger;
+
+ SuspendedEvent(Debugger prepares, Node astNode, MaterializedFrame mFrame, List recentWarnings, final int stackDepth) {
+ this.debugger = prepares;
+ this.astNode = astNode;
+ this.mFrame = mFrame;
+ this.recentWarnings = recentWarnings;
+
+ this.frames = new ArrayList<>();
+ // Map the Truffle stack for this execution, ignore nested executions
+ // The top (current) frame is not produced by the iterator.
+ frames.add(Truffle.getRuntime().getCurrentFrame());
+ Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor() {
+ int frameCount = 1;
+
+ @Override
+ public FrameInstance visitFrame(FrameInstance frameInstance) {
+ if (frameCount < stackDepth) {
+ frames.add(frameInstance);
+ frameCount++;
+ return null;
+ }
+ return frameInstance;
+ }
+ });
+
+ }
+
+ /**
+ * Debugger associated with the just suspended execution. This debuger remains valid after the
+ * event is processed, it is possible and suggested to keep a reference to it and use it any
+ * time later when evaluating sources in the {@link TruffleVM}.
+ *
+ * @return instance of debugger associated with the just suspended execution and any subsequent
+ * ones in the same {@link TruffleVM}.
+ */
+ public Debugger getDebugger() {
+ return debugger;
+ }
+
+ public Node getNode() {
+ return astNode;
+ }
+
+ public MaterializedFrame getFrame() {
+ return mFrame;
+ }
+
+ public List getRecentWarnings() {
+ return Collections.unmodifiableList(recentWarnings);
+ }
+
+ /**
+ * Gets the stack frames from the currently halted {@link TruffleVM} execution.
+ *
+ * @return list of stack frames
+ */
+ @CompilerDirectives.TruffleBoundary
+ public List getStack() {
+ return Collections.unmodifiableList(frames);
+ }
+
+ /**
+ * Prepare to execute in Continue mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node to which an enabled breakpoint is attached,
+ * or:
+ *
execution completes.
+ *
+ *
+ */
+ public void prepareContinue() {
+ debugger.prepareContinue();
+ }
+
+ /**
+ * Prepare to execute in StepInto mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
User breakpoints are disabled.
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+ * STATMENT}, or:
+ *
execution completes.
+ *
+ *
StepInto mode persists only through one resumption (i.e. {@code stepIntoCount} steps),
+ * and reverts by default to Continue mode.
+ *
+ *
+ * @param stepCount the number of times to perform StepInto before halting
+ * @throws IllegalArgumentException if the specified number is {@code <= 0}
+ */
+ public void prepareStepInto(int stepCount) {
+ debugger.prepareStepInto(stepCount);
+ }
+
+ /**
+ * Prepare to execute in StepOut mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
User breakpoints are enabled.
+ *
Execution will continue until either:
+ *
+ *
execution arrives at the nearest enclosing call site on the stack, or
+ *
execution completes.
+ *
+ *
StepOut mode persists only through one resumption, and reverts by default to Continue
+ * mode.
+ *
+ */
+ public void prepareStepOut() {
+ debugger.prepareStepOut();
+ }
+
+ /**
+ * Prepare to execute in StepOver mode when guest language program execution resumes. In this
+ * mode:
+ *
+ *
Execution will continue until either:
+ *
+ *
execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+ * STATEMENT} when not nested in one or more function/method calls, or:
+ *
execution arrives at a node to which a breakpoint is attached and when nested in one or
+ * more function/method calls, or:
+ *
execution completes.
+ *
+ *
StepOver mode persists only through one resumption (i.e. {@code stepOverCount} steps),
+ * and reverts by default to Continue mode.
+ *
+ *
+ * @param stepCount the number of times to perform StepInto before halting
+ * @throws IllegalArgumentException if the specified number is {@code <= 0}
+ */
+ public void prepareStepOver(int stepCount) {
+ debugger.prepareStepOver(stepCount);
+ }
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpoint.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpoint.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import com.oracle.truffle.api.instrument.*;
+
+// TODO (mlvdv) generic?
+/**
+ * A breakpoint associated with a {@link SyntaxTag}.
+ *
+ * @see Debugger
+ */
+abstract class TagBreakpoint extends Breakpoint {
+
+ TagBreakpoint(State state, int ignoreCount, boolean isOneShot) {
+ super(state, ignoreCount, isOneShot);
+ }
+
+ /**
+ * Gets the tag that specifies where this breakpoint will trigger.
+ */
+ public abstract SyntaxTag getTag();
+
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.debug;
+
+import static com.oracle.truffle.api.debug.Breakpoint.State.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.debug.Debugger.BreakpointCallback;
+import com.oracle.truffle.api.debug.Debugger.WarningLog;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+
+// TODO (mlvdv) some common functionality could be factored out of this and LineBreakpointSupport
+
+/**
+ * Support class for creating and managing "Tag Breakpoints". A Tag Breakpoint halts execution just
+ * before reaching any node whose Probe carries a specified {@linkplain SyntaxTag Tag}.
+ *
+ * The {@linkplain Probe#setBeforeTagTrap(SyntaxTagTrap) Tag Trap}, which is built directly into the
+ * Instrumentation Framework, does the same thing more efficiently, but there may only be one Tag
+ * Trap active at a time. Any number of tag breakpoints may coexist with the Tag Trap, but it would
+ * be confusing to have a Tag Breakpoint set for the same Tag as the current Tag Trap.
+ *
+ * Notes:
+ *
+ *
Only one Tag Breakpoint can be active for a specific {@linkplain SyntaxTag Tag}.
+ *
A newly created breakpoint looks for probes matching the tag, attaches to them if found by
+ * installing an {@link Instrument}.
+ *
When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
+ * copied along with the rest of the AST and will call back to the same breakpoint.
+ *
When notification is received that the breakpoint's Tag has been newly added to a Node, then
+ * the breakpoint will attach a new Instrument at the probe to activate the breakpoint at that
+ * location.
+ *
A breakpoint may have multiple Instruments deployed, one attached to each Probe that holds
+ * the breakpoint's tag; this might happen when a source is reloaded.
+ *
+ */
+final class TagBreakpointFactory {
+
+ private static final boolean TRACE = false;
+ private static final PrintStream OUT = System.out;
+
+ private static final String BREAKPOINT_NAME = "TAG BREAKPOINT";
+
+ private static void trace(String format, Object... args) {
+ if (TRACE) {
+ OUT.println(String.format("%s: %s", BREAKPOINT_NAME, String.format(format, args)));
+ }
+ }
+
+ private static final Comparator> BREAKPOINT_COMPARATOR = new Comparator>() {
+
+ @Override
+ public int compare(Entry entry1, Entry entry2) {
+ return entry1.getKey().name().compareTo(entry2.getKey().name());
+ }
+ };
+
+ private final Debugger executionSupport;
+ private final BreakpointCallback breakpointCallback;
+ private final WarningLog warningLog;
+
+ /**
+ * Map: Tags ==> Tag Breakpoints. There may be no more than one breakpoint per Tag.
+ */
+ private final Map tagToBreakpoint = new HashMap<>();
+
+ /**
+ * Globally suspends all line breakpoint activity when {@code false}, ignoring whether
+ * individual breakpoints are enabled.
+ */
+ @CompilationFinal private boolean breakpointsActive = true;
+ private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
+
+ TagBreakpointFactory(Debugger executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
+ this.executionSupport = executionSupport;
+ this.breakpointCallback = breakpointCallback;
+ this.warningLog = warningLog;
+
+ Probe.addProbeListener(new DefaultProbeListener() {
+
+ @Override
+ public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
+ final TagBreakpointImpl breakpoint = tagToBreakpoint.get(tag);
+ if (breakpoint != null) {
+ try {
+ breakpoint.attach(probe);
+ } catch (IOException e) {
+ warningLog.addWarning(BREAKPOINT_NAME + " failure attaching to newly tagged Probe: " + e.getMessage());
+ if (TRACE) {
+ OUT.println(BREAKPOINT_NAME + " failure: " + e.getMessage());
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Globally enables tag breakpoint activity; all breakpoints are ignored when set to
+ * {@code false}. When set to {@code true}, the enabled/disabled status of each breakpoint
+ * determines whether it will trigger when flow of execution reaches it.
+ *
+ * @param breakpointsActive
+ */
+ void setActive(boolean breakpointsActive) {
+ if (this.breakpointsActive != breakpointsActive) {
+ breakpointsActiveUnchanged.invalidate();
+ this.breakpointsActive = breakpointsActive;
+ }
+ }
+
+ /**
+ * Gets all current tag breakpoints,regardless of status; sorted and modification safe.
+ */
+ List getAll() {
+ ArrayList> entries = new ArrayList<>(tagToBreakpoint.entrySet());
+ Collections.sort(entries, BREAKPOINT_COMPARATOR);
+
+ final ArrayList breakpoints = new ArrayList<>(entries.size());
+ for (Entry entry : entries) {
+ breakpoints.add(entry.getValue());
+ }
+ return breakpoints;
+ }
+
+ /**
+ * Creates a new tag breakpoint if one doesn't already exist. If one does exist, then resets the
+ * ignore count.
+ *
+ * @param tag where to set the breakpoint
+ * @param ignoreCount number of initial hits before the breakpoint starts causing breaks.
+ * @param oneShot whether the breakpoint should dispose itself after one hit
+ * @return a possibly new breakpoint
+ * @throws IOException if a breakpoint already exists for the tag and the ignore count is the
+ * same
+ */
+ TagBreakpoint create(int ignoreCount, SyntaxTag tag, boolean oneShot) throws IOException {
+
+ TagBreakpointImpl breakpoint = tagToBreakpoint.get(tag);
+
+ if (breakpoint == null) {
+ breakpoint = new TagBreakpointImpl(ignoreCount, tag, oneShot);
+
+ if (TRACE) {
+ trace("NEW " + breakpoint.getShortDescription());
+ }
+
+ tagToBreakpoint.put(tag, breakpoint);
+
+ for (Probe probe : Probe.findProbesTaggedAs(tag)) {
+ breakpoint.attach(probe);
+ }
+ } else {
+ if (ignoreCount == breakpoint.getIgnoreCount()) {
+ throw new IOException(BREAKPOINT_NAME + " already set for tag " + tag.name());
+ }
+ breakpoint.setIgnoreCount(ignoreCount);
+ if (TRACE) {
+ trace("CHANGED ignoreCount %s", breakpoint.getShortDescription());
+ }
+ }
+ return breakpoint;
+ }
+
+ /**
+ * Returns the {@link TagBreakpoint} for a given tag, {@code null} if none.
+ */
+ TagBreakpoint get(SyntaxTag tag) {
+ return tagToBreakpoint.get(tag);
+ }
+
+ /**
+ * Removes the associated instrumentation for all one-shot breakpoints only.
+ */
+ void disposeOneShots() {
+ List breakpoints = new ArrayList<>(tagToBreakpoint.values());
+ for (TagBreakpointImpl breakpoint : breakpoints) {
+ if (breakpoint.isOneShot()) {
+ breakpoint.dispose();
+ }
+ }
+ }
+
+ /**
+ * Removes all knowledge of a breakpoint, presumed disposed.
+ */
+ private void forget(TagBreakpointImpl breakpoint) {
+ tagToBreakpoint.remove(breakpoint.getTag());
+ }
+
+ /**
+ * Concrete representation of a line breakpoint, implemented by attaching an instrument to a
+ * probe at the designated source location.
+ */
+ private final class TagBreakpointImpl extends TagBreakpoint implements AdvancedInstrumentResultListener {
+
+ private static final String SHOULD_NOT_HAPPEN = "TagBreakpointImpl: should not happen";
+
+ private final SyntaxTag tag;
+
+ // Cached assumption that the global status of tag breakpoint activity has not changed.
+ private Assumption breakpointsActiveAssumption;
+
+ // Whether this breakpoint is enable/disabled
+ @CompilationFinal private boolean isEnabled;
+ private Assumption enabledUnchangedAssumption;
+
+ private String conditionExpr;
+
+ /**
+ * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
+ * {@code null} if not attached.
+ */
+ private List instruments = new ArrayList<>();
+
+ private TagBreakpointImpl(int ignoreCount, SyntaxTag tag, boolean oneShot) {
+ super(ENABLED, ignoreCount, oneShot);
+ this.tag = tag;
+ this.breakpointsActiveAssumption = TagBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+ this.isEnabled = true;
+ this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged");
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return isEnabled;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ // Tag Breakpoints are never unresolved
+ if (enabled != isEnabled) {
+ switch (getState()) {
+ case ENABLED:
+ assert !enabled : SHOULD_NOT_HAPPEN;
+ doSetEnabled(false);
+ changeState(DISABLED);
+ break;
+ case DISABLED:
+ assert enabled : SHOULD_NOT_HAPPEN;
+ doSetEnabled(true);
+ changeState(ENABLED);
+ break;
+ case DISPOSED:
+ assert false : "breakpoint disposed";
+ break;
+ case ENABLED_UNRESOLVED:
+ case DISABLED_UNRESOLVED:
+ default:
+ assert false : SHOULD_NOT_HAPPEN;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void setCondition(String expr) throws IOException {
+ if (this.conditionExpr != null || expr != null) {
+ // De-instrument the Probes instrumented by this breakpoint
+ final ArrayList probes = new ArrayList<>();
+ for (Instrument instrument : instruments) {
+ probes.add(instrument.getProbe());
+ instrument.dispose();
+ }
+ instruments.clear();
+ this.conditionExpr = expr;
+ // Re-instrument the probes previously instrumented
+ for (Probe probe : probes) {
+ attach(probe);
+ }
+ }
+ }
+
+ @Override
+ public String getCondition() {
+ return conditionExpr;
+ }
+
+ @Override
+ public void dispose() {
+ if (getState() != DISPOSED) {
+ for (Instrument instrument : instruments) {
+ instrument.dispose();
+ }
+ changeState(DISPOSED);
+ TagBreakpointFactory.this.forget(this);
+ }
+ }
+
+ private void attach(Probe newProbe) throws IOException {
+ if (getState() == DISPOSED) {
+ throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
+ }
+ Instrument newInstrument = null;
+ if (conditionExpr == null) {
+ newInstrument = Instrument.create(new UnconditionalTagBreakInstrumentListener(), BREAKPOINT_NAME);
+ } else {
+ newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+ }
+ newProbe.attach(newInstrument);
+ instruments.add(newInstrument);
+ changeState(isEnabled ? ENABLED : DISABLED);
+ }
+
+ private void doSetEnabled(boolean enabled) {
+ if (this.isEnabled != enabled) {
+ enabledUnchangedAssumption.invalidate();
+ this.isEnabled = enabled;
+ }
+ }
+
+ private String getShortDescription() {
+ return BREAKPOINT_NAME + "@" + tag.name();
+ }
+
+ private void changeState(State after) {
+ if (TRACE) {
+ trace("STATE %s-->%s %s", getState().getName(), after.getName(), getShortDescription());
+ }
+ setState(after);
+ }
+
+ private void doBreak(Node node, VirtualFrame vFrame) {
+ if (incrHitCountCheckIgnore()) {
+ breakpointCallback.haltedAt(node, vFrame.materialize(), BREAKPOINT_NAME);
+ }
+ }
+
+ /**
+ * Receives notification from the attached instrument that execution is about to enter node
+ * where the breakpoint is set. Designed so that when in the fast path, there is either an
+ * unconditional "halt" call to the debugger or nothing.
+ */
+ private void nodeEnter(Node astNode, VirtualFrame vFrame) {
+
+ // Deopt if the global active/inactive flag has changed
+ try {
+ this.breakpointsActiveAssumption.check();
+ } catch (InvalidAssumptionException ex) {
+ this.breakpointsActiveAssumption = TagBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+ }
+
+ // Deopt if the enabled/disabled state of this breakpoint has changed
+ try {
+ this.enabledUnchangedAssumption.check();
+ } catch (InvalidAssumptionException ex) {
+ this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption("LineBreakpoint enabled state unchanged");
+ }
+
+ if (TagBreakpointFactory.this.breakpointsActive && this.isEnabled) {
+ if (isOneShot()) {
+ dispose();
+ }
+ TagBreakpointImpl.this.doBreak(astNode, vFrame);
+ }
+
+ }
+
+ public void notifyResult(Node node, VirtualFrame vFrame, Object result) {
+ final boolean condition = (Boolean) result;
+ if (TRACE) {
+ trace("breakpoint condition = %b %s", condition, getShortDescription());
+ }
+ if (condition) {
+ nodeEnter(node, vFrame);
+ }
+ }
+
+ public void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex) {
+ warningLog.addWarning(String.format("Exception in %s: %s", getShortDescription(), ex.getMessage()));
+ if (TRACE) {
+ trace("breakpoint failure = %s %s", ex.toString(), getShortDescription());
+ }
+ // Take the breakpoint if evaluation fails.
+ nodeEnter(node, vFrame);
+ }
+
+ @Override
+ public String getLocationDescription() {
+ return "Tag " + tag.name();
+ }
+
+ @Override
+ public SyntaxTag getTag() {
+ return tag;
+ }
+
+ private final class UnconditionalTagBreakInstrumentListener extends DefaultStandardInstrumentListener {
+
+ @Override
+ public void enter(Probe probe, Node node, VirtualFrame vFrame) {
+ TagBreakpointImpl.this.nodeEnter(node, vFrame);
+ }
+ }
+
+ }
+
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/package-info.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/package-info.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/package-info.java Sat Jul 18 18:03:36 2015 +0200
@@ -1,35 +1,31 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE
+ * COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * This code is free software; you can redistribute 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 free software; you can redistribute 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
+ * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version 2 along with this work;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
*
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com
+ * if you need additional information or have any questions.
*/
/**
* Representation of a {@link com.oracle.truffle.api.frame.Frame stack frame}. While
- * {@link com.oracle.truffle.api.TruffleLanguage based language}
- * is executing its stack parameters
- * and local variables are represented by {@link com.oracle.truffle.api.frame.VirtualFrame}. Such a frame
- * can be converted into {@link com.oracle.truffle.api.frame.MaterializedFrame} stored on a heap for
- * later access when the actual stack is elsewhere.
+ * {@link com.oracle.truffle.api.TruffleLanguage based language} is executing its stack parameters
+ * and local variables are represented by {@link com.oracle.truffle.api.frame.VirtualFrame}. Such a
+ * frame can be converted into {@link com.oracle.truffle.api.frame.MaterializedFrame} stored on a
+ * heap for later access when the actual stack is elsewhere.
*/
package com.oracle.truffle.api.frame;
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Sat Jul 18 18:03:36 2015 +0200
@@ -31,6 +31,8 @@
import com.oracle.truffle.api.*;
import com.oracle.truffle.api.debug.*;
import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.vm.*;
@@ -40,6 +42,10 @@
public abstract class Accessor {
private static Accessor API;
private static Accessor SPI;
+ private static Accessor NODES;
+ private static Accessor INSTRUMENT;
+ private static Accessor DEBUG;
+
static {
TruffleLanguage lng = new TruffleLanguage(null) {
@Override
@@ -73,6 +79,14 @@
}
};
lng.hashCode();
+ new Node(null) {
+ }.getRootNode();
+
+ try {
+ Class.forName(Debugger.class.getName(), true, Debugger.class.getClassLoader());
+ } catch (ClassNotFoundException ex) {
+ throw new IllegalStateException(ex);
+ }
}
protected Accessor() {
@@ -81,6 +95,21 @@
throw new IllegalStateException();
}
API = this;
+ } else if (this.getClass().getSimpleName().endsWith("Nodes")) {
+ if (NODES != null) {
+ throw new IllegalStateException();
+ }
+ NODES = this;
+ } else if (this.getClass().getSimpleName().endsWith("Instrument")) {
+ if (INSTRUMENT != null) {
+ throw new IllegalStateException();
+ }
+ INSTRUMENT = this;
+ } else if (this.getClass().getSimpleName().endsWith("Debug")) {
+ if (DEBUG != null) {
+ throw new IllegalStateException();
+ }
+ DEBUG = this;
} else {
if (SPI != null) {
throw new IllegalStateException();
@@ -117,16 +146,36 @@
return API.getDebugSupport(l);
}
- protected Object invoke(Object obj, Object[] args) throws IOException {
+ protected Object invoke(TruffleLanguage lang, Object obj, Object[] args) throws IOException {
for (SymbolInvoker si : ServiceLoader.load(SymbolInvoker.class)) {
- return si.invoke(obj, args);
+ return si.invoke(lang, obj, args);
}
throw new IOException("No symbol invoker found!");
}
+ protected Class extends TruffleLanguage> findLanguage(RootNode n) {
+ return NODES.findLanguage(n);
+ }
+
+ protected Class extends TruffleLanguage> findLanguage(Probe probe) {
+ return INSTRUMENT.findLanguage(probe);
+ }
+
+ protected TruffleLanguage findLanguage(TruffleVM vm, Class extends TruffleLanguage> languageClass) {
+ return API.findLanguage(vm, languageClass);
+ }
+
+ protected Closeable executionStart(TruffleVM vm, Debugger[] fillIn, Source s) {
+ return DEBUG.executionStart(vm, fillIn, s);
+ }
+
+ protected void dispatchEvent(TruffleVM vm, Object event) {
+ SPI.dispatchEvent(vm, event);
+ }
+
/**
* Don't call me. I am here only to let NetBeans debug any Truffle project.
- *
+ *
* @param args
*/
public static void main(String... args) {
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java Sat Jul 18 18:03:36 2015 +0200
@@ -24,6 +24,7 @@
*/
package com.oracle.truffle.api.impl;
+import com.oracle.truffle.api.TruffleLanguage;
import java.io.*;
/**
@@ -31,5 +32,5 @@
* associated nodes too much.
*/
public abstract class SymbolInvoker {
- protected abstract Object invoke(Object symbol, Object... args) throws IOException;
+ protected abstract Object invoke(TruffleLanguage lang, Object symbol, Object... args) throws IOException;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Sat Jul 18 18:03:36 2015 +0200
@@ -42,8 +42,8 @@
*
*
* Client-oriented documentation for the use of Instruments is available online at https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events
+ * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events" >https://
+ * wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events
*
* The implementation of Instruments is complicated by the requirement that Truffle be able to clone
* ASTs at any time. In particular, any instrumentation-supporting Nodes that have been attached to
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java Sat Jul 18 18:03:36 2015 +0200
@@ -30,6 +30,7 @@
import com.oracle.truffle.api.*;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.impl.Accessor;
import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
import com.oracle.truffle.api.nodes.*;
import com.oracle.truffle.api.source.*;
@@ -47,8 +48,8 @@
*
*
* Client-oriented documentation for the use of Probes is available online at https://wiki.openjdk.java.net/display/Graal/Finding+Probes
+ * HREF="https://wiki.openjdk.java.net/display/Graal/Finding+Probes" >https://wiki.openjdk.java.
+ * net/display/Graal/Finding+Probes
*
*
Implementation notes:
*
@@ -100,6 +101,7 @@
* @see SyntaxTag
*/
public final class Probe {
+ private final Class extends TruffleLanguage> language;
private static final boolean TRACE = false;
private static final String TRACE_PREFIX = "PROBE: ";
@@ -303,7 +305,7 @@
/**
* Intended for use only by {@link ProbeNode}.
*/
- Probe(ProbeNode probeNode, SourceSection sourceSection) {
+ Probe(Class extends TruffleLanguage> l, ProbeNode probeNode, SourceSection sourceSection) {
this.sourceSection = sourceSection;
probes.add(new WeakReference<>(this));
registerProbeNodeClone(probeNode);
@@ -314,6 +316,7 @@
for (ProbeListener listener : probeListeners) {
listener.newProbeInserted(this);
}
+ this.language = l;
}
/**
@@ -483,4 +486,18 @@
sb.append("]");
return sb.toString();
}
+
+ static final class AccessorInstrument extends Accessor {
+ @Override
+ protected Class extends TruffleLanguage> findLanguage(RootNode n) {
+ return super.findLanguage(n);
+ }
+
+ @Override
+ protected Class extends TruffleLanguage> findLanguage(Probe probe) {
+ return probe.language;
+ }
+ }
+
+ static final AccessorInstrument ACCESSOR = new AccessorInstrument();
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java Sat Jul 18 18:03:36 2015 +0200
@@ -26,6 +26,7 @@
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode;
import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
@@ -120,7 +121,8 @@
public static Probe insertProbe(WrapperNode wrapper) {
final SourceSection sourceSection = wrapper.getChild().getSourceSection();
final ProbeNode probeNode = new ProbeNode(); // private constructor
- probeNode.probe = new Probe(probeNode, sourceSection); // package private access
+ Class extends TruffleLanguage> l = Probe.ACCESSOR.findLanguage(wrapper.getChild().getRootNode());
+ probeNode.probe = new Probe(l, probeNode, sourceSection); // package private access
wrapper.insertProbe(probeNode);
return probeNode.probe;
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE
+ * COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * This code is free software; you can redistribute 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 free software; you can redistribute 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
+ * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version 2 along with this work;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
*
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com
+ * if you need additional information or have any questions.
*/
/**
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Sat Jul 18 18:03:36 2015 +0200
@@ -245,7 +245,7 @@
protected void setNodeProperty(Object node, String propertyName, Object value) {
Element nodeElem = getElementByObject(node);
Element propElem = getPropertyElement(node, propertyName); // if property exists, replace
- // its value
+ // its value
if (null == propElem) { // if property doesn't exist, create one
propElem = dom.createElement("p");
propElem.setAttribute("name", propertyName);
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Sat Jul 18 18:03:36 2015 +0200
@@ -30,6 +30,7 @@
import com.oracle.truffle.api.*;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.impl.Accessor;
import com.oracle.truffle.api.instrument.*;
import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
import com.oracle.truffle.api.source.*;
@@ -39,7 +40,6 @@
* Abstract base class for all Truffle nodes.
*/
public abstract class Node implements NodeInterface, Cloneable {
-
private final NodeClass nodeClass;
@CompilationFinal private Node parent;
@CompilationFinal private SourceSection sourceSection;
@@ -587,4 +587,14 @@
IN_ATOMIC_BLOCK.set(IN_ATOMIC_BLOCK.get() - 1);
return true;
}
+
+ private static final class AccessorNodes extends Accessor {
+ @Override
+ protected Class extends TruffleLanguage> findLanguage(RootNode n) {
+ return n.language;
+ }
+ }
+
+ // registers into Accessor.NODES
+ @SuppressWarnings("unused") private static final AccessorNodes ACCESSOR = new AccessorNodes();
}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Sat Jul 18 18:03:36 2015 +0200
@@ -37,20 +37,57 @@
* {@link TruffleRuntime#createCallTarget(RootNode)}.
*/
public abstract class RootNode extends Node {
-
+ final Class extends TruffleLanguage> language;
private RootCallTarget callTarget;
@CompilationFinal private FrameDescriptor frameDescriptor;
+ /**
+ * @deprecated each RootNode should be associated with a {@link TruffleLanguage} use constructor
+ * that allows you to specify it. This method will be removed on Aug 15, 2015.
+ */
+ @Deprecated
protected RootNode() {
- this(null, null);
+ this(null, null, null, false);
+ }
+
+ /**
+ * @deprecated each RootNode should be associated with a {@link TruffleLanguage} use constructor
+ * that allows you to specify it. This method will be removed on Aug 15, 2015.
+ */
+ @Deprecated
+ protected RootNode(SourceSection sourceSection) {
+ this(null, sourceSection, null, false);
}
- protected RootNode(SourceSection sourceSection) {
- this(sourceSection, null);
+ /**
+ * @deprecated each RootNode should be associated with a {@link TruffleLanguage} use constructor
+ * that allows you to specify it. This method will be removed on Aug 15, 2015.
+ */
+ @Deprecated
+ protected RootNode(SourceSection sourceSection, FrameDescriptor frameDescriptor) {
+ this(null, sourceSection, frameDescriptor, false);
}
- protected RootNode(SourceSection sourceSection, FrameDescriptor frameDescriptor) {
+ /**
+ * Creates new root node. Each {@link RootNode} is associated with a particular language - if
+ * the root node represents a method it is assumed the method is written in such language.
+ *
+ * @param language the language of the node, cannot benull
+ * @param sourceSection a part of source associated with this node, can be null
+ * @param frameDescriptor descriptor of slots, can be null
+ */
+ protected RootNode(Class extends TruffleLanguage> language, SourceSection sourceSection, FrameDescriptor frameDescriptor) {
+ this(language, sourceSection, frameDescriptor, true);
+ }
+
+ private RootNode(Class extends TruffleLanguage> language, SourceSection sourceSection, FrameDescriptor frameDescriptor, boolean checkLanguage) {
super(sourceSection);
+ if (checkLanguage) {
+ if (!TruffleLanguage.class.isAssignableFrom(language)) {
+ throw new IllegalStateException();
+ }
+ }
+ this.language = language;
if (frameDescriptor == null) {
this.frameDescriptor = new FrameDescriptor();
} else {
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/package-info.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/package-info.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/package-info.java Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE
+ * COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * This code is free software; you can redistribute 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 free software; you can redistribute 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
+ * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version 2 along with this work;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
*
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com
+ * if you need additional information or have any questions.
*/
/**
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/package-info.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/package-info.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/package-info.java Sat Jul 18 18:03:36 2015 +0200
@@ -1,31 +1,28 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE
+ * COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * This code is free software; you can redistribute 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 free software; you can redistribute 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
+ * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version 2 along with this work;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
*
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com
+ * if you need additional information or have any questions.
*/
/**
- * Do you want to implement your own {@link com.oracle.truffle.api.TruffleLanguage Truffle based language}?
- * In such case start {@link com.oracle.truffle.api.TruffleLanguage here}.
+ * Do you want to implement your own {@link com.oracle.truffle.api.TruffleLanguage Truffle based
+ * language}? In such case start {@link com.oracle.truffle.api.TruffleLanguage here}.
*/
package com.oracle.truffle.api;
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/package-info.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/package-info.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/package-info.java Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE
+ * COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * This code is free software; you can redistribute 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 free software; you can redistribute 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
+ * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version 2 along with this work;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
*
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com
+ * if you need additional information or have any questions.
*/
/**
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/EventConsumer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/EventConsumer.java Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.vm;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.debug.ExecutionEvent;
+import com.oracle.truffle.api.debug.SuspendedEvent;
+
+/**
+ * {@link TruffleVM} generates various events and delivers them to
+ * {@link TruffleVM.Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer) registered} handlers.
+ * Each handler is registered for a particular type of event. Examples of events include
+ * {@link ExecutionEvent} or {@link SuspendedEvent} useful when debugging {@link TruffleLanguage
+ * Truffle language}s.
+ *
+ * @param type of event to observe and handle
+ */
+public abstract class EventConsumer {
+ final Class type;
+
+ /**
+ * Creates new handler for specified event type.
+ *
+ * @param eventType type of events to handle
+ */
+ public EventConsumer(Class eventType) {
+ this.type = eventType;
+ }
+
+ /**
+ * Called by the {@link TruffleVM} when event of requested type appears.
+ *
+ * @param event the instance of an event of the request type
+ */
+ protected abstract void on(Event event);
+}
diff -r 324997830dc9 -r 5bc7f7b867ab truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Sat Jul 18 18:03:36 2015 +0200
@@ -63,6 +63,8 @@
private final Reader in;
private final Writer err;
private final Writer out;
+ private final EventConsumer>[] handlers;
+ private Debugger debugger;
/**
* Private & temporary only constructor.
@@ -73,6 +75,7 @@
this.err = null;
this.out = null;
this.langs = null;
+ this.handlers = null;
}
/**
@@ -82,10 +85,11 @@
* @param err stderr
* @param in stdin
*/
- private TruffleVM(Writer out, Writer err, Reader in) {
+ private TruffleVM(Writer out, Writer err, Reader in, EventConsumer>[] handlers) {
this.out = out;
this.err = err;
this.in = in;
+ this.handlers = handlers;
this.initThread = Thread.currentThread();
this.langs = new HashMap<>();
Enumeration en;
@@ -169,12 +173,13 @@
private Writer out;
private Writer err;
private Reader in;
+ private List> handlers = new ArrayList<>();
Builder() {
}
/**
- * Changes the defaut output for languages running in to be created
+ * Changes the default output for languages running in to be created
* {@link TruffleVM virtual machine}. The default is to use {@link System#out}.
*
* @param w the writer to use as output
@@ -210,6 +215,19 @@
}
/**
+ * Registers another instance of {@link EventConsumer} into the to be created
+ * {@link TruffleVM}.
+ *
+ * @param handler the handler to register
+ * @return instance of this builder
+ */
+ public Builder onEvent(EventConsumer> handler) {
+ handler.getClass();
+ handlers.add(handler);
+ return this;
+ }
+
+ /**
* Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from
* values passed into configuration methods in this class.
*
@@ -225,7 +243,7 @@
if (in == null) {
in = new InputStreamReader(System.in);
}
- return new TruffleVM(out, err, in);
+ return new TruffleVM(out, err, in, handlers.toArray(new EventConsumer[0]));
}
}
@@ -273,7 +291,7 @@
if (l == null) {
throw new IOException("No language for " + location + " with MIME type " + mimeType + " found. Supported types: " + langs.keySet());
}
- return SPI.eval(l, s);
+ return eval(l, s);
}
/**
@@ -291,7 +309,7 @@
if (l == null) {
throw new IOException("No language for MIME type " + mimeType + " found. Supported types: " + langs.keySet());
}
- return SPI.eval(l, Source.fromReader(reader, mimeType));
+ return eval(l, Source.fromReader(reader, mimeType));
}
/**
@@ -309,7 +327,18 @@
if (l == null) {
throw new IOException("No language for MIME type " + mimeType + " found. Supported types: " + langs.keySet());
}
- return SPI.eval(l, Source.fromText(code, mimeType));
+ return eval(l, Source.fromText(code, mimeType));
+ }
+
+ private Object eval(TruffleLanguage l, Source s) throws IOException {
+ TruffleVM.findDebuggerSupport(l);
+ Debugger[] fillIn = {debugger};
+ try (Closeable d = SPI.executionStart(this, fillIn, s)) {
+ if (debugger == null) {
+ debugger = fillIn[0];
+ }
+ return SPI.eval(l, s);
+ }
}
/**
@@ -331,12 +360,14 @@
*/
public Symbol findGlobalSymbol(String globalName) {
checkThread();
+ TruffleLanguage lang = null;
Object obj = null;
Object global = null;
for (Language dl : langs.values()) {
TruffleLanguage l = dl.getImpl();
obj = SPI.findExportedSymbol(l, globalName, true);
if (obj != null) {
+ lang = l;
global = SPI.languageGlobal(l);
break;
}
@@ -346,12 +377,13 @@
TruffleLanguage l = dl.getImpl();
obj = SPI.findExportedSymbol(l, globalName, false);
if (obj != null) {
+ lang = l;
global = SPI.languageGlobal(l);
break;
}
}
}
- return obj == null ? null : new Symbol(obj, global);
+ return obj == null ? null : new Symbol(lang, obj, global);
}
private void checkThread() {
@@ -366,15 +398,46 @@
return l == null ? null : l.getImpl();
}
+ @SuppressWarnings("all")
+ void dispatch(Object ev) {
+ Class type = ev.getClass();
+ if (type == SuspendedEvent.class) {
+ dispatchSuspendedEvent((SuspendedEvent) ev);
+ }
+ if (type == ExecutionEvent.class) {
+ dispatchExecutionEvent((ExecutionEvent) ev);
+ }
+ dispatch(type, ev);
+ }
+
+ @SuppressWarnings("unused")
+ void dispatchSuspendedEvent(SuspendedEvent event) {
+ }
+
+ @SuppressWarnings("unused")
+ void dispatchExecutionEvent(ExecutionEvent event) {
+ }
+
+ @SuppressWarnings("all")
+ void dispatch(Class type, Event event) {
+ for (EventConsumer handler : handlers) {
+ if (handler.type == type) {
+ handler.on(event);
+ }
+ }
+ }
+
/**
* Represents {@link TruffleVM#findGlobalSymbol(java.lang.String) global symbol} provided by one
* of the initialized languages in {@link TruffleVM Truffle virtual machine}.
*/
public class Symbol {
+ private final TruffleLanguage language;
private final Object obj;
private final Object global;
- Symbol(Object obj, Object global) {
+ Symbol(TruffleLanguage language, Object obj, Object global) {
+ this.language = language;
this.obj = obj;
this.global = global;
}
@@ -392,16 +455,22 @@
* @throws IOException signals problem during execution
*/
public Object invoke(Object thiz, Object... args) throws IOException {
- List