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(); }
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(); }
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); } }
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); } }