Beispiel #1
0
  @Override
  public IRubyObject call(
      ThreadContext context,
      IRubyObject self,
      RubyModule clazz,
      String name,
      IRubyObject arg0,
      IRubyObject arg1,
      IRubyObject arg2,
      Block block) {
    if (IRRuntimeHelpers.isDebug()) doDebug();

    DynamicMethodBox box = this.box;
    if (box.callCount >= 0) tryJit(context, box);
    DynamicMethod jittedMethod = box.actualMethod;

    if (jittedMethod != null) {
      return jittedMethod.call(context, self, clazz, name, arg0, arg1, arg2, block);
    } else {
      return INTERPRET_METHOD(
          context,
          ensureInstrsReady(),
          getImplementationClass().getMethodLocation(),
          self,
          name,
          arg0,
          arg1,
          arg2,
          block);
    }
  }
Beispiel #2
0
  protected Object interpretSuper(
      ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
    // SSS FIXME: We should check in the current module (for instance methods) or the current
    // module's meta class (for class methods)
    //
    // RubyModule currM = context.getCurrentScope().getStaticScope().getModule();
    // RubyModule klazz = (isInstanceMethodSuper) ? currM : currM.getMetaClass();
    //
    // The question is how do we know what this 'super' ought to do?
    // For 'super' that occurs in a method scope, this is easy to figure out.
    // But, what about 'super' that occurs in block scope?  How do we figure that out?
    RubyModule klazz = context.getFrameKlazz();

    // SSS FIXME: Even though we may know the method name in some instances,
    // we are not making use of it here.
    String methodName = context.getCurrentFrame().getName(); // methAddr.getName();

    checkSuperDisabledOrOutOfMethod(context, klazz, methodName);
    RubyClass superClass =
        RuntimeHelpers.findImplementerIfNecessary(self.getMetaClass(), klazz).getSuperClass();
    DynamicMethod method =
        superClass != null ? superClass.searchMethod(methodName) : UndefinedMethod.INSTANCE;

    Object rVal =
        method.isUndefined()
            ? RuntimeHelpers.callMethodMissing(
                context, self, method.getVisibility(), methodName, CallType.SUPER, args, block)
            : method.call(context, self, superClass, methodName, args, block);

    return hasUnusedResult() ? null : rVal;
  }
Beispiel #3
0
  @Override
  public Object interpret(
      ThreadContext context,
      DynamicScope currDynScope,
      IRubyObject self,
      Object[] temp,
      Block aBlock) {
    // FIXME: Receiver is not being used...should we be retrieving it?
    IRubyObject receiver = (IRubyObject) getReceiver().retrieve(context, self, currDynScope, temp);
    IRubyObject[] args = prepareArguments(context, self, getCallArgs(), currDynScope, temp);
    Block block = prepareBlock(context, self, currDynScope, temp);
    RubyModule klazz = context.getFrameKlazz();
    // SSS FIXME: Even though we may know the method name in some instances,
    // we are not making use of it here.  It is cleaner in the sense of not
    // relying on implicit information whose data flow doesn't show up in the IR.
    String methodName = context.getCurrentFrame().getName(); // methAddr.getName();

    checkSuperDisabledOrOutOfMethod(context, klazz, methodName);
    RubyClass superClass =
        RuntimeHelpers.findImplementerIfNecessary(self.getMetaClass(), klazz).getSuperClass();
    DynamicMethod method =
        superClass != null ? superClass.searchMethod(methodName) : UndefinedMethod.INSTANCE;

    Object rVal =
        method.isUndefined()
            ? RuntimeHelpers.callMethodMissing(
                context, self, method.getVisibility(), methodName, CallType.SUPER, args, block)
            : method.call(context, self, superClass, methodName, args, block);

    return hasUnusedResult() ? null : rVal;
  }
Beispiel #4
0
 protected static boolean methodMissing(
     CacheEntry entry, CallType callType, String name, IRubyObject caller) {
   DynamicMethod method = entry.method;
   return method.isUndefined()
       || (callType == CallType.NORMAL
           && !name.equals("method_missing")
           && !method.isCallableFrom(caller, callType));
 }
Beispiel #5
0
 public DynamicMethod searchWithCache(RubyClass clazz, int index, String name1) {
   CacheEntry entry = clazz.searchWithCache(name1);
   DynamicMethod method = entry.method;
   if (entry.method == UndefinedMethod.INSTANCE) {
     return RuntimeHelpers.selectMethodMissing(
         clazz, method.getVisibility(), name1, CallType.FUNCTIONAL);
   }
   methodCache[index] = entry;
   return method;
 }
Beispiel #6
0
 private DynamicMethod cacheAndGet(
     ThreadContext context, RubyClass selfType, int index, String methodName) {
   CacheEntry entry = selfType.searchWithCache(methodName);
   DynamicMethod method = entry.method;
   if (method.isUndefined()) {
     return RuntimeHelpers.selectMethodMissing(
         context, selfType, method.getVisibility(), methodName, CallType.FUNCTIONAL);
   }
   methodCache[index] = entry;
   return method;
 }
Beispiel #7
0
 private static IRubyObject callConversionMethod(
     ThreadContext context,
     DynamicMethod method,
     IRubyObject converter,
     String methodName,
     IRubyObject value) {
   if (method.getArity().required() == 2) {
     return method.call(
         context,
         converter,
         converter.getMetaClass(),
         methodName,
         value,
         context.runtime.getNil());
   } else {
     return method.call(context, converter, converter.getMetaClass(), methodName, value);
   }
 }
Beispiel #8
0
  public IRubyObject invoke(
      ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block)
      throws Throwable {
    RubyClass selfClass = pollAndGetClass(context, self);
    SwitchPoint switchPoint = (SwitchPoint) selfClass.getInvalidator().getData();
    CacheEntry entry = selfClass.searchWithCache(methodName);
    DynamicMethod method = entry.method;

    if (methodMissing(entry, caller)) {
      return callMethodMissing(entry, callType, context, self, methodName, args, block);
    }

    MethodHandle mh = getHandle(selfClass, this, method);

    updateInvocationTarget(mh, self, selfClass, entry, switchPoint);

    return method.call(context, self, selfClass, methodName, args, block);
  }
Beispiel #9
0
  MethodHandle getHandle(RubyClass dispatchClass, InvokeSite site, DynamicMethod method)
      throws Throwable {
    boolean blockGiven = signature.lastArgType() == Block.class;

    MethodHandle mh = Bootstrap.buildNativeHandle(site, method, blockGiven);
    if (mh == null) mh = Bootstrap.buildIndyHandle(site, method, method.getImplementationClass());
    if (mh == null) mh = Bootstrap.buildJittedHandle(site, method, blockGiven);
    if (mh == null) mh = Bootstrap.buildGenericHandle(site, method, dispatchClass);

    assert mh != null : "we should have a method handle of some sort by now";

    return mh;
  }
Beispiel #10
0
    private IRubyObject invokeRuby(
        final DynamicMethod method,
        final JavaProxyMethod proxyMethod,
        final RubyClass metaClass,
        final String name,
        final Object[] nargs) {
      final IRubyObject[] newArgs = new IRubyObject[nargs.length];
      for (int i = nargs.length; --i >= 0; ) {
        newArgs[i] = JavaUtil.convertJavaToUsableRubyObject(runtime, nargs[i]);
      }

      final int arity = method.getArity().getValue();

      if (arity < 0 || arity == newArgs.length) {
        final ThreadContext context = runtime.getCurrentContext();
        return method.call(context, self, metaClass, name, newArgs);
      }
      if (proxyMethod.hasSuperImplementation()) {
        final ThreadContext context = runtime.getCurrentContext();
        final RubyClass superClass = metaClass.getSuperClass();
        return Helpers.invokeAs(context, superClass, self, name, newArgs, Block.NULL_BLOCK);
      }
      throw runtime.newArgumentError(newArgs.length, arity);
    }
Beispiel #11
0
  static MethodHandle buildNativeHandle(InvokeSite site, DynamicMethod method, boolean blockGiven) {
    MethodHandle mh = null;
    SmartBinder binder = null;

    if (method.getNativeCall() != null) {

      int nativeArgCount = getNativeArgCount(method, method.getNativeCall());

      DynamicMethod.NativeCall nc = method.getNativeCall();

      if (nc.isJava()) {
        // not supported yet, use DynamicMethod.call
      } else {
        if (nativeArgCount >= 0) { // native methods only support arity 3
          if (nativeArgCount == site.arity) {
            // nothing to do
            binder = SmartBinder.from(lookup(), site.signature);
          } else {
            // arity mismatch...leave null and use DynamicMethod.call below
          }
        } else {
          // varargs
          if (site.arity == -1) {
            // ok, already passing []
            binder = SmartBinder.from(lookup(), site.signature);
          } else if (site.arity == 0) {
            // no args, insert dummy
            binder =
                SmartBinder.from(lookup(), site.signature)
                    .insert(2, "args", IRubyObject.NULL_ARRAY);
          } else {
            // 1 or more args, collect into []
            binder = SmartBinder.from(lookup(), site.signature).collect("args", "arg.*");
          }
        }

        if (binder != null) {

          // clean up non-arguments, ordering, types
          if (!nc.hasContext()) {
            binder = binder.drop("context");
          }

          if (nc.hasBlock() && !blockGiven) {
            binder = binder.append("block", Block.NULL_BLOCK);
          } else if (!nc.hasBlock() && blockGiven) {
            binder = binder.drop("block");
          }

          if (nc.isStatic()) {
            mh =
                binder
                    .permute("context", "self", "arg.*", "block") // filter caller
                    .cast(nc.getNativeReturn(), nc.getNativeSignature())
                    .invokeStaticQuiet(LOOKUP, nc.getNativeTarget(), nc.getNativeName())
                    .handle();
          } else {
            mh =
                binder
                    .permute("self", "context", "arg.*", "block") // filter caller, move self
                    .castArg("self", nc.getNativeTarget())
                    .castVirtual(
                        nc.getNativeReturn(), nc.getNativeTarget(), nc.getNativeSignature())
                    .invokeVirtualQuiet(LOOKUP, nc.getNativeName())
                    .handle();
          }
        }
      }
    }

    return mh;
  }
Beispiel #12
0
  @Override
  public boolean methodMissing(CacheEntry entry, IRubyObject caller) {
    DynamicMethod method = entry.method;

    return method.isUndefined();
  }
Beispiel #13
0
  @JRubyMethod(name = "new", meta = true)
  public static final IRubyObject newMappedType(
      ThreadContext context, IRubyObject klass, IRubyObject converter) {
    if (!converter.respondsTo("native_type")) {
      throw context.runtime.newNoMethodError(
          "converter needs a native_type method", "native_type", converter.getMetaClass());
    }

    DynamicMethod toNativeMethod = converter.getMetaClass().searchMethod("to_native");
    if (toNativeMethod.isUndefined()) {
      throw context.runtime.newNoMethodError(
          "converter needs a to_native method", "to_native", converter.getMetaClass());
    }

    if (toNativeMethod.getArity().required() < 1 || toNativeMethod.getArity().required() > 2) {
      throw context.runtime.newArgumentError("to_native should accept one or two arguments");
    }

    DynamicMethod fromNativeMethod = converter.getMetaClass().searchMethod("from_native");
    if (fromNativeMethod.isUndefined()) {
      throw context.runtime.newNoMethodError(
          "converter needs a from_native method", "from_native", converter.getMetaClass());
    }

    if (fromNativeMethod.getArity().required() < 1 || fromNativeMethod.getArity().required() > 2) {
      throw context.runtime.newArgumentError("from_native should accept one or two arguments");
    }

    Type nativeType;
    try {
      nativeType = (Type) converter.callMethod(context, "native_type");
    } catch (ClassCastException ex) {
      throw context.runtime.newTypeError("native_type did not return instance of FFI::Type");
    }

    boolean isReferenceRequired;
    if (converter.respondsTo("reference_required?")) {
      isReferenceRequired = converter.callMethod(context, "reference_required?").isTrue();

    } else {
      switch (nativeType.nativeType) {
        case BOOL:
        case CHAR:
        case UCHAR:
        case SHORT:
        case USHORT:
        case INT:
        case UINT:
        case LONG:
        case ULONG:
        case LONG_LONG:
        case ULONG_LONG:
        case FLOAT:
        case DOUBLE:
          isReferenceRequired = false;
          break;

        default:
          isReferenceRequired = true;
          break;
      }
    }
    return new MappedType(
        context.runtime,
        (RubyClass) klass,
        nativeType,
        converter,
        toNativeMethod,
        fromNativeMethod,
        isReferenceRequired);
  }
Beispiel #14
0
 public static DynamicMethod populateModuleMethod(RubyModule cls, DynamicMethod javaMethod) {
   DynamicMethod moduleMethod = javaMethod.dup();
   moduleMethod.setImplementationClass(cls.getSingletonClass());
   moduleMethod.setVisibility(Visibility.PUBLIC);
   return moduleMethod;
 }
Beispiel #15
0
 private static String logMethod(DynamicMethod method) {
   return "[#" + method.getSerialNumber() + " " + method.getImplementationClass() + "]";
 }