예제 #1
0
  @CompilerDirectives.TruffleBoundary
  public void prepend(Node currentNode, DynamicObject module) {
    assert RubyGuards.isRubyModule(module);

    checkFrozen(currentNode);

    // If the module we want to prepend already includes us, it is cyclic
    if (ModuleOperations.includesModule(module, rubyModuleObject)) {
      throw new RaiseException(
          getContext().getCoreLibrary().argumentError("cyclic prepend detected", currentNode));
    }

    ModuleChain mod = Layouts.MODULE.getFields(module).start;
    ModuleChain cur = start;
    while (mod != null
        && !(RubyGuards.isRubyModule(mod)
            && RubyGuards.isRubyClass(((ModuleFields) mod).rubyModuleObject))) {
      if (!(mod instanceof PrependMarker)) {
        if (!ModuleOperations.includesModule(rubyModuleObject, mod.getActualModule())) {
          cur.insertAfter(mod.getActualModule());
          Layouts.MODULE.getFields(mod.getActualModule()).addDependent(rubyModuleObject);
          cur = cur.getParentModule();
        }
      }
      mod = mod.getParentModule();
    }

    newVersion();
  }
예제 #2
0
  public void getAdoptedByLexicalParent(
      DynamicObject lexicalParent, String name, Node currentNode) {
    assert RubyGuards.isRubyModule(lexicalParent);

    Layouts.MODULE
        .getFields(lexicalParent)
        .setConstantInternal(currentNode, name, rubyModuleObject, false);
    Layouts.MODULE.getFields(lexicalParent).addLexicalDependent(rubyModuleObject);

    if (this.name == null) {
      // Tricky, we need to compare with the Object class, but we only have a Class at hand.
      final DynamicObject classClass = Layouts.BASIC_OBJECT.getLogicalClass(getLogicalClass());
      final DynamicObject objectClass =
          ClassNodes.getSuperClass(ClassNodes.getSuperClass(classClass));

      if (lexicalParent == objectClass) {
        this.name = name;
        updateAnonymousChildrenModules();
      } else if (Layouts.MODULE.getFields(lexicalParent).hasName()) {
        this.name = Layouts.MODULE.getFields(lexicalParent).getName() + "::" + name;
        updateAnonymousChildrenModules();
      }
      // else: Our lexicalParent is also an anonymous module
      // and will name us when it gets named via updateAnonymousChildrenModules()
    }
  }
예제 #3
0
  public static DynamicObject createOneSingletonClass(DynamicObject rubyClass) {
    CompilerAsserts.neverPartOfCompilation();

    if (Layouts.CLASS.getIsSingleton(Layouts.BASIC_OBJECT.getMetaClass(rubyClass))) {
      return Layouts.BASIC_OBJECT.getMetaClass(rubyClass);
    }

    final DynamicObject singletonSuperclass;
    if (getSuperClass(rubyClass) == null) {
      singletonSuperclass = Layouts.BASIC_OBJECT.getLogicalClass(rubyClass);
    } else {
      singletonSuperclass = createOneSingletonClass(getSuperClass(rubyClass));
    }

    String name = String.format("#<Class:%s>", Layouts.MODULE.getFields(rubyClass).getName());
    Layouts.BASIC_OBJECT.setMetaClass(
        rubyClass,
        ClassNodes.createRubyClass(
            Layouts.MODULE.getFields(Layouts.BASIC_OBJECT.getLogicalClass(rubyClass)).getContext(),
            Layouts.BASIC_OBJECT.getLogicalClass(rubyClass),
            null,
            singletonSuperclass,
            name,
            true,
            rubyClass));

    return Layouts.BASIC_OBJECT.getMetaClass(rubyClass);
  }
예제 #4
0
  @Override
  public DynamicObject execute(VirtualFrame frame) {
    CompilerDirectives.transferToInterpreter();

    final Object receiverObject = receiver.execute(frame);

    final InternalMethod methodObject = (InternalMethod) methodNode.execute(frame);

    final DynamicObject module = (DynamicObject) receiverObject;
    assert RubyGuards.isRubyModule(module);

    final Visibility visibility = getVisibility(frame, methodObject.getName());
    final InternalMethod method =
        methodObject.withDeclaringModule(module).withVisibility(visibility);

    if (method.getVisibility() == Visibility.MODULE_FUNCTION) {
      Layouts.MODULE.getFields(module).addMethod(this, method.withVisibility(Visibility.PRIVATE));
      Layouts.MODULE
          .getFields(singletonClassNode.executeSingletonClass(module))
          .addMethod(this, method.withVisibility(Visibility.PUBLIC));
    } else {
      Layouts.MODULE.getFields(module).addMethod(this, method);
    }

    return getSymbol(method.getName());
  }
예제 #5
0
 public void updateAnonymousChildrenModules() {
   for (Map.Entry<String, RubyConstant> entry : constants.entrySet()) {
     RubyConstant constant = entry.getValue();
     if (RubyGuards.isRubyModule(constant.getValue())) {
       DynamicObject module = (DynamicObject) constant.getValue();
       if (!Layouts.MODULE.getFields(module).hasName()) {
         Layouts.MODULE
             .getFields(module)
             .getAdoptedByLexicalParent(rubyModuleObject, entry.getKey(), null);
       }
     }
   }
 }
예제 #6
0
 public static void debugModuleChain(DynamicObject module) {
   assert RubyGuards.isRubyModule(module);
   ModuleChain chain = Layouts.MODULE.getFields(module);
   while (chain != null) {
     System.err.print(chain.getClass());
     if (!(chain instanceof PrependMarker)) {
       DynamicObject real = chain.getActualModule();
       System.err.print(" " + Layouts.MODULE.getFields(real).getName());
     }
     System.err.println();
     chain = chain.getParentModule();
   }
 }
예제 #7
0
  public static void initialize(DynamicObject rubyClass, DynamicObject superclass) {
    assert RubyGuards.isRubyClass(superclass);

    Layouts.MODULE.getFields(rubyClass).parentModule = Layouts.MODULE.getFields(superclass).start;
    Layouts.MODULE.getFields(superclass).addDependent(rubyClass);

    Layouts.MODULE.getFields(rubyClass).newVersion();
    ensureSingletonConsistency(rubyClass);

    DynamicObjectFactory factory = Layouts.CLASS.getInstanceFactory(superclass);
    factory = Layouts.BASIC_OBJECT.setLogicalClass(factory, rubyClass);
    factory = Layouts.BASIC_OBJECT.setMetaClass(factory, rubyClass);
    Layouts.CLASS.setInstanceFactoryUnsafe(rubyClass, factory);
  }
예제 #8
0
  public DynamicObject getNormalObjectSingletonClass(DynamicObject object) {
    CompilerAsserts.neverPartOfCompilation();

    if (RubyGuards.isRubyClass(object)) { // For the direct caller
      return ClassNodes.getSingletonClass(object);
    }

    if (Layouts.CLASS.getIsSingleton(Layouts.BASIC_OBJECT.getMetaClass(object))) {
      return Layouts.BASIC_OBJECT.getMetaClass(object);
    }

    CompilerDirectives.transferToInterpreter();
    final DynamicObject logicalClass = BasicObjectNodes.getLogicalClass(object);

    DynamicObject attached = null;
    if (RubyGuards.isRubyModule(object)) {
      attached = object;
    }

    final String name =
        String.format(
            "#<Class:#<%s:0x%x>>",
            Layouts.MODULE.getFields(logicalClass).getName(),
            BasicObjectNodes.verySlowGetObjectID(object));
    final DynamicObject singletonClass =
        ClassNodes.createSingletonClassOfObject(getContext(), logicalClass, attached, name);
    propagateFrozen(object, singletonClass);

    Layouts.BASIC_OBJECT.setMetaClass(object, singletonClass);

    return singletonClass;
  }
예제 #9
0
 public void performIncludes(ModuleChain inclusionPoint, Deque<DynamicObject> moduleAncestors) {
   while (!moduleAncestors.isEmpty()) {
     DynamicObject mod = moduleAncestors.pop();
     assert RubyGuards.isRubyModule(mod);
     inclusionPoint.insertAfter(mod);
     Layouts.MODULE.getFields(mod).addDependent(rubyModuleObject);
   }
 }
예제 #10
0
 // TODO (eregon, 12 May 2015): ideally all callers would be nodes and check themselves.
 public void checkFrozen(Node currentNode) {
   if (getContext().getCoreLibrary() != null && verySlowIsFrozen(getContext(), rubyModuleObject)) {
     CompilerDirectives.transferToInterpreter();
     throw new RaiseException(
         getContext()
             .getCoreLibrary()
             .frozenError(Layouts.MODULE.getFields(getLogicalClass()).getName(), currentNode));
   }
 }
예제 #11
0
  public void newVersion(Set<DynamicObject> alreadyInvalidated, boolean considerLexicalDependents) {
    if (alreadyInvalidated.contains(rubyModuleObject)) return;

    unmodifiedAssumption.invalidate();
    alreadyInvalidated.add(rubyModuleObject);

    // Make dependents new versions
    for (DynamicObject dependent : dependents) {
      Layouts.MODULE.getFields(dependent).newVersion(alreadyInvalidated, considerLexicalDependents);
    }

    if (considerLexicalDependents) {
      for (DynamicObject dependent : lexicalDependents) {
        Layouts.MODULE
            .getFields(dependent)
            .newVersion(alreadyInvalidated, considerLexicalDependents);
      }
    }
  }
예제 #12
0
 public String getName() {
   if (name != null) {
     return name;
   } else {
     CompilerDirectives.transferToInterpreter();
     if (givenBaseName != null) {
       return Layouts.MODULE.getFields(lexicalParent).getName() + "::" + givenBaseName;
     } else if (getLogicalClass()
         == rubyModuleObject) { // For the case of class Class during initialization
       return "#<cyclic>";
     } else {
       return "#<"
           + Layouts.MODULE.getFields(getLogicalClass()).getName()
           + ":0x"
           + Long.toHexString(ObjectIDOperations.verySlowGetObjectID(rubyModuleObject))
           + ">";
     }
   }
 }
예제 #13
0
  public static DynamicObject getSuperClass(DynamicObject rubyClass) {
    CompilerAsserts.neverPartOfCompilation();

    for (DynamicObject ancestor : Layouts.MODULE.getFields(rubyClass).parentAncestors()) {
      if (RubyGuards.isRubyClass(ancestor)) {
        return ancestor;
      }
    }

    return null;
  }
예제 #14
0
  public static DynamicObject createRubyClass(
      RubyContext context,
      DynamicObject classClass,
      DynamicObject lexicalParent,
      DynamicObject superclass,
      String name,
      boolean isSingleton,
      DynamicObject attached) {
    final ModuleFields model = new ModuleFields(context, lexicalParent, name);

    final DynamicObject rubyClass =
        Layouts.CLASS.createClass(
            Layouts.CLASS.getInstanceFactory(classClass), model, isSingleton, attached, null);
    assert RubyGuards.isRubyClass(rubyClass) : classClass.getShape().getObjectType().getClass();
    assert RubyGuards.isRubyModule(rubyClass) : classClass.getShape().getObjectType().getClass();

    model.rubyModuleObject = rubyClass;

    if (model.lexicalParent == null) { // bootstrap or anonymous module
      Layouts.MODULE.getFields(rubyClass).name = Layouts.MODULE.getFields(rubyClass).givenBaseName;
    } else {
      Layouts.MODULE
          .getFields(rubyClass)
          .getAdoptedByLexicalParent(model.lexicalParent, model.givenBaseName, null);
    }

    if (superclass != null) {
      assert RubyGuards.isRubyClass(superclass);
      assert RubyGuards.isRubyClass(Layouts.MODULE.getFields(rubyClass).rubyModuleObject);

      Layouts.MODULE.getFields(rubyClass).parentModule = Layouts.MODULE.getFields(superclass).start;
      Layouts.MODULE
          .getFields(superclass)
          .addDependent(Layouts.MODULE.getFields(rubyClass).rubyModuleObject);

      Layouts.MODULE.getFields(rubyClass).newVersion();
    }

    DynamicObjectFactory factory = Layouts.CLASS.getInstanceFactory(superclass);
    factory = Layouts.BASIC_OBJECT.setLogicalClass(factory, rubyClass);
    factory = Layouts.BASIC_OBJECT.setMetaClass(factory, rubyClass);
    Layouts.CLASS.setInstanceFactoryUnsafe(rubyClass, factory);

    return rubyClass;
  }
예제 #15
0
  /**
   * This constructor supports initialization and solves boot-order problems and should not normally
   * be used from outside this class.
   */
  public static DynamicObject createBootClass(
      DynamicObject classClass, DynamicObject superclass, String name) {
    assert RubyGuards.isRubyClass(classClass);
    assert superclass == null || RubyGuards.isRubyClass(superclass);
    final ModuleFields model =
        new ModuleFields(
            Layouts.MODULE.getFields(Layouts.BASIC_OBJECT.getLogicalClass(classClass)).getContext(),
            null,
            name);

    final DynamicObject rubyClass =
        Layouts.CLASS.createClass(
            Layouts.CLASS.getInstanceFactory(classClass), model, false, null, null);
    assert RubyGuards.isRubyClass(rubyClass) : classClass.getShape().getObjectType().getClass();
    assert RubyGuards.isRubyModule(rubyClass) : classClass.getShape().getObjectType().getClass();

    model.rubyModuleObject = rubyClass;

    if (model.lexicalParent == null) { // bootstrap or anonymous module
      Layouts.MODULE.getFields(rubyClass).name = Layouts.MODULE.getFields(rubyClass).givenBaseName;
    } else {
      Layouts.MODULE
          .getFields(rubyClass)
          .getAdoptedByLexicalParent(model.lexicalParent, model.givenBaseName, null);
    }

    if (superclass != null) {
      assert RubyGuards.isRubyClass(superclass);
      assert RubyGuards.isRubyClass(Layouts.MODULE.getFields(rubyClass).rubyModuleObject);

      Layouts.MODULE.getFields(rubyClass).parentModule = Layouts.MODULE.getFields(superclass).start;
      Layouts.MODULE
          .getFields(superclass)
          .addDependent(Layouts.MODULE.getFields(rubyClass).rubyModuleObject);

      Layouts.MODULE.getFields(rubyClass).newVersion();
    }

    return rubyClass;
  }
  public CachedBoxedReturnMissingDispatchNode(
      RubyContext context,
      Object cachedName,
      DispatchNode next,
      Shape expectedShape,
      DynamicObject expectedClass,
      DispatchAction dispatchAction) {
    super(context, cachedName, next, dispatchAction);

    this.expectedShape = expectedShape;
    this.unmodifiedAssumption = Layouts.MODULE.getFields(expectedClass).getUnmodifiedAssumption();
    this.next = next;
  }
예제 #17
0
  @CompilerDirectives.TruffleBoundary
  public void initCopy(DynamicObject from) {
    assert RubyGuards.isRubyModule(from);

    // Do not copy name, the copy is an anonymous module
    this.methods.putAll(Layouts.MODULE.getFields(from).methods);
    this.constants.putAll(Layouts.MODULE.getFields(from).constants);
    this.classVariables.putAll(Layouts.MODULE.getFields(from).classVariables);

    if (Layouts.MODULE.getFields(from).start.getParentModule() != Layouts.MODULE.getFields(from)) {
      this.parentModule = Layouts.MODULE.getFields(from).start.getParentModule();
    } else {
      this.parentModule = Layouts.MODULE.getFields(from).parentModule;
    }

    for (DynamicObject ancestor : Layouts.MODULE.getFields(from).ancestors()) {
      Layouts.MODULE.getFields(ancestor).addDependent(rubyModuleObject);
    }
  }
  public CachedSingletonDispatchNode(
      RubyContext context,
      Object cachedName,
      DispatchNode next,
      DynamicObject expectedReceiver,
      DynamicObject expectedClass,
      InternalMethod method,
      DispatchAction dispatchAction) {
    super(context, cachedName, next, dispatchAction);

    this.expectedReceiver = expectedReceiver;
    this.unmodifiedAssumption = Layouts.MODULE.getFields(expectedClass).getUnmodifiedAssumption();
    this.next = next;
    this.method = method;
    this.callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
    applySplittingInliningStrategy(callNode, method);
  }
예제 #19
0
  @Override
  public Object execute(VirtualFrame frame) {
    CompilerDirectives.transferToInterpreter();

    // TODO(CS): cast
    final DynamicObject module = (DynamicObject) definingModule.execute(frame);

    lexicalScope.setLiveModule(module);
    Layouts.MODULE.getFields(lexicalScope.getParent().getLiveModule()).addLexicalDependent(module);

    final InternalMethod definition =
        definitionMethod.executeMethod(frame).withDeclaringModule(module);
    return callModuleDefinitionNode.call(
        frame,
        definition.getCallTarget(),
        RubyArguments.pack(
            definition, null, null, module, null, DeclarationContext.MODULE, new Object[] {}));
  }
예제 #20
0
  /** Set the value of a constant, possibly redefining it. */
  @CompilerDirectives.TruffleBoundary
  public void setConstant(Node currentNode, String name, Object value) {
    if (getContext().getCoreLibrary().isLoadingRubyCore()) {
      final RubyConstant currentConstant = constants.get(name);

      if (currentConstant != null) {
        return;
      }
    }

    if (RubyGuards.isRubyModule(value)) {
      Layouts.MODULE
          .getFields(((DynamicObject) value))
          .getAdoptedByLexicalParent(rubyModuleObject, name, currentNode);
    } else {
      setConstantInternal(currentNode, name, value, false);
    }
  }
예제 #21
0
  @CompilerDirectives.TruffleBoundary
  public void include(Node currentNode, DynamicObject module) {
    assert RubyGuards.isRubyModule(module);

    checkFrozen(currentNode);

    // If the module we want to include already includes us, it is cyclic
    if (ModuleOperations.includesModule(module, rubyModuleObject)) {
      throw new RaiseException(
          getContext().getCoreLibrary().argumentError("cyclic include detected", currentNode));
    }

    // We need to include the module ancestors in reverse order for a given inclusionPoint
    ModuleChain inclusionPoint = this;
    Deque<DynamicObject> modulesToInclude = new ArrayDeque<>();
    for (DynamicObject ancestor : Layouts.MODULE.getFields(module).ancestors()) {
      if (ModuleOperations.includesModule(rubyModuleObject, ancestor)) {
        if (isIncludedModuleBeforeSuperClass(ancestor)) {
          // Include the modules at the appropriate inclusionPoint
          performIncludes(inclusionPoint, modulesToInclude);
          assert modulesToInclude.isEmpty();

          // We need to include the others after that module
          inclusionPoint = parentModule;
          while (inclusionPoint.getActualModule() != ancestor) {
            inclusionPoint = inclusionPoint.getParentModule();
          }
        } else {
          // Just ignore this module, as it is included above the superclass
        }
      } else {
        modulesToInclude.push(ancestor);
      }
    }

    performIncludes(inclusionPoint, modulesToInclude);

    newVersion();
  }
예제 #22
0
  /** Special constructor for class Class */
  public static DynamicObject createClassClass(RubyContext context) {
    final ModuleFields model = new ModuleFields(context, null, "Class");

    final DynamicObject rubyClass = LAYOUT.newInstance(LAYOUT.createShape(new ObjectType()));

    final DynamicObjectFactory factory = Layouts.CLASS.createClassShape(rubyClass, rubyClass);

    rubyClass.setShapeAndGrow(rubyClass.getShape(), factory.getShape());
    assert RubyGuards.isRubyModule(rubyClass);
    assert RubyGuards.isRubyClass(rubyClass);

    model.rubyModuleObject = rubyClass;
    Layouts.CLASS.setInstanceFactoryUnsafe(rubyClass, factory);
    Layouts.MODULE.setFields(rubyClass, model);
    model.name = model.givenBaseName;

    assert RubyGuards.isRubyModule(rubyClass);
    assert RubyGuards.isRubyClass(rubyClass);
    assert Layouts.MODULE.getFields(rubyClass) == model;
    assert Layouts.BASIC_OBJECT.getLogicalClass(rubyClass) == rubyClass;

    return rubyClass;
  }
예제 #23
0
  private DynamicObject translate(UnsupportedSpecializationException exception) {
    if (getContext().getOptions().EXCEPTIONS_PRINT_JAVA) {
      exception.printStackTrace();
    }

    final StringBuilder builder = new StringBuilder();
    builder.append("Truffle doesn't have a case for the ");
    builder.append(exception.getNode().getClass().getName());
    builder.append(" node with values of type ");

    for (Object value : exception.getSuppliedValues()) {
      builder.append(" ");

      if (value == null) {
        builder.append("null");
      } else if (value instanceof DynamicObject) {
        builder.append(
            Layouts.MODULE
                .getFields(Layouts.BASIC_OBJECT.getLogicalClass(((DynamicObject) value)))
                .getName());
        builder.append("(");
        builder.append(value.getClass().getName());
        builder.append(")");

        if (RubyGuards.isRubyArray(value)) {
          final DynamicObject array = (DynamicObject) value;
          builder.append("[");

          if (Layouts.ARRAY.getStore(array) == null) {
            builder.append("null");
          } else {
            builder.append(Layouts.ARRAY.getStore(array).getClass().getName());
          }

          builder.append(",");
          builder.append(Layouts.ARRAY.getSize(array));
          builder.append("]");
        } else if (RubyGuards.isRubyHash(value)) {
          final Object store = Layouts.HASH.getStore((DynamicObject) value);

          if (store == null) {
            builder.append("[null]");
          } else {
            builder.append("[");
            builder.append(store.getClass().getName());
            builder.append("]");
          }
        }
      } else {
        builder.append(value.getClass().getName());
      }

      if (value instanceof Number || value instanceof Boolean) {
        builder.append("=");
        builder.append(value.toString());
      }
    }

    switch (unsupportedOperationBehavior) {
      case TYPE_ERROR:
        return getContext().getCoreLibrary().typeError(builder.toString(), this);
      case ARGUMENT_ERROR:
        return getContext().getCoreLibrary().argumentError(builder.toString(), this);
      default:
        throw new UnsupportedOperationException();
    }
  }
예제 #24
0
 public Assumption getUnmodifiedAssumption(DynamicObject module) {
   return Layouts.MODULE.getFields(module).getUnmodifiedAssumption();
 }