Beispiel #1
0
  static MethodHandle buildJittedHandle(InvokeSite site, DynamicMethod method, boolean blockGiven) {
    MethodHandle mh = null;
    SmartBinder binder;
    CompiledIRMethod compiledIRMethod = null;

    if (method instanceof CompiledIRMethod) {
      compiledIRMethod = (CompiledIRMethod) method;
    } else if (method instanceof InterpretedIRMethod) {
      DynamicMethod actualMethod = ((InterpretedIRMethod) method).getActualMethod();
      if (actualMethod instanceof CompiledIRMethod) {
        compiledIRMethod = (CompiledIRMethod) actualMethod;
      }
    }

    if (compiledIRMethod != null) {
      // attempt IR direct binding
      // TODO: this will have to expand when we start specializing arities

      binder = SmartBinder.from(site.signature).permute("context", "self", "arg.*", "block");

      if (site.arity == -1) {
        // already [], nothing to do
        mh = (MethodHandle) compiledIRMethod.getHandle();
      } else if (site.arity == 0) {
        MethodHandle specific;
        if ((specific = compiledIRMethod.getHandleFor(site.arity)) != null) {
          mh = specific;
        } else {
          mh = (MethodHandle) compiledIRMethod.getHandle();
          binder = binder.insert(2, "args", IRubyObject.NULL_ARRAY);
        }
      } else {
        MethodHandle specific;
        if ((specific = compiledIRMethod.getHandleFor(site.arity)) != null) {
          mh = specific;
        } else {
          mh = (MethodHandle) compiledIRMethod.getHandle();
          binder = binder.collect("args", "arg.*");
        }
      }

      if (!blockGiven) {
        binder = binder.append("block", Block.class, Block.NULL_BLOCK);
      }

      binder =
          binder
              .insert(1, "scope", StaticScope.class, compiledIRMethod.getStaticScope())
              .append("class", RubyModule.class, compiledIRMethod.getImplementationClass());

      mh = binder.invoke(mh).handle();
    }

    return mh;
  }
Beispiel #2
0
  public Binder prepareBinder() {
    SmartBinder binder = SmartBinder.from(signature);

    // prepare arg[]
    if (arity == -1) {
      // do nothing, already have IRubyObject[] in args
    } else if (arity == 0) {
      binder = binder.insert(argOffset, "args", IRubyObject.NULL_ARRAY);
    } else {
      binder = binder.collect("args", "arg[0-9]+");
    }

    // add block if needed
    if (signature.lastArgType() != Block.class) {
      binder = binder.append("block", Block.NULL_BLOCK);
    }

    // bind to site
    binder = binder.insert(0, "site", this);

    return binder.binder();
  }
Beispiel #3
0
  /**
   * Update the given call site using the new target, wrapping with appropriate guard and
   * argument-juggling logic. Return a handle suitable for invoking with the site's original method
   * type.
   */
  MethodHandle updateInvocationTarget(
      MethodHandle target,
      IRubyObject self,
      RubyModule testClass,
      CacheEntry entry,
      SwitchPoint switchPoint) {
    if (target == null
        || clearCount > Options.INVOKEDYNAMIC_MAXFAIL.load()
        || (!hasSeenType(testClass.id)
            && seenTypesCount() + 1 > Options.INVOKEDYNAMIC_MAXPOLY.load())) {
      setTarget(target = prepareBinder().invokeVirtualQuiet(lookup(), "fail"));
    } else {
      MethodHandle fallback;
      MethodHandle gwt;

      // if we've cached no types, and the site is bound and we haven't seen this new type...
      if (seenTypesCount() > 0 && getTarget() != null && !hasSeenType(testClass.id)) {
        // stack it up into a PIC
        if (Options.INVOKEDYNAMIC_LOG_BINDING.load())
          LOG.info(methodName + "\tadded to PIC " + logMethod(entry.method));
        fallback = getTarget();
      } else {
        // wipe out site with this new type and method
        String bind = boundOnce ? "rebind" : "bind";
        if (Options.INVOKEDYNAMIC_LOG_BINDING.load())
          LOG.info(
              methodName
                  + "\ttriggered site #"
                  + siteID
                  + " "
                  + bind); // + " (" + file() + ":" + line() + ")");
        fallback = this.fallback;
        clearTypes();
      }

      addType(testClass.id);

      SmartHandle test;
      SmartBinder selfTest = SmartBinder.from(signature.asFold(boolean.class)).permute("self");

      if (self instanceof RubySymbol
          || self instanceof RubyFixnum
          || self instanceof RubyFloat
          || self instanceof RubyNil
          || self instanceof RubyBoolean.True
          || self instanceof RubyBoolean.False) {

        test =
            selfTest
                .insert(1, "selfJavaType", self.getClass())
                .cast(boolean.class, Object.class, Class.class)
                .invoke(TEST_CLASS);

      } else {

        test =
            SmartBinder.from(signature.changeReturn(boolean.class))
                .permute("self")
                .insert(0, "selfClass", RubyClass.class, testClass)
                .invokeStaticQuiet(Bootstrap.LOOKUP, Bootstrap.class, "testType");
      }

      gwt = MethodHandles.guardWithTest(test.handle(), target, fallback);

      // wrap in switchpoint for mutation invalidation
      gwt = switchPoint.guardWithTest(gwt, fallback);

      setTarget(gwt);
    }

    return target;
  }