ClassNodes.java

  1. /*
  2.  * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
  3.  * code is released under a tri EPL/GPL/LGPL license. You can use it,
  4.  * redistribute it and/or modify it under the terms of the:
  5.  *
  6.  * Eclipse Public License version 1.0
  7.  * GNU General Public License version 2
  8.  * GNU Lesser General Public License version 2.1
  9.  */
  10. package org.jruby.truffle.nodes.core;

  11. import com.oracle.truffle.api.CompilerDirectives;
  12. import com.oracle.truffle.api.dsl.Specialization;
  13. import com.oracle.truffle.api.frame.VirtualFrame;
  14. import com.oracle.truffle.api.source.SourceSection;
  15. import org.jruby.runtime.Visibility;
  16. import org.jruby.truffle.nodes.RubyNode;
  17. import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
  18. import org.jruby.truffle.runtime.RubyContext;
  19. import org.jruby.truffle.runtime.UndefinedPlaceholder;
  20. import org.jruby.truffle.runtime.control.RaiseException;
  21. import org.jruby.truffle.runtime.core.RubyBasicObject;
  22. import org.jruby.truffle.runtime.core.RubyClass;
  23. import org.jruby.truffle.runtime.core.RubyNilClass;
  24. import org.jruby.truffle.runtime.core.RubyProc;

  25. @CoreClass(name = "Class")
  26. public abstract class ClassNodes {

  27.     @CoreMethod(names = "allocate")
  28.     public abstract static class AllocateNode extends CoreMethodNode {

  29.         public AllocateNode(RubyContext context, SourceSection sourceSection) {
  30.             super(context, sourceSection);
  31.         }

  32.         public AllocateNode(AllocateNode prev) {
  33.             super(prev);
  34.         }

  35.         public abstract RubyBasicObject executeAllocate(VirtualFrame frame, RubyClass rubyClass);

  36.         @Specialization
  37.         public RubyBasicObject allocate(RubyClass rubyClass) {
  38.             if (rubyClass.isSingleton()) {
  39.                 CompilerDirectives.transferToInterpreter();
  40.                 throw new RaiseException(getContext().getCoreLibrary().typeError("can't create instance of singleton class", this));
  41.             }
  42.             return rubyClass.allocate(this);
  43.         }

  44.     }

  45.     @CoreMethod(names = "new", needsBlock = true, argumentsAsArray = true)
  46.     public abstract static class NewNode extends CoreMethodNode {

  47.         @Child protected AllocateNode allocateNode;
  48.         @Child protected DispatchHeadNode initialize;
  49.         @CompilerDirectives.CompilationFinal private boolean isCached = true;
  50.         @CompilerDirectives.CompilationFinal private RubyClass cachedClass;

  51.         public NewNode(RubyContext context, SourceSection sourceSection) {
  52.             super(context, sourceSection);
  53.             allocateNode = ClassNodesFactory.AllocateNodeFactory.create(context, sourceSection, new RubyNode[]{null});
  54.             initialize = DispatchHeadNode.onSelf(context);
  55.         }

  56.         public NewNode(NewNode prev) {
  57.             super(prev);
  58.             allocateNode = prev.allocateNode;
  59.             initialize = prev.initialize;
  60.         }

  61.         @Specialization
  62.         public RubyBasicObject newInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, @SuppressWarnings("unused") UndefinedPlaceholder block) {
  63.             return doNewInstance(frame, rubyClass, args, null);
  64.         }

  65.         @Specialization
  66.         public RubyBasicObject newInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, RubyProc block) {
  67.             return doNewInstance(frame, rubyClass, args, block);
  68.         }

  69.         private RubyBasicObject doNewInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, RubyProc block) {
  70.             final RubyBasicObject instance = allocateNode.executeAllocate(frame, rubyClass);
  71.             initialize.call(frame, instance, "initialize", block, args);
  72.             return instance;
  73.         }
  74.     }

  75.     @CoreMethod(names = "initialize", optional = 1, needsBlock = true)
  76.     public abstract static class InitializeNode extends CoreMethodNode {

  77.         @Child protected ModuleNodes.InitializeNode moduleInitializeNode;

  78.         public InitializeNode(RubyContext context, SourceSection sourceSection) {
  79.             super(context, sourceSection);
  80.         }

  81.         public InitializeNode(InitializeNode prev) {
  82.             super(prev);
  83.         }

  84.         void moduleInitialize(VirtualFrame frame, RubyClass rubyClass, RubyProc block) {
  85.             if (moduleInitializeNode == null) {
  86.                 CompilerDirectives.transferToInterpreterAndInvalidate();
  87.                 moduleInitializeNode = insert(ModuleNodesFactory.InitializeNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{null,null}));
  88.             }
  89.             moduleInitializeNode.executeInitialize(frame, rubyClass, block);
  90.         }

  91.         @Specialization
  92.         public RubyClass initialize(RubyClass rubyClass, UndefinedPlaceholder superclass, UndefinedPlaceholder block) {
  93.             return initialize(rubyClass, getContext().getCoreLibrary().getObjectClass(), block);
  94.         }

  95.         @Specialization
  96.         public RubyClass initialize(RubyClass rubyClass, RubyClass superclass, UndefinedPlaceholder block) {
  97.             rubyClass.initialize(superclass);
  98.             return rubyClass;
  99.         }

  100.         @Specialization
  101.         public RubyClass initialize(VirtualFrame frame, RubyClass rubyClass, UndefinedPlaceholder superclass, RubyProc block) {
  102.             return initialize(frame, rubyClass, getContext().getCoreLibrary().getObjectClass(), block);
  103.         }

  104.         @Specialization
  105.         public RubyClass initialize(VirtualFrame frame, RubyClass rubyClass, RubyClass superclass, RubyProc block) {
  106.             rubyClass.initialize(superclass);
  107.             moduleInitialize(frame, rubyClass, block);
  108.             return rubyClass;
  109.         }

  110.     }

  111.     @CoreMethod(names = "inherited", required = 1, visibility = Visibility.PRIVATE)
  112.     public abstract static class InheritedNode extends CoreMethodNode {

  113.         public InheritedNode(RubyContext context, SourceSection sourceSection) {
  114.             super(context, sourceSection);
  115.         }

  116.         public InheritedNode(InheritedNode prev) {
  117.             super(prev);
  118.         }

  119.         @Specialization
  120.         public RubyNilClass inherited(Object subclass) {
  121.             return getContext().getCoreLibrary().getNilObject();
  122.         }

  123.     }

  124.     @CoreMethod(names = "superclass")
  125.     public abstract static class SuperClassNode extends CoreMethodNode {

  126.         public SuperClassNode(RubyContext context, SourceSection sourceSection) {
  127.             super(context, sourceSection);
  128.         }

  129.         public SuperClassNode(SuperClassNode prev) {
  130.             super(prev);
  131.         }

  132.         @Specialization
  133.         public RubyClass getSuperClass(RubyClass rubyClass) {
  134.             return rubyClass.getSuperClass();
  135.         }
  136.     }
  137. }