Example #1
0
  public static IRubyObject lexicalSearchConst(
      ThreadContext context,
      StaticScope scope,
      MutableCallSite site,
      String constName,
      boolean noPrivateConsts)
      throws Throwable {
    Ruby runtime = context.runtime;

    IRubyObject constant = scope.getConstantInner(constName);

    if (constant == null) {
      constant = UndefinedValue.UNDEFINED;
    }

    SwitchPoint switchPoint = (SwitchPoint) runtime.getConstantInvalidator(constName).getData();

    // bind constant until invalidated
    MethodHandle target = Binder.from(site.type()).drop(0, 2).constant(constant);
    MethodHandle fallback =
        Binder.from(site.type())
            .append(site, constName)
            .append(noPrivateConsts)
            .invokeStatic(LOOKUP, Bootstrap.class, "lexicalSearchConst");

    site.setTarget(switchPoint.guardWithTest(target, fallback));

    return constant;
  }
  private static MethodHandle bindWithFallback(
      MethodHandle mh, RoboCallSite site, MethodHandle fallback) {
    SwitchPoint switchPoint = getInvalidator(site.getCaller());
    MethodType type = site.type();

    MethodHandle boundFallback = foldArguments(exactInvoker(type), fallback.bindTo(site));
    mh = switchPoint.guardWithTest(mh.asType(type), boundFallback);

    site.setTarget(mh);
    return mh;
  }
Example #3
0
  public static IRubyObject inheritanceSearchConst(
      ThreadContext context,
      IRubyObject cmVal,
      MutableCallSite site,
      String constName,
      boolean noPrivateConsts)
      throws Throwable {
    Ruby runtime = context.runtime;
    RubyModule module;

    if (cmVal instanceof RubyModule) {
      module = (RubyModule) cmVal;
    } else {
      throw runtime.newTypeError(cmVal + " is not a type/class");
    }

    IRubyObject constant =
        noPrivateConsts
            ? module.getConstantFromNoConstMissing(constName, false)
            : module.getConstantNoConstMissing(constName);

    if (constant == null) {
      constant = UndefinedValue.UNDEFINED;
    }

    SwitchPoint switchPoint = (SwitchPoint) runtime.getConstantInvalidator(constName).getData();

    // bind constant until invalidated
    MethodHandle target = Binder.from(site.type()).drop(0, 2).constant(constant);
    MethodHandle fallback =
        Binder.from(site.type())
            .append(site, constName)
            .append(noPrivateConsts)
            .invokeStatic(LOOKUP, Bootstrap.class, "inheritanceSearchConst");

    // test that module is same as before
    MethodHandle test =
        Binder.from(site.type().changeReturnType(boolean.class))
            .drop(0, 1)
            .insert(1, module.id)
            .invokeStaticQuiet(LOOKUP, Bootstrap.class, "testArg0ModuleMatch");
    target = guardWithTest(test, target, fallback);
    site.setTarget(switchPoint.guardWithTest(target, fallback));

    return constant;
  }
Example #4
0
  public static IRubyObject searchConst(
      ThreadContext context,
      StaticScope staticScope,
      MutableCallSite site,
      String constName,
      boolean noPrivateConsts)
      throws Throwable {

    // Lexical lookup
    Ruby runtime = context.getRuntime();
    RubyModule object = runtime.getObject();
    IRubyObject constant =
        (staticScope == null)
            ? object.getConstant(constName)
            : staticScope.getConstantInner(constName);

    // Inheritance lookup
    RubyModule module = null;
    if (constant == null) {
      // SSS FIXME: Is this null check case correct?
      module = staticScope == null ? object : staticScope.getModule();
      constant =
          noPrivateConsts
              ? module.getConstantFromNoConstMissing(constName, false)
              : module.getConstantNoConstMissing(constName);
    }

    // Call const_missing or cache
    if (constant == null) {
      return module.callMethod(context, "const_missing", context.runtime.fastNewSymbol(constName));
    }

    SwitchPoint switchPoint = (SwitchPoint) runtime.getConstantInvalidator(constName).getData();

    // bind constant until invalidated
    MethodHandle target = Binder.from(site.type()).drop(0, 2).constant(constant);
    MethodHandle fallback =
        Binder.from(site.type())
            .append(site, constName)
            .append(noPrivateConsts)
            .invokeStatic(LOOKUP, Bootstrap.class, "searchConst");

    site.setTarget(switchPoint.guardWithTest(target, fallback));

    return constant;
  }
Example #5
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;
  }