Пример #1
0
/**
 * Represents a block of code run with exception handlers. There's no {@code try} keyword in Ruby -
 * it's implicit - but it's similar to a try statement in any other language.
 */
public class TryNode extends RubyNode {

  @Child protected ExceptionTranslatingNode tryPart;
  @Children final RescueNode[] rescueParts;
  @Child protected RubyNode elsePart;
  @Child protected WriteInstanceVariableNode clearExceptionVariableNode;

  private final BranchProfile elseProfile = BranchProfile.create();
  private final BranchProfile controlFlowProfile = BranchProfile.create();
  private final BranchProfile raiseExceptionProfile = BranchProfile.create();

  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);
  }

  @Override
  public Object execute(VirtualFrame frame) {
    while (true) {
      getContext().getSafepointManager().poll();

      Object result;

      try {
        result = tryPart.execute(frame);
      } catch (ControlFlowException exception) {
        controlFlowProfile.enter();
        throw exception;
      } catch (RaiseException exception) {
        raiseExceptionProfile.enter();

        try {
          return handleException(frame, exception);
        } catch (RetryException e) {
          continue;
        }
      } finally {
        clearExceptionVariableNode.execute(frame);
      }

      elseProfile.enter();
      elsePart.executeVoid(frame);
      return result;
    }
  }

  @ExplodeLoop
  private Object handleException(VirtualFrame frame, RaiseException exception) {
    CompilerAsserts.neverPartOfCompilation();

    notDesignedForCompilation();
    getContext()
        .getCoreLibrary()
        .getGlobalVariablesObject()
        .getOperations()
        .setInstanceVariable(
            getContext().getCoreLibrary().getGlobalVariablesObject(),
            "$!",
            exception.getRubyException());

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

    throw exception;
  }
}
Пример #2
0
/**
 * {@link WriteSuperFrameVariableNode} captures a write to a variable in some parent frame.
 *
 * <p>The state starts out a "unresolved" and transforms to "resolved".
 */
@SuppressWarnings("unused")
@NodeChildren({
  @NodeChild(value = "enclosingFrame", type = AccessEnclosingFrameNode.class),
  @NodeChild(value = "frameSlotNode", type = FrameSlotNode.class)
})
@NodeField(name = "mode", type = Mode.class)
public abstract class WriteSuperFrameVariableNode extends WriteSuperFrameVariableNodeHelper {
  private final ValueProfile storedObjectProfile = ValueProfile.createClassProfile();
  private final BranchProfile invalidateProfile = BranchProfile.create();
  private final ValueProfile enclosingFrameProfile = ValueProfile.createClassProfile();

  protected abstract FrameSlotNode getFrameSlotNode();

  public abstract Mode getMode();

  public static WriteVariableNode create(String name, RNode rhs, Mode mode) {
    return new UnresolvedWriteSuperFrameVariableNode(name, rhs, mode);
  }

  @Specialization(guards = "isLogicalKind(frame, frameSlot)")
  protected void doLogical(
      VirtualFrame frame, byte value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) {
    FrameSlotChangeMonitor.setByteAndInvalidate(
        enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile);
  }

  @Specialization(guards = "isIntegerKind(frame, frameSlot)")
  protected void doInteger(
      VirtualFrame frame, int value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) {
    FrameSlotChangeMonitor.setIntAndInvalidate(
        enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile);
  }

  @Specialization(guards = "isDoubleKind(frame, frameSlot)")
  protected void doDouble(
      VirtualFrame frame, double value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) {
    FrameSlotChangeMonitor.setDoubleAndInvalidate(
        enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile);
  }

  @Specialization
  protected void doObject(
      VirtualFrame frame, Object value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) {
    MaterializedFrame profiledFrame = enclosingFrameProfile.profile(enclosingFrame);
    Object newValue =
        shareObjectValue(
            profiledFrame, frameSlot, storedObjectProfile.profile(value), getMode(), true);
    FrameSlotChangeMonitor.setObjectAndInvalidate(
        profiledFrame, frameSlot, newValue, true, invalidateProfile);
  }

  public static class UnresolvedWriteSuperFrameVariableNode
      extends WriteSuperFrameVariableNodeHelper {

    @Child private RNode rhs;
    private final String symbol;
    private final BaseWriteVariableNode.Mode mode;

    public UnresolvedWriteSuperFrameVariableNode(
        String symbol, RNode rhs, BaseWriteVariableNode.Mode mode) {
      this.rhs = rhs;
      this.symbol = symbol;
      this.mode = mode;
    }

    @Override
    public String getName() {
      return symbol;
    }

    @Override
    public RNode getRhs() {
      return rhs;
    }

    @Override
    public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) {
      CompilerDirectives.transferToInterpreterAndInvalidate();
      if (getName().isEmpty()) {
        throw RError.error(this, RError.Message.ZERO_LENGTH_VARIABLE);
      }
      final WriteSuperFrameVariableNodeHelper writeNode;
      if (REnvironment.isGlobalEnvFrame(enclosingFrame)) {
        /*
         * we've reached the global scope, do unconditional write. if this is the first node
         * in the chain, needs the rhs and enclosingFrame nodes
         */
        AccessEnclosingFrameNode enclosingFrameNode =
            RArguments.getEnclosingFrame(frame) == enclosingFrame
                ? new AccessEnclosingFrameNode()
                : null;
        writeNode =
            WriteSuperFrameVariableNodeGen.create(
                getRhs(),
                enclosingFrameNode,
                FrameSlotNode.create(
                    findOrAddFrameSlot(
                        enclosingFrame.getFrameDescriptor(), symbol, FrameSlotKind.Illegal)),
                getName(),
                mode);
      } else {
        WriteSuperFrameVariableNode actualWriteNode =
            WriteSuperFrameVariableNodeGen.create(
                null, null, FrameSlotNode.create(symbol), this.getName(), mode);
        writeNode =
            new WriteSuperFrameVariableConditionalNode(
                actualWriteNode,
                new UnresolvedWriteSuperFrameVariableNode(symbol, null, mode),
                getRhs());
      }
      replace(writeNode).execute(frame, value, enclosingFrame);
    }

    @Override
    public void execute(VirtualFrame frame, Object value) {
      CompilerDirectives.transferToInterpreterAndInvalidate();
      MaterializedFrame enclosingFrame = RArguments.getEnclosingFrame(frame);
      if (enclosingFrame != null) {
        execute(frame, value, enclosingFrame);
      } else {
        // we're in global scope, do a local write instead
        replace(UnresolvedWriteLocalFrameVariableNodeGen.create(getRhs(), symbol, mode))
            .execute(frame, value);
      }
    }
  }

  public static class WriteSuperFrameVariableConditionalNode
      extends WriteSuperFrameVariableNodeHelper {

    @Child private WriteSuperFrameVariableNode writeNode;
    @Child private WriteSuperFrameVariableNodeHelper nextNode;
    @Child private RNode rhs;

    private final ValueProfile enclosingFrameProfile = ValueProfile.createClassProfile();
    private final ConditionProfile hasValueProfile = ConditionProfile.createBinaryProfile();
    private final ConditionProfile nullSuperFrameProfile = ConditionProfile.createBinaryProfile();

    WriteSuperFrameVariableConditionalNode(
        WriteSuperFrameVariableNode writeNode,
        WriteSuperFrameVariableNodeHelper nextNode,
        RNode rhs) {
      this.writeNode = writeNode;
      this.nextNode = nextNode;
      this.rhs = rhs;
    }

    @Override
    public Object getName() {
      return writeNode.getName();
    }

    @Override
    public RNode getRhs() {
      return rhs;
    }

    @Override
    public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) {
      MaterializedFrame profiledEnclosingFrame = enclosingFrameProfile.profile(enclosingFrame);
      if (hasValueProfile.profile(writeNode.getFrameSlotNode().hasValue(profiledEnclosingFrame))) {
        writeNode.execute(frame, value, profiledEnclosingFrame);
      } else {
        MaterializedFrame superFrame = RArguments.getEnclosingFrame(profiledEnclosingFrame);
        if (nullSuperFrameProfile.profile(superFrame == null)) {
          // Might be the case if "{ x <<- 42 }": This is in globalEnv!
          superFrame = REnvironment.globalEnv().getFrame();
        }
        nextNode.execute(frame, value, superFrame);
      }
    }

    @Override
    public void execute(VirtualFrame frame, Object value) {
      assert RArguments.getEnclosingFrame(frame) != null;
      execute(frame, value, RArguments.getEnclosingFrame(frame));
    }
  }
}
Пример #3
0
abstract class PositionCheckNode extends Node {

  protected final Class<?> positionClass;
  protected final int dimensionIndex;
  protected final int numDimensions;
  protected final VectorLengthProfile positionLengthProfile = VectorLengthProfile.create();
  protected final BranchProfile error = BranchProfile.create();
  protected final boolean replace;
  protected final RType containerType;
  @Child private PositionCastNode castNode;
  @Child private RLengthNode positionLengthNode = RLengthNode.create();
  @Child private PositionCharacterLookupNode characterLookup;

  PositionCheckNode(
      ElementAccessMode mode,
      RType containerType,
      Object positionValue,
      int dimensionIndex,
      int numDimensions,
      boolean exact,
      boolean replace) {
    this.positionClass = positionValue.getClass();
    this.dimensionIndex = dimensionIndex;
    this.numDimensions = numDimensions;
    this.replace = replace;
    this.containerType = containerType;
    this.castNode = PositionCastNode.create(mode, replace);
    if (positionValue instanceof String || positionValue instanceof RAbstractStringVector) {
      boolean useNAForNotFound = !replace && isListLike(containerType) && mode.isSubscript();
      characterLookup =
          new PositionCharacterLookupNode(
              mode, numDimensions, dimensionIndex, useNAForNotFound, exact);
    }
  }

  protected static boolean isListLike(RType type) {
    switch (type) {
      case Language:
      case DataFrame:
      case Expression:
      case PairList:
      case List:
        return true;
    }
    return false;
  }

  public boolean isIgnoreDimension() {
    return positionClass == RMissing.class;
  }

  public Class<?> getPositionClass() {
    return positionClass;
  }

  public final boolean isSupported(Object object) {
    return object.getClass() == positionClass;
  }

  public static PositionCheckNode createNode(
      ElementAccessMode mode,
      RType containerType,
      Object position,
      int positionIndex,
      int numDimensions,
      boolean exact,
      boolean replace,
      boolean recursive) {
    if (mode.isSubset()) {
      return PositionCheckSubsetNodeGen.create(
          mode, containerType, position, positionIndex, numDimensions, exact, replace);
    } else {
      return PositionCheckSubscriptNodeGen.create(
          mode, containerType, position, positionIndex, numDimensions, exact, replace, recursive);
    }
  }

  protected boolean isMultiDimension() {
    return numDimensions > 1;
  }

  public final Object execute(
      PositionProfile profile,
      RAbstractContainer vector,
      int[] vectorDimensions,
      int vectorLength,
      Object position) {
    Object castPosition = castNode.execute(positionClass.cast(position));

    int dimensionLength;
    if (numDimensions == 1) {
      dimensionLength = vectorLength;
    } else {
      assert vectorDimensions != null;
      assert vectorDimensions.length == numDimensions;
      dimensionLength = vectorDimensions[dimensionIndex];
    }

    if (characterLookup != null) {
      castPosition =
          characterLookup.execute(vector, (RAbstractStringVector) castPosition, dimensionLength);
    }

    RTypedValue positionVector = (RTypedValue) profilePosition(castPosition);

    int positionLength;
    if (positionVector instanceof RMissing) {
      positionLength = -1;
    } else {
      positionLength =
          positionLengthProfile.profile(((RAbstractVector) positionVector).getLength());
    }

    assert isValidCastedType(positionVector)
        : "result type of a position cast node must be integer or logical";

    return execute(profile, dimensionLength, positionVector, positionLength);
  }

  private final ValueProfile castedValue = ValueProfile.createClassProfile();

  Object profilePosition(Object positionVector) {
    return castedValue.profile(positionVector);
  }

  private static boolean isValidCastedType(RTypedValue positionVector) {
    RType type = positionVector.getRType();
    return type == RType.Integer
        || type == RType.Logical
        || type == RType.Character
        || type == RType.Double
        || type == RType.Null;
  }

  public abstract Object execute(
      PositionProfile statistics, int dimensionLength, Object position, int positionLength);
}