예제 #1
0
 @Override
 public Object execute(
     TranslatorDriver.ParserContext parserContext,
     Object self,
     MaterializedFrame parentFrame,
     org.jruby.ast.RootNode rootNode) {
   try {
     final RubyParserResult parseResult =
         truffleContext
             .getTranslator()
             .parse(
                 truffleContext,
                 truffleContext.getSourceManager().get(rootNode.getPosition().getFile()),
                 parserContext,
                 parentFrame,
                 rootNode);
     final CallTarget callTarget =
         Truffle.getRuntime().createCallTarget(parseResult.getRootNode());
     return callTarget.call(RubyArguments.pack(parentFrame, self, null));
   } catch (ThrowException e) {
     throw new RaiseException(truffleContext.getCoreLibrary().nameErrorUncaughtThrow(e.getTag()));
   } catch (RaiseException | BreakShellException | QuitException e) {
     throw e;
   } catch (Throwable e) {
     e.printStackTrace();
     throw new RaiseException(ExceptionTranslator.translateException(truffleContext, e));
   }
 }
예제 #2
0
  @CompilerDirectives.TruffleBoundary
  public void addMethod(Node currentNode, InternalMethod method) {
    assert method != null;

    if (getContext().getCoreLibrary().isLoadingRubyCore()) {
      final InternalMethod currentMethod = methods.get(method.getName());

      if (currentMethod != null
          && currentMethod.getSharedMethodInfo().getSourceSection() instanceof CoreSourceSection) {
        return;
      }
    }

    checkFrozen(currentNode);
    methods.put(method.getName(), method.withDeclaringModule(rubyModuleObject));
    newVersion();

    if (context.getCoreLibrary().isLoaded() && !method.isUndefined()) {
      context.send(
          rubyModuleObject,
          "method_added",
          null,
          context.getSymbolTable().getSymbol(method.getName()));
    }
  }
예제 #3
0
 public TraceInstrument(RubyContext context, SourceSection sourceSection) {
   this.context = context;
   traceAssumption = context.getTraceManager().getTraceAssumption();
   traceFunc = null;
   callNode = null;
   event = context.makeString("line");
   file = context.makeString(sourceSection.getSource().getName());
   line = sourceSection.getStartLine();
 }
예제 #4
0
    @CompilerDirectives.SlowPath
    private RubyString formatSlow(RubyString format, Object[] args) {
      final RubyContext context = getContext();

      if (args.length == 1 && args[0] instanceof RubyArray) {
        singleArrayProfile.enter();
        return context.makeString(
            StringFormatter.format(format.toString(), ((RubyArray) args[0]).asList()));
      } else {
        multipleArgumentsProfile.enter();
        return context.makeString(StringFormatter.format(format.toString(), Arrays.asList(args)));
      }
    }
  public CachedBoxedSymbolDispatchNode(
      RubyContext context,
      Object cachedName,
      DispatchNode next,
      Object value,
      InternalMethod method,
      boolean indirect,
      DispatchAction dispatchAction) {
    super(context, cachedName, next, indirect, dispatchAction);

    unmodifiedAssumption = context.getCoreLibrary().getSymbolClass().getUnmodifiedAssumption();
    this.value = value;
    this.method = method;

    if (method != null) {
      if (indirect) {
        indirectCallNode = Truffle.getRuntime().createIndirectCallNode();
      } else {
        callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());

        if (callNode.isCallTargetCloningAllowed()
            && method.getSharedMethodInfo().shouldAlwaysSplit()) {
          insert(callNode);
          callNode.cloneCallTarget();
        }
      }
    }
  }
예제 #6
0
  @TruffleBoundary
  private SafepointAction step(Node currentNode, boolean isDrivingThread) {
    final DynamicObject thread = context.getThreadManager().getCurrentThread();

    // wait other threads to reach their safepoint
    phaser.arriveAndAwaitAdvance();

    if (isDrivingThread) {
      assumption = Truffle.getRuntime().createAssumption("SafepointManager");
    }

    // wait the assumption to be renewed
    phaser.arriveAndAwaitAdvance();

    // Read these while in the safepoint.
    SafepointAction deferredAction = deferred ? action : null;

    try {
      if (!deferred && thread != null && Layouts.THREAD.getStatus(thread) != Status.ABORTING) {
        action.run(thread, currentNode);
      }
    } finally {
      // wait other threads to finish their action
      phaser.arriveAndAwaitAdvance();
    }

    return deferredAction;
  }
예제 #7
0
 @Override
 public TruffleMethod truffelize(DynamicMethod originalMethod, ArgsNode argsNode, Node bodyNode) {
   final MethodDefinitionNode methodDefinitionNode =
       truffleContext.getTranslator().parse(truffleContext, null, argsNode, bodyNode);
   return new TruffleMethod(
       originalMethod,
       Truffle.getRuntime().createCallTarget(methodDefinitionNode.getMethodRootNode()));
 }
예제 #8
0
파일: TryNode.java 프로젝트: jwinter/jruby
  private Object handleException(VirtualFrame frame, RuntimeException exception) {
    CompilerAsserts.neverPartOfCompilation();

    final RubyContext context = getContext();

    final RubyBasicObject rubyException =
        ExceptionTranslator.translateException(context, exception);

    context.getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", rubyException);

    for (RescueNode rescue : rescueParts) {
      if (rescue.canHandle(frame, rubyException)) {
        return rescue.execute(frame);
      }
    }

    throw exception;
  }
예제 #9
0
  public static String expandPath(RubyContext context, String fileName) {
    // TODO (nirvdrum 11-Feb-15) This needs to work on Windows without calling into non-Truffle
    // JRuby.
    if (context.isRunningOnWindows()) {
      final org.jruby.RubyString path =
          context.toJRubyString(
              StringNodes.createString(context.getCoreLibrary().getStringClass(), fileName));
      final org.jruby.RubyString expanded =
          (org.jruby.RubyString)
              org.jruby.RubyFile.expand_path19(
                  context.getRuntime().getCurrentContext(),
                  null,
                  new org.jruby.runtime.builtin.IRubyObject[] {path});

      return expanded.asJavaString();
    } else {
      return expandPath(fileName, null);
    }
  }
예제 #10
0
파일: TryNode.java 프로젝트: godfat/jruby
 public TryNode(
     RubyContext context,
     SourceSection sourceSection,
     ExceptionTranslatingNode tryPart,
     RescueNode[] rescueParts,
     RubyNode elsePart) {
   super(context, sourceSection);
   this.tryPart = tryPart;
   this.rescueParts = rescueParts;
   this.elsePart = elsePart;
   clearExceptionVariableNode =
       new WriteInstanceVariableNode(
           context,
           sourceSection,
           "$!",
           new ObjectLiteralNode(
               context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject()),
           new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject()),
           true);
 }
  public CachedBoxedSymbolDispatchNode(
      RubyContext context, Object cachedName, DispatchNode next, Object value, RubyMethod method) {
    super(context, cachedName, next);
    unmodifiedAssumption = context.getCoreLibrary().getSymbolClass().getUnmodifiedAssumption();
    this.value = value;
    this.method = method;

    if (method != null) {
      callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
    }
  }
예제 #12
0
  public synchronized void attach(String file, int line, final DynamicObject block) {
    assert RubyGuards.isRubyProc(block);

    final Instrument instrument =
        Instrument.create(
            new StandardInstrumentListener() {

              @Override
              public void enter(Probe probe, Node node, VirtualFrame frame) {
                final DynamicObject binding =
                    BindingNodes.createRubyBinding(
                        context.getCoreLibrary().getBindingClass(),
                        RubyArguments.getSelf(frame.getArguments()),
                        frame.materialize());
                ProcNodes.rootCall(block, binding);
              }

              @Override
              public void returnVoid(Probe probe, Node node, VirtualFrame virtualFrame) {}

              @Override
              public void returnValue(
                  Probe probe, Node node, VirtualFrame virtualFrame, Object o) {}

              @Override
              public void returnExceptional(
                  Probe probe, Node node, VirtualFrame virtualFrame, Exception e) {}
            },
            String.format("Truffle::Primitive.attach@%s:%d", file, line));

    final Source source = context.getSourceManager().forFileBestFuzzily(file);

    final LineLocation lineLocation = source.createLineLocation(line);

    List<Instrument> instruments = attachments.get(lineLocation);

    if (instruments == null) {
      instruments = new ArrayList<>();
      attachments.put(lineLocation, instruments);
    }

    instruments.add(instrument);

    for (Probe probe : lineToProbesMap.findProbes(lineLocation)) {
      if (probe.isTaggedAs(StandardSyntaxTag.STATEMENT)) {
        probe.attach(instrument);
        return;
      }
    }

    throw new RuntimeException("couldn't find a statement!");
  }
예제 #13
0
  public static RubyNode sequence(
      RubyContext context, SourceSection sourceSection, List<RubyNode> sequence) {
    final List<RubyNode> flattened = flatten(sequence, true);

    if (flattened.isEmpty()) {
      return new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject());
    } else if (flattened.size() == 1) {
      return flattened.get(0);
    } else {
      return new SequenceNode(
          context, sourceSection, flattened.toArray(new RubyNode[flattened.size()]));
    }
  }
예제 #14
0
  public synchronized void detach(String file, int line) {
    final Source source = context.getSourceManager().forFileBestFuzzily(file);

    final LineLocation lineLocation = source.createLineLocation(line);

    final List<Instrument> instruments = attachments.remove(lineLocation);

    if (instruments != null) {
      for (Instrument instrument : instruments) {
        instrument.dispose();
      }
    }
  }
예제 #15
0
  @CompilerDirectives.TruffleBoundary
  public Object removeClassVariable(Node currentNode, String name) {
    checkFrozen(currentNode);

    final Object found = classVariables.remove(name);
    if (found == null) {
      CompilerDirectives.transferToInterpreter();
      throw new RaiseException(
          context
              .getCoreLibrary()
              .nameErrorClassVariableNotDefined(name, rubyModuleObject, currentNode));
    }
    return found;
  }
예제 #16
0
  @CompilerDirectives.TruffleBoundary
  public void changeConstantVisibility(Node currentNode, String name, boolean isPrivate) {
    checkFrozen(currentNode);
    RubyConstant rubyConstant = constants.get(name);

    if (rubyConstant != null) {
      rubyConstant.setPrivate(isPrivate);
      newLexicalVersion();
    } else {
      throw new RaiseException(
          context
              .getCoreLibrary()
              .nameErrorUninitializedConstant(rubyModuleObject, name, currentNode));
    }
  }
예제 #17
0
  @Override
  public void init() {
    if (RubyContext.PRINT_RUNTIME) {
      runtime
          .getInstanceConfig()
          .getError()
          .println("jruby: using " + Truffle.getRuntime().getName());
    }

    // Bring in core method nodes

    CoreMethodNodeManager.addStandardMethods(truffleContext.getCoreLibrary().getObjectClass());

    // Give the core library manager a chance to tweak some of those methods

    truffleContext.getCoreLibrary().initializeAfterMethodsAdded();

    // Set program arguments

    for (IRubyObject arg :
        ((org.jruby.RubyArray) runtime.getObject().getConstant("ARGV")).toJavaArray()) {
      assert arg != null;

      truffleContext.getCoreLibrary().getArgv().slowPush(truffleContext.makeString(arg.toString()));
    }

    // Set the load path

    final RubyArray loadPath =
        (RubyArray)
            truffleContext.getCoreLibrary().getGlobalVariablesObject().getInstanceVariable("$:");

    for (IRubyObject path :
        ((org.jruby.RubyArray) runtime.getLoadService().getLoadPath()).toJavaArray()) {
      loadPath.slowPush(truffleContext.makeString(path.toString()));
    }

    // Hook

    if (truffleContext.getHooks() != null) {
      truffleContext.getHooks().afterInit(truffleContext);
    }
  }
예제 #18
0
  public boolean require(String feature, Node currentNode) throws IOException {
    final RubyConstant dataConstantBefore =
        ModuleOperations.lookupConstant(
            context, LexicalScope.NONE, context.getCoreLibrary().getObjectClass(), "DATA");

    if (feature.startsWith("./")) {
      final String cwd = context.getRuntime().getCurrentDirectory();
      feature = cwd + "/" + feature.substring(2);
    } else if (feature.startsWith("../")) {
      final String cwd = context.getRuntime().getCurrentDirectory();
      feature = cwd.substring(0, cwd.lastIndexOf('/')) + "/" + feature.substring(3);
    }

    try {
      if (isAbsolutePath(feature)) {
        // Try as a full path

        if (requireInPath(null, feature, currentNode)) {
          return true;
        }
      } else {
        // Try each load path in turn

        for (Object pathObject : ArrayNodes.slowToArray(context.getCoreLibrary().getLoadPath())) {
          String loadPath = pathObject.toString();
          if (!isAbsolutePath(loadPath)) {
            loadPath = expandPath(context, loadPath);
          }

          if (requireInPath(loadPath, feature, currentNode)) {
            return true;
          }
        }
      }

      throw new RaiseException(context.getCoreLibrary().loadErrorCannotLoad(feature, currentNode));
    } finally {
      if (dataConstantBefore == null) {
        context.getCoreLibrary().getObjectClass().removeConstant(currentNode, "DATA");
      } else {
        context
            .getCoreLibrary()
            .getObjectClass()
            .setConstant(currentNode, "DATA", dataConstantBefore.getValue());
      }
    }
  }
예제 #19
0
  /** Also searches on Object for modules. Used for alias_method, visibility changes, etc. */
  @CompilerDirectives.TruffleBoundary
  public InternalMethod deepMethodSearch(String name) {
    InternalMethod method = ModuleOperations.lookupMethod(rubyModuleObject, name);
    if (method != null && !method.isUndefined()) {
      return method;
    }

    // Also search on Object if we are a Module. JRuby calls it deepMethodSearch().
    if (RubyGuards.isRubyModule(rubyModuleObject)
        && !RubyGuards.isRubyClass(rubyModuleObject)) { // TODO: handle undefined methods
      method = ModuleOperations.lookupMethod(context.getCoreLibrary().getObjectClass(), name);

      if (method != null && !method.isUndefined()) {
        return method;
      }
    }

    return null;
  }
예제 #20
0
  @TruffleBoundary
  private void assumptionInvalidated(Node currentNode, boolean fromBlockingCall) {
    final DynamicObject thread = context.getThreadManager().getCurrentThread();
    final InterruptMode interruptMode = Layouts.THREAD.getInterruptMode(thread);

    final boolean interruptible =
        (interruptMode == InterruptMode.IMMEDIATE)
            || (fromBlockingCall && interruptMode == InterruptMode.ON_BLOCKING);

    if (!interruptible) {
      Thread.currentThread().interrupt(); // keep the interrupt flag
      return; // interrupt me later
    }

    SafepointAction deferredAction = step(currentNode, false);

    // We're now running again normally and can run deferred actions
    if (deferredAction != null) {
      deferredAction.run(thread, currentNode);
    }
  }
예제 #21
0
 @TruffleBoundary
 public void pauseThreadAndExecuteLater(
     final Thread thread, Node currentNode, final SafepointAction action) {
   if (Thread.currentThread() == thread) {
     // fast path if we are already the right thread
     DynamicObject rubyThread = context.getThreadManager().getCurrentThread();
     action.run(rubyThread, currentNode);
   } else {
     pauseAllThreadsAndExecute(
         currentNode,
         true,
         new SafepointAction() {
           @Override
           public void run(DynamicObject rubyThread, Node currentNode) {
             if (Thread.currentThread() == thread) {
               action.run(rubyThread, currentNode);
             }
           }
         });
   }
 }
예제 #22
0
  @Override
  public void enter(Node node, VirtualFrame frame) {
    try {
      traceAssumption.check();
    } catch (InvalidAssumptionException e) {

      traceAssumption = context.getTraceManager().getTraceAssumption();
      traceFunc = context.getTraceManager().getTraceFunc();

      if (traceFunc != null) {
        callNode = insert(Truffle.getRuntime().createDirectCallNode(traceFunc.getCallTarget()));
      } else {
        callNode = null;
      }
    }

    if (traceFunc != null) {
      if (!context.getTraceManager().isInTraceFunc()) {
        context.getTraceManager().setInTraceFunc(true);

        final Object[] args =
            new Object[] {
              event,
              file,
              line,
              NilPlaceholder.INSTANCE,
              new RubyBinding(
                  context.getCoreLibrary().getBindingClass(),
                  RubyArguments.getSelf(frame.getArguments()),
                  frame.materialize()),
              NilPlaceholder.INSTANCE
            };

        try {
          callNode.call(
              frame,
              RubyArguments.pack(
                  traceFunc,
                  traceFunc.getDeclarationFrame(),
                  traceFunc.getSelfCapturedInScope(),
                  traceFunc.getBlockCapturedInScope(),
                  args));
        } finally {
          context.getTraceManager().setInTraceFunc(false);
        }
      }
    }
  }
  @Override
  public void handle(Signal signal) {
    // TODO: just make this a normal Ruby thread once we don't have the global lock anymore
    context
        .getSafepointManager()
        .pauseAllThreadsAndExecuteFromNonRubyThread(
            new Consumer<RubyThread>() {

              @Override
              public void accept(RubyThread thread) {
                if (thread == context.getThreadManager().getRootThread()) {
                  context.getThreadManager().enterGlobalLock(thread);
                  try {
                    // assumes this proc does not re-enter the SafepointManager.
                    proc.rootCall();
                  } finally {
                    context.getThreadManager().leaveGlobalLock();
                  }
                }
              }
            });
  }
예제 #24
0
  @TruffleBoundary
  public void pauseAllThreadsAndExecute(
      Node currentNode, boolean deferred, SafepointAction action) {
    if (lock.isHeldByCurrentThread()) {
      throw new IllegalStateException("Re-entered SafepointManager");
    }

    // Need to lock interruptibly since we are in the registered threads.
    while (!lock.tryLock()) {
      poll(currentNode);
    }

    try {
      pauseAllThreadsAndExecute(currentNode, true, action, deferred);
    } finally {
      lock.unlock();
    }

    // Run deferred actions after leaving the SafepointManager lock.
    if (deferred) {
      action.run(context.getThreadManager().getCurrentThread(), currentNode);
    }
  }
예제 #25
0
  private boolean requireFile(String feature, String path, Node currentNode) throws IOException {
    // We expect '/' in various classpath URLs, so normalize Windows file paths to use '/'
    path = path.replace('\\', '/');
    final RubyBasicObject loadedFeatures = context.getCoreLibrary().getLoadedFeatures();

    if (path.startsWith("uri:classloader:/")) {
      // TODO CS 13-Feb-15 this uri:classloader:/ and core:/ thing is a hack - simplify it

      for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(loadedFeatures))) {
        if (loaded.toString().equals(path)) {
          return true;
        }
      }

      String coreFileName = path.substring("uri:classloader:/".length());

      coreFileName = FileSystems.getDefault().getPath(coreFileName).normalize().toString();

      if (context
              .getRuntime()
              .getLoadService()
              .getClassPathResource(context.getRuntime().getJRubyClassLoader(), coreFileName)
          == null) {
        return false;
      }

      if (SHOW_RESOLUTION) {
        System.err.printf("resolved %s -> %s%n", feature, coreFileName);
      }

      context.getCoreLibrary().loadRubyCore(coreFileName, "uri:classloader:/");
      ArrayNodes.slowPush(
          loadedFeatures,
          StringNodes.createString(context.getCoreLibrary().getStringClass(), path));

      return true;
    } else if (path.startsWith("core:/")) {
      for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(loadedFeatures))) {
        if (loaded.toString().equals(path)) {
          return true;
        }
      }

      final String coreFileName = path.substring("core:/".length());

      if (context
              .getRuntime()
              .getLoadService()
              .getClassPathResource(context.getRuntime().getJRubyClassLoader(), coreFileName)
          == null) {
        return false;
      }

      if (SHOW_RESOLUTION) {
        System.err.printf("resolved %s -> %s%n", feature, coreFileName);
      }

      context.getCoreLibrary().loadRubyCore(coreFileName, "core:/");
      ArrayNodes.slowPush(
          loadedFeatures,
          StringNodes.createString(context.getCoreLibrary().getStringClass(), path));

      return true;
    } else {
      final File file = new File(path);

      assert file.isAbsolute();

      if (!file.isAbsolute() || !file.isFile()) {
        return false;
      }

      final String expandedPath = expandPath(context, path);

      for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(loadedFeatures))) {
        if (loaded.toString().equals(expandedPath)) {
          return true;
        }
      }

      if (SHOW_RESOLUTION) {
        System.err.printf("resolved %s -> %s%n", feature, expandedPath);
      }

      // TODO (nirvdrum 15-Jan-15): If we fail to load, we should remove the path from the loaded
      // features because subsequent requires of the same statement may succeed.
      final RubyBasicObject pathString =
          StringNodes.createString(context.getCoreLibrary().getStringClass(), expandedPath);
      ArrayNodes.slowPush(loadedFeatures, pathString);
      try {
        context.loadFile(path, currentNode);
      } catch (RaiseException e) {
        final ArrayMirror mirror =
            ArrayMirror.reflect((Object[]) ArrayNodes.getStore(loadedFeatures));
        final int length = ArrayNodes.getSize(loadedFeatures);
        for (int i = length - 1; i >= 0; i--) {
          if (mirror.get(i) == pathString) {
            for (int j = length - 1; j > i; j--) {
              mirror.set(i - 1, mirror.get(i));
            }
            ArrayNodes.setSize(loadedFeatures, length - 1);
            break;
          }
        }
        throw e;
      }
    }

    return true;
  }
예제 #26
0
 @Override
 public Object toTruffle(IRubyObject object) {
   return truffleContext.toTruffle(object);
 }
예제 #27
0
 @Override
 public void shutdown() {
   truffleContext.shutdown();
 }
예제 #28
0
 @Override
 public IRubyObject toJRuby(Object object) {
   return truffleContext.toJRuby(object);
 }
예제 #29
0
  public static boolean verifyStore(
      RubyContext context, Object store, int size, Entry firstInSequence, Entry lastInSequence) {
    assert store == null || store.getClass() == Object[].class || store instanceof Entry[];

    if (store == null) {
      assert size == 0;
      assert firstInSequence == null;
      assert lastInSequence == null;
    } else if (store instanceof Entry[]) {
      assert lastInSequence == null || lastInSequence.getNextInSequence() == null;

      final Entry[] entryStore = (Entry[]) store;

      Entry foundFirst = null;
      Entry foundLast = null;
      int foundSizeBuckets = 0;

      for (int n = 0; n < entryStore.length; n++) {
        Entry entry = entryStore[n];

        while (entry != null) {
          foundSizeBuckets++;

          if (entry == firstInSequence) {
            assert foundFirst == null;
            foundFirst = entry;
          }

          if (entry == lastInSequence) {
            assert foundLast == null;
            foundLast = entry;
          }

          entry = entry.getNextInLookup();
        }
      }

      assert foundSizeBuckets == size;
      assert firstInSequence == foundFirst;
      assert lastInSequence == foundLast;

      int foundSizeSequence = 0;
      Entry entry = firstInSequence;

      while (entry != null) {
        foundSizeSequence++;

        if (entry.getNextInSequence() == null) {
          assert entry == lastInSequence;
        } else {
          assert entry.getNextInSequence().getPreviousInSequence() == entry;
        }

        entry = entry.getNextInSequence();

        assert entry != firstInSequence;
      }

      assert foundSizeSequence == size : String.format("%d %d", foundSizeSequence, size);
    } else if (store.getClass() == Object[].class) {
      assert ((Object[]) store).length
              == context.getOptions().HASH_PACKED_ARRAY_MAX * PackedArrayStrategy.ELEMENTS_PER_ENTRY
          : ((Object[]) store).length;

      final Object[] packedStore = (Object[]) store;

      for (int n = 0; n < context.getOptions().HASH_PACKED_ARRAY_MAX; n++) {
        if (n < size) {
          assert packedStore[n * 2] != null;
          assert packedStore[n * 2 + 1] != null;
        }
      }

      assert firstInSequence == null;
      assert lastInSequence == null;
    }

    return true;
  }