# HG changeset patch # User Lukas Stadler # Date 1397209991 -7200 # Node ID f675818d9ad09b4b0a8da907bc3961cc233b2436 # Parent 36e1a11a72b3a9c139c265c31ad36c7d857b6b7c new getStackTrace and getCurrentFrame functionality in TruffleRuntime diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle.hotspot; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.stack.*; +import com.oracle.graal.graph.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.nodes.*; + +public abstract class HotSpotFrameInstance implements FrameInstance { + + private final InspectedFrame stackFrame; + + public HotSpotFrameInstance(InspectedFrame stackFrame) { + this.stackFrame = stackFrame; + } + + protected abstract int getNotifyIndex(); + + protected abstract int getCallTargetIndex(); + + protected abstract int getFrameIndex(); + + @SlowPath + public Frame getFrame(FrameAccess access, boolean slowPath) { + if (access == FrameAccess.NONE) { + return null; + } + if (!slowPath) { + MaterializedFrameNotify notify = (MaterializedFrameNotify) stackFrame.getLocal(getNotifyIndex()); + if (access.ordinal() > notify.getOutsideFrameAccess().ordinal()) { + notify.setOutsideFrameAccess(access); + } + if (stackFrame.isVirtual(getFrameIndex())) { + stackFrame.materializeVirtualObjects(true); + } + } + switch (access) { + case READ_ONLY: { + Frame frame = (Frame) stackFrame.getLocal(getFrameIndex()); + // assert that it is really used read only + assert (frame = new ReadOnlyFrame(frame)) != null; + return frame; + } + case READ_WRITE: + case MATERIALIZE: + if (stackFrame.isVirtual(getFrameIndex())) { + stackFrame.materializeVirtualObjects(false); + } + return (Frame) stackFrame.getLocal(getFrameIndex()); + default: + throw GraalInternalError.unimplemented(); + } + } + + public boolean isVirtualFrame() { + return stackFrame.isVirtual(getFrameIndex()); + } + + public CallTarget getCallTarget() { + return (CallTarget) stackFrame.getLocal(getCallTargetIndex()); + } + + public CallNode getCallNode() { + Object receiver = stackFrame.getLocal(getNotifyIndex()); + if (receiver instanceof CallNode) { + return (CallNode) receiver; + } else { + return null; + } + } + + /** + * This class represents a frame that is taken from the + * {@link DefaultCallNode#callProxy(MaterializedFrameNotify, CallTarget, VirtualFrame, Object[])} + * method. + */ + public static final class NextFrame extends HotSpotFrameInstance { + public static final Method METHOD; + static { + try { + METHOD = DefaultCallNode.class.getDeclaredMethod("callProxy", MaterializedFrameNotify.class, CallTarget.class, VirtualFrame.class, Object[].class); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + } + private static final int NOTIFY_INDEX = 0; + private static final int CALL_TARGET_INDEX = 1; + private static final int FRAME_INDEX = 2; + + public NextFrame(InspectedFrame stackFrame) { + super(stackFrame); + } + + @Override + protected int getNotifyIndex() { + return NOTIFY_INDEX; + } + + @Override + protected int getCallTargetIndex() { + return CALL_TARGET_INDEX; + } + + @Override + protected int getFrameIndex() { + return FRAME_INDEX; + } + } + + /** + * This class represents a frame that is taken from the + * {@link RootCallTarget#callProxy(VirtualFrame)} method. + */ + @SuppressWarnings("javadoc") + public static final class CurrentFrame extends HotSpotFrameInstance { + public static final Method METHOD; + static { + try { + METHOD = RootCallTarget.class.getDeclaredMethod("callProxy", VirtualFrame.class); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + } + private static final int NOTIFY_INDEX = 0; + private static final int CALL_TARGET_INDEX = 0; + private static final int FRAME_INDEX = 1; + + public CurrentFrame(InspectedFrame stackFrame) { + super(stackFrame); + } + + @Override + public Frame getFrame(FrameAccess access, boolean slowPath) { + if (!slowPath) { + throw new UnsupportedOperationException("cannot access current frame as fast path"); + } + return super.getFrame(access, slowPath); + } + + @Override + protected int getNotifyIndex() { + return NOTIFY_INDEX; + } + + @Override + protected int getCallTargetIndex() { + return CALL_TARGET_INDEX; + } + + @Override + protected int getFrameIndex() { + return FRAME_INDEX; + } + } +} diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Fri Apr 11 11:53:11 2014 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.code.stack.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.target.*; @@ -48,6 +49,7 @@ import com.oracle.graal.runtime.*; import com.oracle.graal.truffle.*; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; @@ -63,6 +65,7 @@ private TruffleCompiler truffleCompiler; private Replacements truffleReplacements; + private StackIntrospection stackIntrospection; private ArrayList includes; private ArrayList excludes; @@ -212,4 +215,42 @@ RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class); return runtimeProvider.getHostBackend().getProviders(); } + + @SlowPath + public Iterable getStackTrace() { + if (stackIntrospection == null) { + stackIntrospection = Graal.getRequiredCapability(StackIntrospection.class); + } + ResolvedJavaMethod method = getGraalProviders().getMetaAccess().lookupJavaMethod(HotSpotFrameInstance.NextFrame.METHOD); + final Iterator frames = stackIntrospection.getStackTrace(method, method).iterator(); + class FrameIterator implements Iterator { + public boolean hasNext() { + return frames.hasNext(); + } + + public FrameInstance next() { + InspectedFrame frame = frames.next(); + return new HotSpotFrameInstance.NextFrame(frame); + } + } + return new Iterable() { + public Iterator iterator() { + return new FrameIterator(); + } + }; + } + + public FrameInstance getCurrentFrame() { + if (stackIntrospection == null) { + stackIntrospection = Graal.getRequiredCapability(StackIntrospection.class); + } + ResolvedJavaMethod method = getGraalProviders().getMetaAccess().lookupJavaMethod(HotSpotFrameInstance.CurrentFrame.METHOD); + Iterator frames = stackIntrospection.getStackTrace(method, method).iterator(); + if (frames.hasNext()) { + return new HotSpotFrameInstance.CurrentFrame(frames.next()); + } else { + System.out.println("no current frame found"); + return null; + } + } } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/ReadOnlyFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/ReadOnlyFrame.java Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle.hotspot; + +import com.oracle.graal.graph.*; +import com.oracle.truffle.api.frame.*; + +class ReadOnlyFrame implements Frame { + private final Frame delegate; + + public ReadOnlyFrame(Frame delegate) { + this.delegate = delegate; + } + + public FrameDescriptor getFrameDescriptor() { + return delegate.getFrameDescriptor(); + } + + public Object[] getArguments() { + return delegate.getArguments().clone(); + } + + public Object getObject(FrameSlot slot) throws FrameSlotTypeException { + return delegate.getObject(slot); + } + + public void setObject(FrameSlot slot, Object value) { + throw GraalInternalError.shouldNotReachHere(); + } + + public byte getByte(FrameSlot slot) throws FrameSlotTypeException { + return delegate.getByte(slot); + } + + public void setByte(FrameSlot slot, byte value) { + throw GraalInternalError.shouldNotReachHere(); + } + + public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException { + return delegate.getBoolean(slot); + } + + public void setBoolean(FrameSlot slot, boolean value) { + throw GraalInternalError.shouldNotReachHere(); + } + + public int getInt(FrameSlot slot) throws FrameSlotTypeException { + return delegate.getInt(slot); + } + + public void setInt(FrameSlot slot, int value) { + throw GraalInternalError.shouldNotReachHere(); + } + + public long getLong(FrameSlot slot) throws FrameSlotTypeException { + return delegate.getLong(slot); + } + + public void setLong(FrameSlot slot, long value) { + throw GraalInternalError.shouldNotReachHere(); + } + + public float getFloat(FrameSlot slot) throws FrameSlotTypeException { + return delegate.getFloat(slot); + } + + public void setFloat(FrameSlot slot, float value) { + throw GraalInternalError.shouldNotReachHere(); + } + + public double getDouble(FrameSlot slot) throws FrameSlotTypeException { + return delegate.getDouble(slot); + } + + public void setDouble(FrameSlot slot, double value) { + throw GraalInternalError.shouldNotReachHere(); + } + + public Object getValue(FrameSlot slot) { + return delegate.getValue(slot); + } + + public MaterializedFrame materialize() { + throw GraalInternalError.shouldNotReachHere(); + } + + public boolean isObject(FrameSlot slot) { + return delegate.isObject(slot); + } + + public boolean isByte(FrameSlot slot) { + return delegate.isByte(slot); + } + + public boolean isBoolean(FrameSlot slot) { + return delegate.isBoolean(slot); + } + + public boolean isInt(FrameSlot slot) { + return delegate.isInt(slot); + } + + public boolean isLong(FrameSlot slot) { + return delegate.isLong(slot); + } + + public boolean isFloat(FrameSlot slot) { + return delegate.isFloat(slot); + } + + public boolean isDouble(FrameSlot slot) { + return delegate.isDouble(slot); + } +} \ No newline at end of file diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Fri Apr 11 11:53:11 2014 +0200 @@ -26,6 +26,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter; @@ -74,14 +75,14 @@ } @Override - public Object call(Object[] arguments) { + public Object call(VirtualFrame frame, Object[] arguments) { if (CompilerDirectives.inInterpreter()) { interpreterCall(); if (inliningCounter.get() > 0 || inliningForced) { return getCurrentCallTarget().callInlined(arguments); } } - return getCurrentCallTarget().call(arguments); + return callProxy(this, getCurrentCallTarget(), frame, arguments); } private void interpreterCall() { diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Apr 11 11:53:11 2014 +0200 @@ -162,13 +162,17 @@ public final Object executeHelper(Object[] args) { VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), args); - return getRootNode().execute(frame); + return callProxy(frame); } public static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, Object[] args) { return new FrameWithoutBoxing(descriptor, args); } + public static FrameWithoutBoxing createMaterializedFrame(FrameDescriptor descriptor, Object[] args) { + return new FrameWithoutBoxing(descriptor, args); + } + @Override public void reportLoopCount(int count) { compilationProfile.reportLoopCount(count); diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle.nodes.frame; + +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +public class ForceMaterializeNode extends FixedWithNextNode implements LIRGenLowerable { + + @Input private ValueNode object; + + public ForceMaterializeNode(ValueNode object) { + super(StampFactory.forVoid()); + this.object = object; + } + + public void generate(NodeLIRBuilder generator) { + // nothing to do + } + + @NodeIntrinsic + public native static void force(Object object); +} diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java Fri Apr 11 11:53:11 2014 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.truffle.*; import com.oracle.graal.truffle.nodes.*; +import com.oracle.graal.truffle.nodes.frame.*; import com.oracle.graal.truffle.nodes.typesystem.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; @@ -165,4 +166,10 @@ public static Object unsafeGetFinalObject(Object receiver, long offset, boolean condition, Object locationIdentity) { return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Object); } + + @MethodSubstitution + public static void materialize(Object obj) { + ForceMaterializeNode.force(obj); + } + } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java Fri Apr 11 11:53:11 2014 +0200 @@ -176,7 +176,7 @@ int execute(VirtualFrame frame) { int arg = (Integer) frame.getArguments()[0]; if (arg > 0) { - return (int) callNode.call(new Object[]{(arg - 1)}); + return (int) callNode.call(frame, new Object[]{(arg - 1)}); } else { return valueNode.execute(frame); } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java Fri Apr 11 11:53:11 2014 +0200 @@ -42,4 +42,6 @@ public final Object call() { return call(NO_ARGUMENTS); } + + public abstract void setNeedsMaterializedFrame(); } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Fri Apr 11 11:53:11 2014 +0200 @@ -619,4 +619,13 @@ @Target({ElementType.TYPE}) public @interface ValueType { } + + /** + * Ensures that the given object is not virtual, i.e., not removed by Escape Analysis at the + * point of this call. + * + * @param obj the object to exclude from Escape Analysis + */ + public static void materialize(Object obj) { + } } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/RootCallTarget.java Fri Apr 11 11:53:11 2014 +0200 @@ -24,6 +24,7 @@ */ package com.oracle.truffle.api; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; /** @@ -48,4 +49,13 @@ public final RootNode getRootNode() { return rootNode; } + + protected final Object callProxy(VirtualFrame frame) { + try { + return getRootNode().execute(frame); + } finally { + // this assertion is needed to keep the values from being cleared as non-live locals + assert frame != null && this != null; + } + } } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Fri Apr 11 11:53:11 2014 +0200 @@ -25,6 +25,7 @@ package com.oracle.truffle.api; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; /** @@ -90,4 +91,20 @@ * @return the newly created materialized frame object */ MaterializedFrame createMaterializedFrame(Object[] arguments, FrameDescriptor frameDescriptor); + + /** + * Accesses the current stack, i.e., the contents of the {@link Frame}s and the associated + * {@link CallTarget}s. For this functionality to work each call needs to go through + * {@link DefaultCallNode#callProxy(MaterializedFrameNotify, CallTarget, VirtualFrame, Object[])} + * instead of calling {@link CallTarget#call(Object[])} directly. + * + * @return a lazy collection of {@link FrameInstance}. + */ + Iterable getStackTrace(); + + /** + * Accesses the current frame, i.e., the frame of the closest {@link CallTarget}. It is + * important to note that this {@link FrameInstance} supports only slow path access. + */ + FrameInstance getCurrentFrame(); } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.frame; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; + +public interface FrameInstance { + + public static enum FrameAccess { + NONE, + READ_ONLY, + READ_WRITE, + MATERIALIZE + } + + Frame getFrame(FrameAccess access, boolean slowPath); + + boolean isVirtualFrame(); + + CallNode getCallNode(); + + CallTarget getCallTarget(); +} diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Fri Apr 11 11:53:11 2014 +0200 @@ -25,17 +25,44 @@ package com.oracle.truffle.api.impl; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.frame.FrameInstance.*; import com.oracle.truffle.api.nodes.*; -public class DefaultCallNode extends CallNode { +public class DefaultCallNode extends CallNode implements MaterializedFrameNotify { + + @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE; public DefaultCallNode(CallTarget target) { super(target); } @Override - public Object call(Object[] arguments) { - return getCurrentCallTarget().call(arguments); + public Object call(VirtualFrame frame, Object[] arguments) { + return callProxy(this, getCurrentCallTarget(), frame, arguments); + } + + public static Object callProxy(MaterializedFrameNotify notify, CallTarget callTarget, VirtualFrame frame, Object[] arguments) { + try { + if (notify.getOutsideFrameAccess() != FrameAccess.NONE) { + CompilerDirectives.materialize(frame); + } + return callTarget.call(arguments); + } finally { + // this assertion is needed to keep the values from being cleared as non-live locals + assert notify != null & callTarget != null & frame != null; + } + } + + @Override + public FrameAccess getOutsideFrameAccess() { + return outsideFrameAccess; + } + + @Override + public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) { + this.outsideFrameAccess = outsideFrameAccess; } @Override diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java Fri Apr 11 11:53:11 2014 +0200 @@ -25,6 +25,7 @@ package com.oracle.truffle.api.impl; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -34,6 +35,8 @@ */ public class DefaultCallTarget extends RootCallTarget { + @CompilationFinal protected boolean needsMaterializedFrame = true; + protected DefaultCallTarget(RootNode function) { super(function); } @@ -41,6 +44,11 @@ @Override public Object call(Object[] args) { VirtualFrame frame = new DefaultVirtualFrame(getRootNode().getFrameDescriptor(), args); - return getRootNode().execute(frame); + return callProxy(frame); + } + + @Override + public void setNeedsMaterializedFrame() { + needsMaterializedFrame = true; } } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Fri Apr 11 11:53:11 2014 +0200 @@ -81,4 +81,14 @@ public Assumption createAssumption(String name) { return new DefaultAssumption(name); } + + public Iterable getStackTrace() { + // TODO(lstadler) implement this using ThreadLocal + return null; + } + + public FrameInstance getCurrentFrame() { + // TODO(lstadler) implement this using ThreadLocal + return null; + } } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/MaterializedFrameNotify.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/MaterializedFrameNotify.java Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.impl; + +import com.oracle.truffle.api.frame.FrameInstance.*; + +public interface MaterializedFrameNotify { + + FrameAccess getOutsideFrameAccess(); + + void setOutsideFrameAccess(FrameAccess outsideFrameAccess); +} diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Fri Apr 11 11:53:11 2014 +0200 @@ -25,11 +25,14 @@ package com.oracle.truffle.api.nodes; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.frame.*; /** - * Represents a call to a {@link CallTarget} in the Truffle AST. Addtionally to calling the - * {@link CallTarget} this {@link Node} enables the runtime system to implement further - * optimizations. Optimizations that can possibly applied to a {@link CallNode} are inlining and + * Represents a call to a {@link CallTarget} in the Truffle AST. In addition to calling the + * {@link CallTarget}, this {@link Node} enables the runtime system to implement further + * optimizations. Optimizations that can possibly be applied to a {@link CallNode} are inlining and * splitting. Inlining inlines this call site into the call graph of the parent {@link CallTarget}. * Splitting duplicates the {@link CallTarget} using {@link RootNode#split()} to collect call site * sensitive profiling information. @@ -54,7 +57,7 @@ * @param arguments the arguments that should be passed to the callee * @return the return result of the call */ - public abstract Object call(Object[] arguments); + public abstract Object call(VirtualFrame frame, Object[] arguments); /** * Returns the originally supplied {@link CallTarget} when this call node was created. Please @@ -115,14 +118,14 @@ } /** - * Returns the splitted {@link CallTarget} if this method is split. + * Returns the split {@link CallTarget} if this method is split. * * @return the split {@link CallTarget} */ public abstract CallTarget getSplitCallTarget(); /** - * Returns the used call target when {@link #call(Object[])} is invoked. If the + * Returns the used call target when {@link #call(VirtualFrame, Object[])} is invoked. If the * {@link CallTarget} was split this method returns the {@link CallTarget} returned by * {@link #getSplitCallTarget()}. * @@ -152,5 +155,4 @@ } return null; } - } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.sl.test/tests/HelloEqualsWorld.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/HelloEqualsWorld.output Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,90 @@ +Initial stack trace: +Frame: root doIt, a=0, hello=null +Frame: root main, i=0 +After 123 assignment: +Frame: root doIt, a=0, hello=123 +Frame: root main, i=0 +After hello assignment: +Frame: root doIt, a=0, hello=world +Frame: root main, i=0 +Initial stack trace: +Frame: root doIt, a=1, hello=null +Frame: root main, i=1 +After 123 assignment: +Frame: root doIt, a=1, hello=123 +Frame: root main, i=1 +After hello assignment: +Frame: root doIt, a=1, hello=world +Frame: root main, i=1 +Initial stack trace: +Frame: root doIt, a=2, hello=null +Frame: root main, i=2 +After 123 assignment: +Frame: root doIt, a=2, hello=123 +Frame: root main, i=2 +After hello assignment: +Frame: root doIt, a=2, hello=world +Frame: root main, i=2 +Initial stack trace: +Frame: root doIt, a=3, hello=null +Frame: root main, i=3 +After 123 assignment: +Frame: root doIt, a=3, hello=123 +Frame: root main, i=3 +After hello assignment: +Frame: root doIt, a=3, hello=world +Frame: root main, i=3 +Initial stack trace: +Frame: root doIt, a=4, hello=null +Frame: root main, i=4 +After 123 assignment: +Frame: root doIt, a=4, hello=123 +Frame: root main, i=4 +After hello assignment: +Frame: root doIt, a=4, hello=world +Frame: root main, i=4 +Initial stack trace: +Frame: root doIt, a=5, hello=null +Frame: root main, i=5 +After 123 assignment: +Frame: root doIt, a=5, hello=123 +Frame: root main, i=5 +After hello assignment: +Frame: root doIt, a=5, hello=world +Frame: root main, i=5 +Initial stack trace: +Frame: root doIt, a=6, hello=null +Frame: root main, i=6 +After 123 assignment: +Frame: root doIt, a=6, hello=123 +Frame: root main, i=6 +After hello assignment: +Frame: root doIt, a=6, hello=world +Frame: root main, i=6 +Initial stack trace: +Frame: root doIt, a=7, hello=null +Frame: root main, i=7 +After 123 assignment: +Frame: root doIt, a=7, hello=123 +Frame: root main, i=7 +After hello assignment: +Frame: root doIt, a=7, hello=world +Frame: root main, i=7 +Initial stack trace: +Frame: root doIt, a=8, hello=null +Frame: root main, i=8 +After 123 assignment: +Frame: root doIt, a=8, hello=123 +Frame: root main, i=8 +After hello assignment: +Frame: root doIt, a=8, hello=world +Frame: root main, i=8 +Initial stack trace: +Frame: root doIt, a=9, hello=null +Frame: root main, i=9 +After 123 assignment: +Frame: root doIt, a=9, hello=123 +Frame: root main, i=9 +After hello assignment: +Frame: root doIt, a=9, hello=world +Frame: root main, i=9 \ No newline at end of file diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.sl.test/tests/HelloEqualsWorld.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/HelloEqualsWorld.sl Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,22 @@ +function doIt(a) { + println("Initial stack trace:"); + println(stacktrace()); + + hello = 123; + println("After 123 assignment:"); + println(stacktrace()); + + helloEqualsWorld(); + println("After hello assignment:"); + println(stacktrace()); + +// readln(); +} + +function main() { + i = 0; + while (i < 10) { + doIt(i); + i = i + 1; + } +} diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLHelloEqualsWorldBuiltin.java Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.builtins; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.nodes.*; + +/** + * This builtin sets the variable named "hello" in the caller frame to the string "world". + */ +@NodeInfo(shortName = "helloEqualsWorld") +public abstract class SLHelloEqualsWorldBuiltin extends SLBuiltinNode { + + @Specialization + public Object change() { + FrameInstance frameInstance = Truffle.getRuntime().getStackTrace().iterator().next(); + Frame frame = frameInstance.getFrame(FrameAccess.READ_WRITE, false); + FrameSlot slot = frame.getFrameDescriptor().findOrAddFrameSlot("hello"); + frame.setObject(slot, "world"); + return null; + } +} diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Fri Apr 11 11:53:11 2014 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.builtins; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.nodes.*; + +/** + * Returns a string representation of the current stack. This includes the {@link CallTarget}s and + * the contents of the {@link Frame}. Note that this is implemented as a slow path by passing + * {@code true} to {@link FrameInstance#getFrame(FrameAccess, boolean)}. + */ +@NodeInfo(shortName = "stacktrace") +public abstract class SLStackTraceBuiltin extends SLBuiltinNode { + + @Specialization + public String trace() { + return createStackTrace(); + } + + @SlowPath + private static String createStackTrace() { + StringBuilder str = new StringBuilder(); + for (FrameInstance frame : Truffle.getRuntime().getStackTrace()) { + dumpFrame(str, frame.getCallNode().getRootNode(), frame.getFrame(FrameAccess.READ_ONLY, true), frame.isVirtualFrame()); + } + return str.toString(); + } + + private static void dumpFrame(StringBuilder str, RootNode rootNode, Frame frame, boolean isVirtual) { + if (str.length() > 0) { + str.append("\n"); + } + str.append("Frame: ").append(rootNode).append(isVirtual ? " (virtual)" : ""); + FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); + for (FrameSlot s : frameDescriptor.getSlots()) { + str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s)); + } + } +} diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Fri Apr 11 11:53:11 2014 +0200 @@ -92,7 +92,7 @@ * Now we are really ready to perform the call. We use a Truffle CallNode for that, * because it does all the work for method inlining. */ - return callCachedTargetNode.call(arguments); + return callCachedTargetNode.call(frame, arguments); } catch (InvalidAssumptionException ex) { /* diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java Fri Apr 11 11:53:11 2014 +0200 @@ -22,14 +22,19 @@ */ package com.oracle.truffle.sl.nodes.call; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.impl.*; import com.oracle.truffle.sl.runtime.*; /** * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such * calls are not optimized any further, e.g., no method inlining is performed. */ -final class SLGenericDispatchNode extends SLAbstractDispatchNode { +final class SLGenericDispatchNode extends SLAbstractDispatchNode implements MaterializedFrameNotify { + + @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE; @Override protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) { @@ -37,6 +42,14 @@ * SL has a quite simple call lookup: just ask the function for the current call target, and * call it. */ - return function.getCallTarget().call(arguments); + return DefaultCallNode.callProxy(this, function.getCallTarget(), frame, arguments); + } + + public FrameAccess getOutsideFrameAccess() { + return outsideFrameAccess; + } + + public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) { + this.outsideFrameAccess = outsideFrameAccess; } } diff -r 36e1a11a72b3 -r f675818d9ad0 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Fri Apr 11 11:52:19 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Fri Apr 11 11:53:11 2014 +0200 @@ -97,6 +97,8 @@ installBuiltin(SLPrintlnBuiltinFactory.getInstance()); installBuiltin(SLNanoTimeBuiltinFactory.getInstance()); installBuiltin(SLDefineFunctionBuiltinFactory.getInstance()); + installBuiltin(SLStackTraceBuiltinFactory.getInstance()); + installBuiltin(SLHelloEqualsWorldBuiltinFactory.getInstance()); } private void installBuiltin(NodeFactory factory) {