Skip to content

Commit

Permalink
[Truffle] Added support for $@ global variable.
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvdrum committed Mar 12, 2015
1 parent b84a3fd commit 2ef7d6e
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/

package org.jruby.truffle.nodes.globals;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class ReadLastBacktraceNode extends RubyNode {

@Child private CallDispatchHeadNode getBacktraceNode;

public ReadLastBacktraceNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Override
public Object execute(VirtualFrame frame) {
// TODO (nirvdrum 12-Mar-15) $! should be thread-local.
final RubyBasicObject globals = getContext().getCoreLibrary().getGlobalVariablesObject();
final Object lastException = globals.getOperations().getInstanceVariable(globals, "$!");

if (lastException == getContext().getCoreLibrary().getNilObject()) {
return getContext().getCoreLibrary().getNilObject();
}

if (getBacktraceNode == null) {
CompilerDirectives.transferToInterpreter();
getBacktraceNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

return getBacktraceNode.call(frame, lastException, "backtrace", null);
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/

package org.jruby.truffle.nodes.globals;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class UpdateLastBacktraceNode extends RubyNode {

@Child private RubyNode child;
@Child private CallDispatchHeadNode setBacktraceNode;

public UpdateLastBacktraceNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
super(context, sourceSection);
this.child = child;
}

@Override
public Object execute(VirtualFrame frame) {
// TODO (nirvdrum 12-Mar-15) $! should be thread-local.
final RubyBasicObject globals = getContext().getCoreLibrary().getGlobalVariablesObject();
final Object lastException = globals.getOperations().getInstanceVariable(globals, "$!");

if (lastException == getContext().getCoreLibrary().getNilObject()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("$! is not set", this));
}

if (setBacktraceNode == null) {
CompilerDirectives.transferToInterpreter();
setBacktraceNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

final Object newBacktrace = child.execute(frame);
setBacktraceNode.call(frame, lastException, "set_backtrace", null, newBacktrace);

return newBacktrace;
}
}
Expand Up @@ -1351,6 +1351,10 @@ public RubyNode translateGlobalAsgnNode(org.jruby.ast.GlobalAsgnNode node, RubyN
rhs = new CheckStdoutVariableTypeNode(context, sourceSection, rhs);
} else if (name.equals("$VERBOSE")) {
rhs = new UpdateVerbosityNode(context, sourceSection, rhs);
} else if (name.equals("$@")) {
// $@ is a special-case and doesn't write directly to an ivar field in the globals object.
// Instead, it writes to the backtrace field of the thread-local $! value.
return new UpdateLastBacktraceNode(context, sourceSection, rhs);
}

if (readOnlyGlobalVariables.contains(name)) {
Expand Down Expand Up @@ -1417,6 +1421,10 @@ public RubyNode visitGlobalVarNode(org.jruby.ast.GlobalVarNode node) {
} else if (THREAD_LOCAL_GLOBAL_VARIABLES.contains(name)) {
final ThreadLocalObjectNode threadLocalVariablesObjectNode = new ThreadLocalObjectNode(context, sourceSection);
return new ReadInstanceVariableNode(context, sourceSection, name, threadLocalVariablesObjectNode, true);
} else if (name.equals("$@")) {
// $@ is a special-case and doesn't read directly from an ivar field in the globals object.
// Instead, it reads the backtrace field of the thread-local $! value.
return new ReadLastBacktraceNode(context, sourceSection);
} else {
final ObjectLiteralNode globalVariablesObjectNode = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject());
return new ReadInstanceVariableNode(context, sourceSection, name, globalVariablesObjectNode, true);
Expand Down

0 comments on commit 2ef7d6e

Please sign in to comment.