Mercurial > hg > graal-compiler
view graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java @ 13569:1894412de0ed
Ruby: major upgrade in debugging support, mainly for navigation: step, next (passing over calls), return (from enclosing function), etc. Also a few bug fixes.
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Wed, 08 Jan 2014 14:03:36 -0800 |
parents | fb846424299f |
children | 497fada09efb |
line wrap: on
line source
/* * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This * code is released under a tri EPL/GPL/LGPL license. You can use it, * redistribute it and/or modify it under the terms of the: * * Eclipse Public License version 1.0 * GNU General Public License version 2 * GNU Lesser General Public License version 2.1 */ package com.oracle.truffle.ruby.runtime; import java.math.*; import java.util.concurrent.atomic.*; import jnr.posix.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.ruby.runtime.configuration.*; import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; import com.oracle.truffle.ruby.runtime.debug.*; import com.oracle.truffle.ruby.runtime.methods.*; import com.oracle.truffle.ruby.runtime.objects.*; import com.oracle.truffle.ruby.runtime.subsystems.*; /** * The global state of a running Ruby system. */ public class RubyContext implements ExecutionContext { private final Configuration configuration; private final RubyParser parser; private final CoreLibrary coreLibrary; private final FeatureManager featureManager; private final ObjectSpaceManager objectSpaceManager; private final TraceManager traceManager; private final ThreadManager threadManager; private final FiberManager fiberManager; private final AtExitManager atExitManager; private final RubyDebugManager debugManager; private final SourceManager sourceManager; private final ASTPrinter astPrinter; private AtomicLong nextObjectID = new AtomicLong(0); private String currentDirectory = System.getProperty("user.dir"); private POSIX posix = POSIXFactory.getPOSIX(); public RubyContext(RubyParser parser) { this(new Configuration(new ConfigurationBuilder()), parser, null); } public RubyContext(Configuration configuration, RubyParser parser) { this(configuration, parser, null); } public RubyContext(Configuration configuration, RubyParser parser, ASTPrinter astPrinter) { assert configuration != null; this.configuration = configuration; this.parser = parser; this.astPrinter = astPrinter; objectSpaceManager = new ObjectSpaceManager(this); traceManager = new TraceManager(this); // See note in CoreLibrary#initialize to see why we need to break this into two statements coreLibrary = new CoreLibrary(this); coreLibrary.initialize(); featureManager = new FeatureManager(this); atExitManager = new AtExitManager(); sourceManager = new SourceManager(); debugManager = configuration.getDebug() ? new RubyDebugManager(this) : null; // Must initialize threads before fibers threadManager = new ThreadManager(this); if (configuration.getRubyVersion().is19OrLater()) { fiberManager = new FiberManager(this); } else { fiberManager = null; } } public String getLanguageShortName() { return configuration.getRubyVersion().getShortName(); } public RubyDebugManager getDebugManager() { return debugManager; } public ASTPrinter getASTPrinter() { return astPrinter; } public void implementationMessage(String format, Object... arguments) { System.err.println("rubytruffle: " + String.format(format, arguments)); } public void load(Source source) { execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null); } public void loadFile(String fileName) { final Source source = sourceManager.get(fileName); final String code = source.getCode(); if (code == null) { throw new RuntimeException("Can't read file " + fileName); } execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null); } /** * Receives runtime notification that execution has halted. */ public void haltedAt(Node node, MaterializedFrame frame) { runShell(node, frame); } public Object eval(String code) { final Source source = sourceManager.get("(eval)", code); return execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null); } public Object eval(String code, RubyModule module) { final Source source = sourceManager.get("(eval)", code); return execute(this, source, RubyParser.ParserContext.MODULE, module, null); } public Object eval(String code, RubyBinding binding) { final Source source = sourceManager.get("(eval)", code); return execute(this, source, RubyParser.ParserContext.TOP_LEVEL, binding.getSelf(), binding.getFrame()); } public void runShell(Node node, MaterializedFrame frame) { MaterializedFrame existingLocals = frame; String prompt = "Ruby> "; if (node != null) { final SourceSection src = node.getSourceSection(); if (src != null) { prompt = (src.getSource().getName() + ":" + src.getStartLine() + "> "); } } while (true) { try { final String line = configuration.getInputReader().readLine(prompt); final ShellResult result = evalShell(line, existingLocals); configuration.getStandardOut().println("=> " + result.getResult()); existingLocals = result.getFrame(); } catch (BreakShellException e) { return; } catch (Exception e) { e.printStackTrace(); } } } public ShellResult evalShell(String code, MaterializedFrame existingLocals) { final Source source = sourceManager.get("(shell)", code); return (ShellResult) execute(this, source, RubyParser.ParserContext.SHELL, coreLibrary.getMainObject(), existingLocals); } public Object execute(RubyContext context, Source source, RubyParser.ParserContext parserContext, Object self, MaterializedFrame parentFrame) { if (configuration.getPrintExecutedFiles()) { implementationMessage("executing: %s", source.getName()); } try { final RubyParserResult parseResult = parser.parse(context, source, parserContext, parentFrame); final RubyArguments arguments = new RubyArguments(parentFrame, self, null); final CallTarget callTarget = Truffle.getRuntime().createCallTarget(parseResult.getRootNode(), parseResult.getFrameDescriptor()); return callTarget.call(null, arguments); } catch (RaiseException e) { throw e; } catch (ThrowException e) { if (context.getConfiguration().getRubyVersion().is18OrEarlier()) { throw new RaiseException(context.getCoreLibrary().nameErrorUncaughtThrow(e.getTag())); } else { throw new RaiseException(context.getCoreLibrary().argumentErrorUncaughtThrow(e.getTag())); } } catch (BreakShellException | QuitException e) { throw e; } catch (Throwable e) { throw new RaiseException(ExceptionTranslator.translateException(this, e)); } } public long getNextObjectID() { // TODO(CS): We can theoretically run out of long values final long id = nextObjectID.getAndIncrement(); if (id < 0) { nextObjectID.set(Long.MIN_VALUE); throw new RuntimeException("Object IDs exhausted"); } return id; } public void shutdown() { atExitManager.run(); threadManager.leaveGlobalLock(); objectSpaceManager.shutdown(); if (fiberManager != null) { fiberManager.shutdown(); } } public RubyString makeString(String string) { return new RubyString(coreLibrary.getStringClass(), string); } public RubyString makeString(char string) { return makeString(Character.toString(string)); } public Configuration getConfiguration() { return configuration; } public CoreLibrary getCoreLibrary() { return coreLibrary; } public FeatureManager getFeatureManager() { return featureManager; } public ObjectSpaceManager getObjectSpaceManager() { return objectSpaceManager; } public TraceManager getTraceManager() { return traceManager; } public FiberManager getFiberManager() { return fiberManager; } public ThreadManager getThreadManager() { return threadManager; } public RubyParser getParser() { return parser; } /** * Utility method to check if an object should be visible in a Ruby program. Used in assertions * at method boundaries to check that only values we want to be visible to the programmer become * so. */ public static boolean shouldObjectBeVisible(Object object) { // TODO(cs): RubyMethod should never be visible return object instanceof UndefinedPlaceholder || // object instanceof Boolean || // object instanceof Integer || // object instanceof BigInteger || // object instanceof Double || // object instanceof RubyBasicObject || // object instanceof RubyMethod || // object instanceof NilPlaceholder || // object instanceof RubyMethod; } public static boolean shouldObjectsBeVisible(Object... objects) { for (Object object : objects) { if (!shouldObjectBeVisible(object)) { return false; } } return true; } public void setCurrentDirectory(String currentDirectory) { this.currentDirectory = currentDirectory; } public String getCurrentDirectory() { return currentDirectory; } public POSIX getPOSIX() { return posix; } public AtExitManager getAtExitManager() { return atExitManager; } public SourceManager getSourceManager() { return sourceManager; } }