예제 #1
0
 public static void installBytecode(MethodVisitor method, String classname) {
   SkinnyMethodAdapter mv = new SkinnyMethodAdapter(method);
   mv.ldc(c(classname));
   mv.invokestatic(p(Class.class), "forName", sig(Class.class, params(String.class)));
   mv.invokestatic(
       p(InvokeDynamicSupport.class), "registerBootstrap", sig(void.class, Class.class));
 }
  public String getNewField(String type, String name, Object init) {
    ClassVisitor cv = getClassVisitor();

    // declare the field
    cv.visitField(ACC_PRIVATE, name, type, null, null).visitEnd();

    if (init != null) {
      initMethod.aload(THIS);
      initMethod.ldc(init);
      initMethod.putfield(getClassname(), name, type);
    }

    return name;
  }
  public String getNewConstant(String type, String name_prefix, Object init) {
    ClassVisitor cv = getClassVisitor();

    String realName = getNewConstantName();

    // declare the field
    cv.visitField(ACC_PRIVATE, realName, type, null, null).visitEnd();

    if (init != null) {
      initMethod.aload(THIS);
      initMethod.ldc(init);
      initMethod.putfield(getClassname(), realName, type);
    }

    return realName;
  }
  public void startScript(StaticScope scope) {
    classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

    // Create the class with the appropriate class name and source file
    classWriter.visit(
        javaVersion == null ? RubyInstanceConfig.JAVA_VERSION : javaVersion,
        ACC_PUBLIC + ACC_SUPER,
        getClassname(),
        null,
        p(AbstractScript.class),
        null);

    // add setPosition impl, which stores filename as constant to speed updates
    SkinnyMethodAdapter method =
        new SkinnyMethodAdapter(
            getClassVisitor(),
            ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC,
            "setPosition",
            sig(Void.TYPE, params(ThreadContext.class, int.class)),
            null,
            null);
    method.start();

    method.aload(0); // thread context
    method.ldc(sourcename);
    method.iload(1); // line number
    method.invokevirtual(
        p(ThreadContext.class), "setFileAndLine", sig(void.class, String.class, int.class));
    method.voidreturn();
    method.end();

    topLevelScope = scope;

    beginInit();

    cacheCompiler = OptoFactory.newCacheCompiler(this);

    // This code was originally used to provide debugging info using JSR-45
    // "SMAP" format. However, it breaks using normal Java traces to
    // generate Ruby traces, since the original path is lost. Reverting
    // to full path for now.
    //        String sourceNoPath;
    //        if (sourcename.indexOf("/") >= 0) {
    //            String[] pathElements = sourcename.split("/");
    //            sourceNoPath = pathElements[pathElements.length - 1];
    //        } else if (sourcename.indexOf("\\") >= 0) {
    //            String[] pathElements = sourcename.split("\\\\");
    //            sourceNoPath = pathElements[pathElements.length - 1];
    //        } else {
    //            sourceNoPath = sourcename;
    //        }

    final File sourceFile = new File(getSourcename());
    // Revert to using original sourcename here, so that jitted traces match
    // interpreted traces.
    classWriter.visitSource(sourcename, sourceFile.getAbsolutePath());
  }
  private void beginClassInit() {
    ClassVisitor cv = getClassVisitor();

    clinitMethod =
        new SkinnyMethodAdapter(
            cv, ACC_PUBLIC | ACC_STATIC, "<clinit>", sig(Void.TYPE), null, null);
    clinitMethod.start();
  }
  private void beginInit() {
    ClassVisitor cv = getClassVisitor();

    initMethod = new SkinnyMethodAdapter(cv, ACC_PUBLIC, "<init>", sig(Void.TYPE), null, null);
    initMethod.start();
    initMethod.aload(THIS);
    initMethod.invokespecial(p(AbstractScript.class), "<init>", sig(Void.TYPE));

    // JRUBY-3014: make __FILE__ dynamically determined at load time, but
    // we provide a reasonable default here
    initMethod.aload(THIS);
    initMethod.ldc(getSourcename());
    initMethod.putfield(getClassname(), "filename", ci(String.class));
  }
  public BodyCompiler startFileMethod(
      CompilerCallback args, StaticScope scope, ASTInspector inspector) {
    MethodBodyCompiler methodCompiler =
        new MethodBodyCompiler(this, "__file__", "__file__", inspector, scope, 0);

    // allocate the 0 StaticScope slot in the cache
    int reservedIndex = cacheCompiler.reserveStaticScope();
    assert reservedIndex == 0 : "__file__ scope index was not zero";

    methodCompiler.beginMethod(args, scope);

    // boxed arg list __file__
    SkinnyMethodAdapter method =
        new SkinnyMethodAdapter(
            getClassVisitor(), ACC_PUBLIC, "__file__", getMethodSignature(4), null, null);
    method.start();

    // invoke static __file__
    method.aload(THIS);
    method.aload(THREADCONTEXT_INDEX);
    method.aload(SELF_INDEX);
    method.aload(ARGS_INDEX);
    method.aload(ARGS_INDEX + 1); // block
    method.invokestatic(getClassname(), "__file__", getStaticMethodSignature(getClassname(), 4));

    method.areturn();
    method.end();

    if (methodCompiler.isSpecificArity()) {
      // exact arg list __file__
      method =
          new SkinnyMethodAdapter(
              getClassVisitor(),
              ACC_PUBLIC,
              "__file__",
              getMethodSignature(scope.getRequiredArgs()),
              null,
              null);
      method.start();

      // invoke static __file__
      method.aload(THIS);
      method.aload(THREADCONTEXT_INDEX);
      method.aload(SELF_INDEX);
      for (int i = 0; i < scope.getRequiredArgs(); i++) {
        method.aload(ARGS_INDEX + i);
      }
      method.aload(ARGS_INDEX + scope.getRequiredArgs()); // block
      method.invokestatic(
          getClassname(),
          "__file__",
          getStaticMethodSignature(getClassname(), scope.getRequiredArgs()));

      method.areturn();
      method.end();
    }

    return methodCompiler;
  }
 private void endClassInit() {
   if (clinitMethod != null) {
     clinitMethod.voidreturn();
     clinitMethod.end();
   }
 }
 private void endInit() {
   initMethod.voidreturn();
   initMethod.end();
 }
예제 #10
0
  public void endScript(boolean generateLoad, boolean generateMain) {
    // add Script#run impl, used for running this script with a specified threadcontext and self
    // root method of a script is always in __file__ method
    String methodName = "__file__";

    String loadSig = sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, boolean.class);

    if (generateLoad || generateMain) {
      // the load method is used for loading as a top-level script, and prepares appropriate scoping
      // around the code
      SkinnyMethodAdapter method =
          new SkinnyMethodAdapter(getClassVisitor(), ACC_PUBLIC, "load", loadSig, null, null);
      method.start();

      // invoke __file__ with threadcontext, self, args (null), and block (null)
      Label tryBegin = new Label();
      Label tryFinally = new Label();

      method.label(tryBegin);
      method.aload(THREADCONTEXT_INDEX);
      String scopeNames = Helpers.encodeScope(topLevelScope);
      method.ldc(scopeNames);
      method.iload(SELF_INDEX + 1);
      method.invokestatic(
          p(Helpers.class),
          "preLoad",
          sig(StaticScope.class, ThreadContext.class, String.class, boolean.class));

      // store root scope
      method.aload(THIS);
      method.swap();
      method.invokevirtual(
          p(AbstractScript.class), "setRootScope", sig(void.class, StaticScope.class));

      method.aload(THIS);
      method.aload(THREADCONTEXT_INDEX);
      method.aload(SELF_INDEX);
      method.getstatic(p(IRubyObject.class), "NULL_ARRAY", ci(IRubyObject[].class));
      method.getstatic(p(Block.class), "NULL_BLOCK", ci(Block.class));

      method.invokestatic(getClassname(), methodName, getStaticMethodSignature(getClassname(), 4));
      method.aload(THREADCONTEXT_INDEX);
      method.invokestatic(p(Helpers.class), "postLoad", sig(void.class, ThreadContext.class));
      method.areturn();

      method.label(tryFinally);
      method.aload(THREADCONTEXT_INDEX);
      method.invokestatic(p(Helpers.class), "postLoad", sig(void.class, ThreadContext.class));
      method.athrow();

      method.trycatch(tryBegin, tryFinally, tryFinally, null);

      method.end();
    }

    if (generateMain) {
      // add main impl, used for detached or command-line execution of this script with a new
      // runtime
      // root method of a script is always in stub0, method0
      SkinnyMethodAdapter method =
          new SkinnyMethodAdapter(
              getClassVisitor(),
              ACC_PUBLIC | ACC_STATIC,
              "main",
              sig(Void.TYPE, params(String[].class)),
              null,
              null);
      method.start();

      // init script filename to simple class name in case we don't assign it (null ClassLoader)
      method.ldc(getClassname().replaceAll("\\\\.", "/"));
      method.astore(1);

      // new instance to invoke run against
      method.newobj(getClassname());
      method.dup();
      method.invokespecial(getClassname(), "<init>", sig(Void.TYPE));

      // guard against null classloader
      method.ldc(Type.getType("L" + getClassname() + ";"));
      method.invokevirtual(p(Class.class), "getClassLoader", sig(ClassLoader.class));
      Label skip = new Label();
      method.ifnull(skip);

      // set filename for the loaded script class (JRUBY-4825)
      method.dup();
      method.ldc(Type.getType("L" + getClassname() + ";"));
      method.invokevirtual(p(Class.class), "getClassLoader", sig(ClassLoader.class));
      method.ldc(getClassname() + ".class");
      method.invokevirtual(p(ClassLoader.class), "getResource", sig(URL.class, String.class));
      method.invokevirtual(p(Object.class), "toString", sig(String.class));
      method.astore(1);
      method.aload(1);
      method.invokevirtual(p(AbstractScript.class), "setFilename", sig(void.class, String.class));

      // ifnull ClassLoader
      method.label(skip);

      // instance config for the script run
      method.newobj(p(RubyInstanceConfig.class));
      method.dup();
      method.invokespecial(p(RubyInstanceConfig.class), "<init>", "()V");

      // set argv from main's args
      method.dup();
      method.aload(0);
      method.invokevirtual(p(RubyInstanceConfig.class), "setArgv", sig(void.class, String[].class));

      // set script filename ($0)
      method.dup();
      method.aload(1);
      method.invokevirtual(
          p(RubyInstanceConfig.class), "setScriptFileName", sig(void.class, String.class));

      // invoke run with threadcontext and topself
      method.invokestatic(p(Ruby.class), "newInstance", sig(Ruby.class, RubyInstanceConfig.class));
      method.dup();

      method.invokevirtual(RUBY, "getCurrentContext", sig(ThreadContext.class));
      method.swap();
      method.invokevirtual(RUBY, "getTopSelf", sig(IRubyObject.class));
      method.ldc(false);

      method.invokevirtual(getClassname(), "load", loadSig);
      method.voidreturn();
      method.end();
    }

    getCacheCompiler().finish();

    endInit();
    endClassInit();
  }
예제 #11
0
  public CompiledBlockCallback19 compileBlock19(
      ThreadContext context, StandardASMCompiler asmCompiler, final IterNode iterNode) {
    final ASTCompiler19 astCompiler = new ASTCompiler19();
    final StaticScope scope = iterNode.getScope();

    asmCompiler.startScript(scope);

    final ArgsNode argsNode = (ArgsNode) iterNode.getVarNode();

    // create the closure class and instantiate it
    final CompilerCallback closureBody =
        new CompilerCallback() {
          public void call(BodyCompiler context) {
            if (iterNode.getBodyNode() != null) {
              astCompiler.compile(iterNode.getBodyNode(), context, true);
            } else {
              context.loadNil();
            }
          }
        };

    // create the closure class and instantiate it
    final CompilerCallback closureArgs =
        new CompilerCallback() {
          public void call(BodyCompiler context) {
            // FIXME: This is temporary since the variable compilers assume we want
            // args already on stack for assignment. We just pop and continue with
            // 1.9 args logic.
            context.consumeCurrentValue(); // args value
            context.consumeCurrentValue(); // passed block
            if (iterNode.getVarNode() != null) {
              if (iterNode instanceof LambdaNode) {
                final int required = argsNode.getRequiredArgsCount();
                final int opt = argsNode.getOptionalArgsCount();
                final int rest = argsNode.getRestArg();
                context.getVariableCompiler().checkMethodArity(required, opt, rest);
                astCompiler.compileMethodArgs(argsNode, context, true);
              } else {
                astCompiler.compileMethodArgs(argsNode, context, true);
              }
            }
          }
        };

    ASTInspector inspector = new ASTInspector();
    inspector.inspect(iterNode.getBodyNode());
    inspector.inspect(iterNode.getVarNode());

    NodeType argsNodeId = BlockBody.getArgumentTypeWackyHack(iterNode);

    int scopeIndex = asmCompiler.getCacheCompiler().reserveStaticScope();
    ChildScopedBodyCompiler closureCompiler =
        new ChildScopedBodyCompiler19(
            asmCompiler, "__file__", asmCompiler.getClassname(), inspector, scope, scopeIndex);

    closureCompiler.beginMethod(argsNodeId == null ? null : closureArgs, scope);

    closureBody.call(closureCompiler);

    closureCompiler.endBody();

    // __file__ method to call static version
    SkinnyMethodAdapter method =
        new SkinnyMethodAdapter(
            asmCompiler.getClassVisitor(),
            ACC_PUBLIC,
            "__file__",
            getMethodSignature(4),
            null,
            null);
    method.start();

    // invoke static __file__
    method.aload(THIS);
    method.aload(THREADCONTEXT_INDEX);
    method.aload(SELF_INDEX);
    method.aload(ARGS_INDEX);
    method.aload(ARGS_INDEX + 1); // block
    method.invokestatic(
        asmCompiler.getClassname(),
        "__file__",
        asmCompiler.getStaticMethodSignature(asmCompiler.getClassname(), 4));

    method.areturn();
    method.end();

    asmCompiler.endScript(false, false);

    byte[] bytes = asmCompiler.getClassByteArray();
    Class blockClass =
        new JRubyClassLoader(context.runtime.getJRubyClassLoader())
            .defineClass(asmCompiler.getClassname(), bytes);
    try {
      final AbstractScript script = (AbstractScript) blockClass.newInstance();
      script.setRootScope(scope);

      return new CompiledBlockCallback19() {

        @Override
        public IRubyObject call(
            ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
          return script.__file__(context, self, args, block);
        }

        @Override
        public String getFile() {
          return iterNode.getPosition().getFile();
        }

        @Override
        public int getLine() {
          return iterNode.getPosition().getLine();
        }
      };
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
예제 #12
0
  public CompiledBlockCallback compileBlock(
      ThreadContext context, StandardASMCompiler asmCompiler, final IterNode iterNode) {
    final ASTCompiler astCompiler = new ASTCompiler();
    final StaticScope scope = iterNode.getScope();

    asmCompiler.startScript(scope);

    // create the closure class and instantiate it
    final CompilerCallback closureBody =
        new CompilerCallback() {

          public void call(BodyCompiler context) {
            if (iterNode.getBodyNode() != null) {
              astCompiler.compile(iterNode.getBodyNode(), context, true);
            } else {
              context.loadNil();
            }
          }
        };

    // create the closure class and instantiate it
    final CompilerCallback closureArgs =
        new CompilerCallback() {
          public void call(BodyCompiler context) {
            if (iterNode.getVarNode() != null) {
              astCompiler.compileAssignment(iterNode.getVarNode(), context);
            } else {
              context.consumeCurrentValue();
            }

            if (iterNode.getBlockVarNode() != null) {
              astCompiler.compileAssignment(iterNode.getBlockVarNode(), context);
            } else {
              context.consumeCurrentValue();
            }
          }
        };

    ASTInspector inspector = new ASTInspector();
    inspector.inspect(iterNode.getBodyNode());
    inspector.inspect(iterNode.getVarNode());

    int scopeIndex = asmCompiler.getCacheCompiler().reserveStaticScope();
    ChildScopedBodyCompiler closureCompiler =
        new ChildScopedBodyCompiler(
            asmCompiler, "__file__", asmCompiler.getClassname(), inspector, scope, scopeIndex);

    closureCompiler.beginMethod(closureArgs, scope);

    closureBody.call(closureCompiler);

    closureCompiler.endBody();

    // __file__ method with [] args; no-op
    SkinnyMethodAdapter method =
        new SkinnyMethodAdapter(
            asmCompiler.getClassVisitor(),
            ACC_PUBLIC,
            "__file__",
            getMethodSignature(4),
            null,
            null);
    method.start();

    method.aload(SELF_INDEX);
    method.areturn();
    method.end();

    // __file__ method to call static version
    method =
        new SkinnyMethodAdapter(
            asmCompiler.getClassVisitor(),
            ACC_PUBLIC,
            "__file__",
            getMethodSignature(1),
            null,
            null);
    method.start();

    // invoke static __file__
    method.aload(THIS);
    method.aload(THREADCONTEXT_INDEX);
    method.aload(SELF_INDEX);
    method.aload(ARGS_INDEX);
    method.aload(ARGS_INDEX + 1); // block
    method.invokestatic(
        asmCompiler.getClassname(),
        "__file__",
        getStaticMethodSignature(asmCompiler.getClassname(), 1));

    method.areturn();
    method.end();

    asmCompiler.endScript(false, false);

    byte[] bytes = asmCompiler.getClassByteArray();
    Class blockClass =
        new JRubyClassLoader(context.runtime.getJRubyClassLoader())
            .defineClass(asmCompiler.getClassname(), bytes);
    try {
      final AbstractScript script = (AbstractScript) blockClass.newInstance();
      script.setRootScope(scope);

      return new CompiledBlockCallback() {

        @Override
        public IRubyObject call(
            ThreadContext context, IRubyObject self, IRubyObject args, Block block) {
          return script.__file__(context, self, args, block);
        }

        @Override
        public String getFile() {
          return "blah";
        }

        @Override
        public int getLine() {
          return -1;
        }
      };
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }