Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * To change this template, choose Tools | Templates
    * and open the template in the editor.
    */
   package org.jruby.compiler.impl;
   
   import java.io.PrintStream;
   import java.math.BigInteger;
   import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.TreeMap;
  import org.jruby.Ruby;
  import  org.objectweb.asm.Label;
  import  org.objectweb.asm.Type;
  import static org.objectweb.asm.Opcodes.*;
  import static org.jruby.util.CodegenUtils.*;
BaseBodyCompiler encapsulates all common behavior between BodyCompiler implementations.
  
  public abstract class BaseBodyCompiler implements BodyCompiler {
      protected SkinnyMethodAdapter method;
      protected VariableCompiler variableCompiler;
      protected InvocationCompiler invocationCompiler;
      protected int argParamCount;
      protected Label[] currentLoopLabels;
      protected Label scopeStart = new Label();
      protected Label scopeEnd = new Label();
      protected Label redoJump;
      protected boolean inNestedMethod = false;
      protected boolean inRescue = false;
      private int lastLine = -1;
      private int lastPositionLine = -1;
      protected StaticScope scope;
      protected ASTInspector inspector;
      protected String methodName;
      protected String rubyName;
      protected StandardASMCompiler script;
      protected int scopeIndex;
 
     public BaseBodyCompiler(StandardASMCompiler scriptCompilerString methodNameString rubyNameASTInspector inspectorStaticScope scopeint scopeIndex) {
         this. = scriptCompiler;
         this. = scope;
         this. = inspector;
         this. = methodName;
         this. = rubyName;
         this. = getActualArgsCount(scope);
 
          = new SkinnyMethodAdapter(.getClassVisitor(), ACC_PUBLIC | ACC_STATIC, methodNamegetSignature(), nullnull);
 
         createVariableCompiler();
          = OptoFactory.newInvocationCompiler(this);
 
         this. = scopeIndex;
     }
 
     public String getNativeMethodName() {
         return ;
     }
 
     public String getRubyName() {
         return ;
     }
 
     protected boolean shouldUseBoxedArgs(StaticScope scope) {
         return scope.getRestArg() >= 0 || scope.getRestArg() == -2 || scope.getOptionalArgs() > 0 || scope.getRequiredArgs() > 3;
     }
 
     protected int getActualArgsCount(StaticScope scope) {
         if (shouldUseBoxedArgs(scope)) {
             return 1; // use IRubyObject[]
         } else {
             return scope.getRequiredArgs(); // specific arity
         }
     }
 
     protected abstract String getSignature();
 
     protected abstract void createVariableCompiler();
 
     public abstract void beginMethod(CompilerCallback argsStaticScope scope);
 
     public abstract void endBody();
 
     public BodyCompiler chainToMethod(String methodName) {
         BodyCompiler compiler = outline(methodName);
         endBody();
         return compiler;
     }
 
     public void beginChainedMethod() {
         .start();
 
         .invokevirtual(p(ThreadContext.class), "getCurrentScope"sig(DynamicScope.class));
         .astore(getDynamicScopeIndex());
 
         // if more than 4 locals, get the locals array too
         if (.getNumberOfVariables() > 4) {
             .aload(getDynamicScopeIndex());
             .invokevirtual(p(DynamicScope.class), "getValues"sig(IRubyObject[].class));
             .astore(getVarsArrayIndex());
         }
 
         // visit a label to start scoping for local vars in this method
         .label();
     }
 
     public abstract BaseBodyCompiler outline(String methodName);
 
         return ;
     }
 
     public void lineNumber(ISourcePosition position) {
         int thisLine = position.getStartLine();
 
         // No point in updating number if last number was same value.
         if (thisLine != ) {
              = thisLine;
         } else {
             return;
         }
 
         Label line = new Label();
         .label(line);
         .visitLineNumber(thisLine + 1, line);
     }
 
     public int getLastLine() {
         return ;
     }
 
     public void loadThreadContext() {
     }
 
     public void loadSelf() {
     }
 
     protected int getClosureIndex() {
     }
 
     protected int getPreviousExceptionIndex() {
     }
 
     protected int getDynamicScopeIndex() {
     }
 
     protected int getVarsArrayIndex() {
     }
 
     protected int getFirstTempIndex() {
     }
 
     protected int getExceptionIndex() {
     }
 
     protected void loadStaticScope() {
     }
 
     public void loadThis() {
     }
 
     public void loadRuntime() {
         loadThreadContext();
         if (..load()) {
             .invokedynamic("runtime"sig(Ruby.classThreadContext.class), InvokeDynamicSupport.getContextFieldHandle());
         } else {
             .getfield(p(ThreadContext.class), "runtime"ci(Ruby.class));
         }
     }
 
     public void loadBlock() {
         .aload(getClosureIndex());
     }
 
     public void loadNil() {
         loadThreadContext();
         if (..load()) {
             .invokedynamic("nil"sig(IRubyObject.classThreadContext.class), InvokeDynamicSupport.getContextFieldHandle());
         } else {
             .getfield(p(ThreadContext.class), "nil"ci(IRubyObject.class));
         }
     }
 
     public void loadNull() {
         .aconst_null();
     }
 
     public void loadObject() {
         loadRuntime();
 
         invokeRuby("getObject"sig(RubyClass.classparams()));
     }

    
This is for utility methods used by the compiler, to reduce the amount of code generation necessary. All of these live in CompilerHelpers.
 
     public void invokeUtilityMethod(String methodNameString signature) {
         .invokestatic(p(Helpers.class), methodNamesignature);
     }
 
     public void invokeThreadContext(String methodNameString signature) {
         .invokevirtual(.methodNamesignature);
     }
 
     public void invokeRuby(String methodNameString signature) {
         .invokevirtual(.methodNamesignature);
     }
 
     public void invokeIRubyObject(String methodNameString signature) {
         .invokeinterface(.methodNamesignature);
     }
 
     public void consumeCurrentValue() {
         .pop();
     }
 
     public void duplicateCurrentValue() {
         .dup();
     }
 
     public void swapValues() {
         .swap();
     }
 
     public void reverseValues(int count) {
         switch (count) {
         case 2:
             .swap();
             break;
         case 3:
             .dup_x2();
             .pop();
             .swap();
             break;
         case 4:
             .swap();
             .dup2_x2();
             .pop2();
             .swap();
             break;
         case 5:
         case 6:
         case 7:
         case 8:
         case 9:
         case 10:
             // up to ten, stuff into tmp locals, load in reverse order, and assign
             // FIXME: There's probably a slightly smarter way, but is it important?
             int[] tmpLocals = new int[count];
             for (int i = 0; i < counti++) {
                 tmpLocals[i] = getVariableCompiler().grabTempLocal();
                 getVariableCompiler().setTempLocal(tmpLocals[i]);
             }
             for (int i = 0; i < counti++) {
                 getVariableCompiler().getTempLocal(tmpLocals[i]);
                 getVariableCompiler().releaseTempLocal();
             }
             break;
         default:
             throw new NotCompilableException("can't reverse more than ten values on the stack");
         }
     }
 
     public void retrieveSelf() {
         loadSelf();
     }
 
     public void retrieveSelfClass() {
         loadSelf();
         metaclass();
     }
 
         return ;
     }
 
         return ;
     }
 
     public void assignConstantInCurrent(String nameCompilerCallback value) {
         loadStaticScope();
         .ldc(name);
         value.call(this);
         .invokevirtual(p(StaticScope.class), "setConstant"sig(IRubyObject.classparams(String.classIRubyObject.class)));
     }
 
     public void assignConstantInModule(String nameCompilerCallback valueAndModule) {
         loadThreadContext();
         .ldc(name);
         valueAndModule.call(this);
         invokeUtilityMethod("setConstantInModule"sig(IRubyObject.classThreadContext.classString.classIRubyObject.classIRubyObject.class));
     }
 
     public void assignConstantInObject(String namefinal CompilerCallback value) {
         assignConstantInModule(namenew CompilerCallback() {
             public void call(BodyCompiler context) {
                 value.call(context);
                 loadObject();
             }
         });
     }
 
     // TODO: Inefficient, but rarely used (constants in masgn are not common)
     public void mAssignConstantInCurrent(String name) {
         loadStaticScope();
         .ldc(name);
         .dup2_x1();
         .pop2();
         .invokevirtual(p(StaticScope.class), "setConstant"sig(IRubyObject.classparams(String.classIRubyObject.class)));
     }
 
     // TODO: Inefficient, but rarely used (constants in masgn are not common)
     public void mAssignConstantInModule(String name) {
         loadThreadContext();
         .ldc(name);
         .dup2_x2();
         .pop2();
         invokeUtilityMethod("setConstantInModule"sig(IRubyObject.classThreadContext.classString.classIRubyObject.classIRubyObject.class));
     }
 
     // TODO: Inefficient, but rarely used (constants in masgn are not common)
     public void mAssignConstantInObject(String name) {
         loadObject();
         loadThreadContext();
         .ldc(name);
         .dup2_x2();
         .pop2();
         invokeUtilityMethod("setConstantInModule"sig(IRubyObject.classThreadContext.classString.classIRubyObject.classIRubyObject.class));
     }
 
     public void retrieveConstant(String name) {
         .getCacheCompiler().cacheConstant(thisname);
     }
 
     public void retrieveConstantFromModule(String name) {
         invokeUtilityMethod("checkIsModule"sig(RubyModule.classIRubyObject.class));
         .getCacheCompiler().cacheConstantFrom(thisname);
     }
 
     public void retrieveConstantFromObject(String name) {
         loadObject();
         .getCacheCompiler().cacheConstantFrom(thisname);
     }
 
     public void retrieveClassVariable(String name) {
         loadRuntime();
         loadStaticScope();
         loadSelf();
         .ldc(name);
 
         invokeUtilityMethod("fetchClassVariable"sig(IRubyObject.classparams(Ruby.classStaticScope.classIRubyObject.classString.class)));
     }
 
     public void assignClassVariable(String name) {
         loadRuntime();
         .swap();
         loadStaticScope();
         .swap();
         loadSelf();
         .swap();
         .ldc(name);
         .swap();
 
         invokeUtilityMethod("setClassVariable"sig(IRubyObject.classparams(Ruby.classStaticScope.classIRubyObject.classString.classIRubyObject.class)));
     }
 
     public void assignClassVariable(String nameCompilerCallback value) {
         loadRuntime();
         loadStaticScope();
         loadSelf();
         .ldc(name);
         value.call(this);
 
         invokeUtilityMethod("setClassVariable"sig(IRubyObject.classparams(Ruby.classStaticScope.classIRubyObject.classString.classIRubyObject.class)));
     }
 
     // inefficient, but uncommon to see class vars in masgn
     public void declareClassVariable(String name) {
         loadRuntime();
         .swap();
         loadStaticScope();
         .swap();
         loadSelf();
         .swap();
         .ldc(name);
         .swap();
 
         invokeUtilityMethod("declareClassVariable"sig(IRubyObject.classparams(Ruby.classStaticScope.classIRubyObject.classString.classIRubyObject.class)));
     }
 
     public void declareClassVariable(String nameCompilerCallback value) {
         loadRuntime();
         loadStaticScope();
         loadSelf();
         .ldc(name);
         value.call(this);
 
         invokeUtilityMethod("declareClassVariable"sig(IRubyObject.classparams(Ruby.classStaticScope.classIRubyObject.classString.classIRubyObject.class)));
     }
 
     public void createNewFloat(double value) {
         .getCacheCompiler().cacheFloat(thisvalue);
     }
 
     public void createNewFixnum(long value) {
         .getCacheCompiler().cacheFixnum(thisvalue);
     }
 
     public void createNewBignum(BigInteger value) {
         loadRuntime();
         .getCacheCompiler().cacheBigInteger(thisvalue);
         .invokestatic(p(RubyBignum.class), "newBignum"sig(RubyBignum.classparams(Ruby.classBigInteger.class)));
     }
 
     public void createNewString(ArrayCallback callbackint countEncoding encoding) {
         loadRuntime();
         if (encoding == null) {
             .invokestatic(p(RubyString.class), "newStringLight"sig(RubyString.classRuby.classint.class));
         } else {
             .getCacheCompiler().cacheEncoding(thisencoding);
             .invokestatic(p(RubyString.class), "newStringLight"sig(RubyString.classRuby.classint.classEncoding.class));
         }
 
         for (int i = 0; i < counti++) {
             callback.nextValue(thisnulli);
             appendObject(encoding != null);
         }
     }
 
     public void buildNewString(ArrayCallback callbackint countEncoding encoding) {
         loadRuntime();
         if (encoding == null) {
             .invokestatic(p(RubyString.class), "newStringLight"sig(RubyString.classRuby.classint.class));
         } else {
             .getCacheCompiler().cacheEncoding(thisencoding);
             .invokestatic(p(RubyString.class), "newStringLight"sig(RubyString.classRuby.classint.classEncoding.class));
         }
 
         for (int i = 0; i < counti++) {
             callback.nextValue(thisnulli);
         }
     }
 
     public void appendByteList(ByteList valueint codeRangeboolean is19) {
         .getCacheCompiler().cacheByteList(thisvalue);
         if (is19) {
             .ldc(codeRange);
             invokeUtilityMethod("appendByteList19"sig(RubyString.classRubyString.classByteList.classint.class));
         } else {
             invokeUtilityMethod("appendByteList"sig(RubyString.classRubyString.classByteList.class));
         }
     }
 
     public void appendObject(boolean is19) {
         if (is19) {
             .invokevirtual(p(RubyString.class), "append19"sig(RubyString.classparams(IRubyObject.class)));
         } else {
             .invokevirtual(p(RubyString.class), "append"sig(RubyString.classparams(IRubyObject.class)));
         }
     }
 
     public void shortcutAppend(boolean is19) {
         if (is19) {
             invokeUtilityMethod("shortcutAppend"sig(RubyString.classRubyString.classIRubyObject.class));
         } else {
             invokeUtilityMethod("shortcutAppend18"sig(RubyString.classRubyString.classIRubyObject.class));
         }
     }
 
     public void stringToSymbol(boolean is19) {
         if (is19) {
             .invokevirtual(p(RubyString.class), "intern19"sig(RubySymbol.class));
         } else {
             .invokevirtual(p(RubyString.class), "intern"sig(RubySymbol.class));
         }
     }
 
     public void createNewSymbol(ArrayCallback callbackint countEncoding encoding) {
         loadRuntime();
         buildNewString(callbackcountencoding);
         toJavaString();
         invokeRuby("newSymbol"sig(RubySymbol.classparams(String.class)));
     }
 
     public void createNewString(ByteList valueint codeRange) {
         .getCacheCompiler().cacheString(thisvaluecodeRange);
     }
 
     public void createNewSymbol(String name) {
         .getCacheCompiler().cacheSymbol(thisname);
     }
 
     public void createNewArray(boolean lightweight) {
         loadRuntime();
         // put under object array already present
         .swap();
 
         if (lightweight) {
             .invokestatic(p(RubyArray.class), "newArrayNoCopyLight"sig(RubyArray.classparams(Ruby.classIRubyObject[].class)));
         } else {
             .invokestatic(p(RubyArray.class), "newArrayNoCopy"sig(RubyArray.classparams(Ruby.classIRubyObject[].class)));
         }
     }
 
     public void createNewArray(Object[] sourceArrayArrayCallback callbackboolean lightweight) {
         loadRuntime();
 
         buildRubyArray(sourceArraycallbacklightweight);
     }
 
     public void createNewLiteralArray(Object[] sourceArrayArrayCallback callbackboolean lightweight) {
         buildRubyLiteralArray(sourceArraycallbacklightweight);
     }
 
     public void createEmptyArray() {
         loadRuntime();
 
         invokeRuby("newArray"sig(RubyArray.class));
     }
 
     public void createObjectArray(Object[] sourceArrayArrayCallback callback) {
         buildObjectArray(.sourceArraycallback);
     }
 
     private void buildObjectArray(String typeObject[] sourceArrayArrayCallback callback) {
         if (sourceArray.length == 0) {
             .getstatic(p(IRubyObject.class), "NULL_ARRAY"ci(IRubyObject[].class));
         } else if (sourceArray.length <= .) {
             // if we have a specific-arity helper to construct an array for us, use that
             for (int i = 0; i < sourceArray.lengthi++) {
                 callback.nextValue(thissourceArrayi);
             }
             invokeUtilityMethod("constructObjectArray"sig(IRubyObject[].classparams(IRubyObject.classsourceArray.length)));
         } else {
             // brute force construction inline
             .pushInt(sourceArray.length);
             .anewarray(type);
 
             for (int i = 0; i < sourceArray.lengthi++) {
                 .dup();
                 .pushInt(i);
 
                 callback.nextValue(thissourceArrayi);
 
                 .arraystore();
             }
         }
     }
 
     private void buildRubyArray(Object[] sourceArrayArrayCallback callbackboolean light) {
         if (sourceArray.length == 0) {
             .invokestatic(p(RubyArray.class), "newEmptyArray"sig(RubyArray.classRuby.class));
         } else if (sourceArray.length <= .) {
             // if we have a specific-arity helper to construct an array for us, use that
             for (int i = 0; i < sourceArray.lengthi++) {
                 callback.nextValue(thissourceArrayi);
             }
             invokeUtilityMethod("constructRubyArray"sig(RubyArray.classparams(Ruby.classIRubyObject.classsourceArray.length)));
         } else {
             // brute force construction
             
             // construct array all at once
             .pushInt(sourceArray.length);
             invokeUtilityMethod("anewarrayIRubyObjects"sig(IRubyObject[].classint.class));
 
             // iterate over elements, stuffing every ten into array in batches
             int i = 0;
             for (; i < sourceArray.lengthi++) {
                 callback.nextValue(thissourceArrayi);
 
                 if ((i + 1) % 10 == 0) {
                     .pushInt(i - 9);
                     invokeUtilityMethod("aastoreIRubyObjects"sig(IRubyObject[].classparams(IRubyObject[].classIRubyObject.class, 10, int.class)));
                 }
             }
             
             // stuff remaining into array
             int remain = i % 10;
             if (remain != 0) {
                 .pushInt(i - remain);
                 invokeUtilityMethod("aastoreIRubyObjects"sig(IRubyObject[].classparams(IRubyObject[].classIRubyObject.classremainint.class)));
             }
             
             // construct RubyArray wrapper
             if (light) {
                 .invokestatic(p(RubyArray.class), "newArrayNoCopyLight"sig(RubyArray.classRuby.classIRubyObject[].class));
             } else {
                 .invokestatic(p(RubyArray.class), "newArrayNoCopy"sig(RubyArray.classRuby.classIRubyObject[].class));
             }
         }
     }
 
     private void buildRubyLiteralArray(Object[] sourceArrayArrayCallback callbackboolean light) {
         if (sourceArray.length < 100) {
             // don't chunk arrays smaller than 100 elements
             loadRuntime();
             buildRubyArray(sourceArraycallbacklight);
         } else {
             // populate the array in a separate series of methods
             SkinnyMethodAdapter oldMethod = ;
 
             // prepare the first builder in the chain
             String newMethodName = "array_builder_" + .getAndIncrementMethodIndex() + "";
              = new SkinnyMethodAdapter(
                     .getClassVisitor(),
                     ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC,
                     newMethodName,
                     sig(IRubyObject[].class"L" + .getClassname() + ";"ThreadContext.classIRubyObject[].class),
                     null,
                     null);
             .start();
 
             for (int i = 0; i < sourceArray.lengthi++) {
                 // for every hundred elements, chain to the next call
                 if ((i + 1) % 100 == 0) {
                     String nextName = "array_builder_" + .getAndIncrementMethodIndex() + "";
 
                     .aloadMany(0, 1, 2);
                     .invokestatic(.getClassname(), nextName,
                             sig(IRubyObject[].class"L" + .getClassname() + ";"ThreadContext.classIRubyObject[].class));
                     .areturn();
                     .end();
                     
                      = new SkinnyMethodAdapter(
                             .getClassVisitor(),
                             ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC,
                             nextName,
                             sig(IRubyObject[].class"L" + .getClassname() + ";"ThreadContext.classIRubyObject[].class),
                             null,
                             null);
                     .start();
                 }
 
                 .aload(2);
                 .pushInt(i);
 
                 callback.nextValue(thissourceArrayi);
 
                 .arraystore();
             }
 
             // close out the last method in the chain
             .aload(2);
             .areturn();
             .end();
 
             // restore original method, prepare runtime and array, and invoke the chain
              = oldMethod;
 
             loadRuntime(); // for newArray* call below
 
             // chain invoke
             .aload(.);
             .pushInt(sourceArray.length);
             .anewarray(p(IRubyObject.class));
             .invokestatic(.getClassname(), newMethodName,
                     sig(IRubyObject[].class"L" + .getClassname() + ";"ThreadContext.classIRubyObject[].class));
 
             // array construct
             if (light) {
                 .invokestatic(p(RubyArray.class), "newArrayNoCopyLight"sig(RubyArray.classRuby.classIRubyObject[].class));
             } else {
                 .invokestatic(p(RubyArray.class), "newArrayNoCopy"sig(RubyArray.classRuby.classIRubyObject[].class));
             }
         }
     }
 
     public void createEmptyHash() {
         loadRuntime();
 
         .invokestatic(p(RubyHash.class), "newHash"sig(RubyHash.classparams(Ruby.class)));
     }
 
     public void createNewHash(Object elementsArrayCallback callbackint keyCount) {
         if (keyCount <= 10) {
             createNewHashCommon(elementscallbackkeyCount"constructSmallHash""fastASetSmallCheckString");
         } else {
             createNewHashCommon(elementscallbackkeyCount"constructHash""fastASetCheckString");
         }
     }
 
     public void createNewLiteralHash(Object elementsArrayCallback callbackint keyCount) {
         if (keyCount <= 10) {
             createNewLiteralHashCommon(elementscallbackkeyCount"constructSmallHash""fastASetSmallCheckString");
         } else {
             createNewLiteralHashCommon(elementscallbackkeyCount"constructHash""fastASetCheckString");
         }
     }
     
     public void createNewHash19(Object elementsArrayCallback callbackint keyCount) {
         if (keyCount <= 10) {
             createNewHashCommon(elementscallbackkeyCount"constructSmallHash19""fastASetSmallCheckString19");
         } else {
             createNewHashCommon(elementscallbackkeyCount"constructHash19""fastASetCheckString19");
         }
     }
     
     private void createNewHashCommon(Object elementsArrayCallback callbackint keyCount,
             String constructorNameString methodName) {
         loadRuntime();
 
         // use specific-arity for as much as possible
         int i = 0;
         for (; i < keyCount && i < .i++) {
             callback.nextValue(thiselementsi);
         }
 
         invokeUtilityMethod(constructorNamesig(RubyHash.classparams(Ruby.classIRubyObject.classi * 2)));
 
         for (; i < keyCounti++) {
             .dup();
             loadRuntime();
             callback.nextValue(thiselementsi);
             .invokevirtual(p(RubyHash.class), methodNamesig(void.classparams(Ruby.classIRubyObject.classIRubyObject.class)));
         }
     }
 
     private void createNewLiteralHashCommon(Object elementsArrayCallback callbackint keyCount,
             String constructorNameString methodName) {
         if (keyCount < 50) {
             // small hash, use standard construction
             createNewHashCommon(elementscallbackkeyCountconstructorNamemethodName);
         } else {
             // populate the hash in a separate series of methods
             SkinnyMethodAdapter oldMethod = ;
 
             // prepare the first builder in the chain
             String builderMethod = "hash_builder_" + .getAndIncrementMethodIndex() + "";
              = new SkinnyMethodAdapter(
                     .getClassVisitor(),
                     ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC,
                     builderMethod,
                     sig(RubyHash.class"L" + .getClassname() + ";"ThreadContext.classRubyHash.class),
                     null,
                     null);
             .start();
 
             for (int i = 0; i < keyCounti++) {
                 // for every hundred keys, chain to the next call
                 if ((i + 1) % 100 == 0) {
                     String nextName = "hash_builder_" + .getAndIncrementMethodIndex() + "";
 
                     .aloadMany(0, 1, 2);
                     .invokestatic(.getClassname(), nextName,
                             sig(RubyHash.class"L" + .getClassname() + ";"ThreadContext.classRubyHash.class));
                     .areturn();
                     .end();
 
                      = new SkinnyMethodAdapter(
                             .getClassVisitor(),
                             ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC,
                             nextName,
                             sig(RubyHash.class"L" + .getClassname() + ";"ThreadContext.classRubyHash.class),
                             null,
                             null);
                     .start();
                 }
 
                 .aload(2);
                 loadRuntime();
                 callback.nextValue(thiselementsi);
                 .invokevirtual(p(RubyHash.class), methodNamesig(void.classparams(Ruby.classIRubyObject.classIRubyObject.class)));
             }
 
             // close out the last method in the chain
             .aload(2);
             .areturn();
             .end();
 
             // restore original method
              = oldMethod;
 
             // chain invoke
             .aload(.);
             loadRuntime();
             .invokestatic(p(RubyHash.class), "newHash"sig(RubyHash.classRuby.class));
             .invokestatic(.getClassname(), builderMethod,
                     sig(RubyHash.class"L" + .getClassname() + ";"ThreadContext.classRubyHash.class));
         }
     }
 
     public void createNewRange(CompilerCallback beginEndCallbackboolean isExclusive) {
         loadRuntime();
         loadThreadContext();
         beginEndCallback.call(this);
 
         if (isExclusive) {
             .invokestatic(p(RubyRange.class), "newExclusiveRange"sig(RubyRange.classparams(Ruby.classThreadContext.classIRubyObject.classIRubyObject.class)));
         } else {
             .invokestatic(p(RubyRange.class), "newInclusiveRange"sig(RubyRange.classparams(Ruby.classThreadContext.classIRubyObject.classIRubyObject.class)));
         }
     }
 
     public void createNewLambda(CompilerCallback closure) {
         loadThreadContext();
         closure.call(this);
         loadSelf();
 
         invokeUtilityMethod("newLiteralLambda"sig(RubyProc.classThreadContext.classBlock.classIRubyObject.class));
     }

    
Invoke IRubyObject.isTrue
 
     public void isTrue() {
         invokeIRubyObject("isTrue"sig(.));
     }
 
     public void performBooleanBranch(BranchCallback trueBranchBranchCallback falseBranch) {
         // call isTrue on the result
         isTrue();
         
         performBooleanBranch2(trueBranchfalseBranch);
     }
 
     public void