CachedUnboxedDispatchNode.java

  1. /*
  2.  * Copyright (c) 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.dispatch;

  11. import com.oracle.truffle.api.Assumption;
  12. import com.oracle.truffle.api.CompilerAsserts;
  13. import com.oracle.truffle.api.CompilerDirectives;
  14. import com.oracle.truffle.api.Truffle;
  15. import com.oracle.truffle.api.dsl.Fallback;
  16. import com.oracle.truffle.api.dsl.Specialization;
  17. import com.oracle.truffle.api.frame.VirtualFrame;
  18. import com.oracle.truffle.api.nodes.DirectCallNode;
  19. import com.oracle.truffle.api.nodes.IndirectCallNode;
  20. import com.oracle.truffle.api.nodes.InvalidAssumptionException;
  21. import org.jruby.truffle.runtime.LexicalScope;
  22. import org.jruby.truffle.runtime.RubyArguments;
  23. import org.jruby.truffle.runtime.RubyContext;
  24. import org.jruby.truffle.runtime.core.RubyBasicObject;
  25. import org.jruby.truffle.runtime.core.RubyProc;
  26. import org.jruby.truffle.runtime.methods.RubyMethod;

  27. public abstract class CachedUnboxedDispatchNode extends CachedDispatchNode {

  28.     private final Class<?> expectedClass;
  29.     private final Assumption unmodifiedAssumption;

  30.     private final Object value;

  31.     private final RubyMethod method;
  32.     @Child protected DirectCallNode callNode;
  33.     @Child protected IndirectCallNode indirectCallNode;

  34.     public CachedUnboxedDispatchNode(RubyContext context, Object cachedName, DispatchNode next,
  35.                                      Class<?> expectedClass, Assumption unmodifiedAssumption, Object value,
  36.                                      RubyMethod method, boolean indirect) {
  37.         super(context, cachedName, next, indirect);
  38.         this.expectedClass = expectedClass;
  39.         this.unmodifiedAssumption = unmodifiedAssumption;
  40.         this.value = value;
  41.         this.method = method;

  42.         if (method != null) {
  43.             if (indirect) {
  44.                 indirectCallNode = Truffle.getRuntime().createIndirectCallNode();
  45.             } else {
  46.                 callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
  47.             }
  48.         }
  49.     }

  50.     public CachedUnboxedDispatchNode(CachedUnboxedDispatchNode prev) {
  51.         super(prev);
  52.         expectedClass = prev.expectedClass;
  53.         unmodifiedAssumption = prev.unmodifiedAssumption;
  54.         value = prev.value;
  55.         method = prev.method;
  56.         callNode = prev.callNode;
  57.         indirectCallNode = prev.indirectCallNode;
  58.     }

  59.     @Specialization(guards = {"isPrimitive", "guardName"})
  60.     public Object dispatch(
  61.             VirtualFrame frame,
  62.             LexicalScope lexicalScope,
  63.             Object receiverObject,
  64.             Object methodName,
  65.             Object blockObject,
  66.             Object argumentsObjects,
  67.             Dispatch.DispatchAction dispatchAction) {
  68.         CompilerAsserts.compilationConstant(dispatchAction);

  69.         // Check the class is what we expect

  70.         if (receiverObject.getClass() != expectedClass) {
  71.             return next.executeDispatch(
  72.                     frame,
  73.                     lexicalScope,
  74.                     receiverObject,
  75.                     methodName,
  76.                     blockObject,
  77.                     argumentsObjects,
  78.                     dispatchAction);
  79.         }

  80.         // Check the class has not been modified

  81.         try {
  82.             unmodifiedAssumption.check();
  83.         } catch (InvalidAssumptionException e) {
  84.             return resetAndDispatch(
  85.                     frame,
  86.                     lexicalScope,
  87.                     receiverObject,
  88.                     methodName,
  89.                     CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
  90.                     argumentsObjects,
  91.                     dispatchAction,
  92.                     "class modified");
  93.         }

  94.         if (dispatchAction == Dispatch.DispatchAction.CALL_METHOD) {
  95.             if (isIndirect()) {
  96.                 return indirectCallNode.call(
  97.                         frame,
  98.                         method.getCallTarget(),
  99.                         RubyArguments.pack(
  100.                                 method,
  101.                                 method.getDeclarationFrame(),
  102.                                 receiverObject, CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
  103.                                 CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
  104.             } else {
  105.                 return callNode.call(
  106.                         frame,
  107.                         RubyArguments.pack(
  108.                                 method,
  109.                                 method.getDeclarationFrame(),
  110.                                 receiverObject, CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
  111.                                 CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
  112.             }
  113.         } else  if (dispatchAction == Dispatch.DispatchAction.RESPOND_TO_METHOD) {
  114.             return true;
  115.         } else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
  116.             return value;
  117.         } else {
  118.             throw new UnsupportedOperationException();
  119.         }
  120.     }

  121.     @Fallback
  122.     public Object dispatchFallback(
  123.             VirtualFrame frame,
  124.             LexicalScope lexicalScope,
  125.             Object receiverObject,
  126.             Object methodName,
  127.             Object blockObject,
  128.             Object argumentsObjects,
  129.             Dispatch.DispatchAction dispatchAction) {
  130.         return next.executeDispatch(
  131.                 frame,
  132.                 lexicalScope,
  133.                 receiverObject,
  134.                 methodName,
  135.                 CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
  136.                 argumentsObjects,
  137.                 dispatchAction);
  138.     }

  139.     protected static final boolean isPrimitive(
  140.             LexicalScope lexicalScope,
  141.             Object receiverObject,
  142.             Object methodName,
  143.             Object blockObject,
  144.             Object argumentsObjects) {
  145.         return !(receiverObject instanceof RubyBasicObject);
  146.     }

  147. }