Esempio n. 1
0
    @Specialization
    public RubyString fullTree() {
      notDesignedForCompilation();

      return getContext()
          .makeString(
              NodeUtil.printTreeToString(
                  Truffle.getRuntime().getCallerFrame().getCallNode().getRootNode()));
    }
 public Stream<Node> nodeStream(boolean includeInlinedNodes) {
   Iterator<Node> iterator;
   TruffleInlining inliner = getInlining();
   if (includeInlinedNodes && inliner != null) {
     iterator = inliner.makeNodeIterator(this);
   } else {
     iterator = NodeUtil.makeRecursiveIterator(this.getRootNode());
   }
   return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
 }
Esempio n. 3
0
  /**
   * Only local reads are effectively analyzed.<br>
   * Since any local write is a statement by it self, and the recursive call to
   * escapesCurrentFrame() always return false.
   */
  private boolean escapesCurrentFrame(FrameSlot slot) {
    if (slot.getIdentifier().equals("<return_val>")) {
      return true;
    }

    for (FrameSlotNode slotNode : NodeUtil.findAllNodeInstances(root, FrameSlotNode.class)) {
      if (!slotNode.getSlot().equals(slot)) {
        continue;
      }

      boolean escapse = escapesCurrentFrame(slotNode);
      if (escapse) {
        return true;
      }
    }

    return false;
  }
 private static RootNode cloneRootNode(RootNode root) {
   if (root == null || !root.isCloningAllowed()) {
     return null;
   }
   return NodeUtil.cloneNode(root);
 }
 private YieldDispatchHeadNode getHeadNode() {
   return NodeUtil.findParent(this, YieldDispatchHeadNode.class);
 }
Esempio n. 6
0
  public BlockDefinitionNode compileBlockNode(
      SourceSection sourceSection,
      String methodName,
      org.jruby.ast.Node bodyNode,
      SharedMethodInfo sharedMethodInfo,
      Type type) {
    declareArguments(sourceSection, methodName, sharedMethodInfo);
    final Arity arity = getArity(argsNode);
    final Arity arityForCheck;

    /*
     * If you have a block with parameters |a,| Ruby checks the arity as if was minimum 1, maximum 1. That's
     * counter-intuitive - as you'd expect the anonymous rest argument to cause it to have no maximum. Indeed,
     * that's how JRuby reports it, and by the look of their failing spec they consider this to be correct. We'll
     * follow the specs for now until we see a reason to do something else.
     */

    if (argsNode.getRestArgNode() instanceof org.jruby.ast.UnnamedRestArgNode
        && !((UnnamedRestArgNode) argsNode.getRestArgNode()).isStar()) {
      arityForCheck = arity.withRest(false);
    } else {
      arityForCheck = arity;
    }

    final boolean isProc = type == Type.PROC;
    final LoadArgumentsTranslator loadArgumentsTranslator =
        new LoadArgumentsTranslator(currentNode, context, source, isProc, this);
    final RubyNode loadArguments = argsNode.accept(loadArgumentsTranslator);

    final RubyNode preludeProc;
    if (shouldConsiderDestructuringArrayArg(arity)) {
      final RubyNode readArrayNode =
          new ReadPreArgumentNode(
              context, sourceSection, 0, MissingArgumentBehaviour.RUNTIME_ERROR);
      final RubyNode castArrayNode = ArrayCastNodeGen.create(context, sourceSection, readArrayNode);

      final FrameSlot arraySlot =
          environment.declareVar(environment.allocateLocalTemp("destructure"));
      final RubyNode writeArrayNode =
          new WriteLocalVariableNode(context, sourceSection, castArrayNode, arraySlot);

      final LoadArgumentsTranslator destructureArgumentsTranslator =
          new LoadArgumentsTranslator(currentNode, context, source, isProc, this);
      destructureArgumentsTranslator.pushArraySlot(arraySlot);
      final RubyNode newDestructureArguments = argsNode.accept(destructureArgumentsTranslator);

      final RubyNode shouldDestructure =
          new ShouldDestructureNode(
              context,
              sourceSection,
              new RespondToNode(context, sourceSection, readArrayNode, "to_ary"));

      final RubyNode arrayWasNotNil =
          SequenceNode.sequence(
              context,
              sourceSection,
              writeArrayNode,
              new NotNode(
                  context,
                  sourceSection,
                  new IsNilNode(
                      context,
                      sourceSection,
                      new ReadLocalVariableNode(context, sourceSection, arraySlot))));

      final RubyNode shouldDestructureAndArrayWasNotNil =
          new AndNode(context, sourceSection, shouldDestructure, arrayWasNotNil);

      preludeProc =
          new IfNode(
              context,
              sourceSection,
              shouldDestructureAndArrayWasNotNil,
              newDestructureArguments,
              loadArguments);
    } else {
      preludeProc = loadArguments;
    }

    final RubyNode preludeLambda =
        SequenceNode.sequence(
            context,
            sourceSection,
            CheckArityNode.create(context, sourceSection, arityForCheck),
            NodeUtil.cloneNode(loadArguments));

    RubyNode body;

    parentSourceSection.push(sourceSection);
    try {
      if (argsNode.getBlockLocalVariables() != null
          && !argsNode.getBlockLocalVariables().isEmpty()) {
        for (org.jruby.ast.Node var : argsNode.getBlockLocalVariables().children()) {
          environment.declareVar(((INameNode) var).getName());
        }
      }

      body = translateNodeOrNil(sourceSection, bodyNode);
    } finally {
      parentSourceSection.pop();
    }

    // Procs
    final RubyNode bodyProc =
        new CatchForProcNode(
            context,
            SequenceNode.enclosing(sourceSection, body.getEncapsulatingSourceSection()),
            composeBody(preludeProc, NodeUtil.cloneNode(body)));

    final RubyRootNode newRootNodeForProcs =
        new RubyRootNode(
            context,
            considerExtendingMethodToCoverEnd(bodyProc.getEncapsulatingSourceSection()),
            environment.getFrameDescriptor(),
            environment.getSharedMethodInfo(),
            bodyProc,
            environment.needsDeclarationFrame());

    // Lambdas
    final RubyNode composed = composeBody(preludeLambda, body /* no copy, last usage */);
    final RubyNode bodyLambda =
        new CatchForLambdaNode(
            context, composed.getEncapsulatingSourceSection(), composed, environment.getReturnID());

    final RubyRootNode newRootNodeForLambdas =
        new RubyRootNode(
            context,
            considerExtendingMethodToCoverEnd(bodyLambda.getEncapsulatingSourceSection()),
            environment.getFrameDescriptor(),
            environment.getSharedMethodInfo(),
            bodyLambda,
            environment.needsDeclarationFrame());

    // TODO CS 23-Nov-15 only the second one will get instrumented properly!
    final CallTarget callTargetAsLambda =
        Truffle.getRuntime().createCallTarget(newRootNodeForLambdas);
    final CallTarget callTargetAsProc = Truffle.getRuntime().createCallTarget(newRootNodeForProcs);

    FrameSlot frameOnStackMarkerSlot;

    if (frameOnStackMarkerSlotStack.isEmpty()) {
      frameOnStackMarkerSlot = null;
    } else {
      frameOnStackMarkerSlot = frameOnStackMarkerSlotStack.peek();

      if (frameOnStackMarkerSlot == BAD_FRAME_SLOT) {
        frameOnStackMarkerSlot = null;
      }
    }

    return new BlockDefinitionNode(
        context,
        newRootNodeForProcs.getEncapsulatingSourceSection(),
        type,
        environment.getSharedMethodInfo(),
        callTargetAsProc,
        callTargetAsLambda,
        environment.getBreakID(),
        frameOnStackMarkerSlot);
  }