Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   ***** BEGIN LICENSE BLOCK *****
   * Version: EPL 1.0/GPL 2.0/LGPL 2.1
   *
   * The contents of this file are subject to the Eclipse Public
   * License Version 1.0 (the "License"); you may not use this file
   * except in compliance with the License. You may obtain a copy of
   * the License at http://www.eclipse.org/legal/epl-v10.html
   *
  * Software distributed under the License is distributed on an "AS
  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  * implied. See the License for the specific language governing
  * rights and limitations under the License.
  * 
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the EPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the EPL, the GPL or the LGPL.
  ***** END LICENSE BLOCK *****/
 
 package org.jruby.compiler.impl;
 
 import static org.jruby.util.CodegenUtils.*;
 import  org.objectweb.asm.Label;
 import  org.objectweb.asm.Opcodes;

Author(s):
headius
 
 public class StandardInvocationCompiler implements InvocationCompiler {
     protected BaseBodyCompiler methodCompiler;
     protected SkinnyMethodAdapter method;
 
     public StandardInvocationCompiler(BaseBodyCompiler methodCompilerSkinnyMethodAdapter method) {
         this. = methodCompiler;
         this. = method;
     }
 
     public SkinnyMethodAdapter getMethodAdapter() {
         return this.;
     }
 
     public void setMethodAdapter(SkinnyMethodAdapter sma) {
         this. = sma;
     }
 
     public void invokeAttrAssignMasgn(String nameCompilerCallback receiverCallbackfinal ArgumentsCallback argsCallbackboolean selfCall) {
         // value is already on stack, save it for later
         final int temp = .getVariableCompiler().grabTempLocal();
         
         ArgumentsCallback newArgumentsCallback = new ArgumentsCallback() {
             public int getArity() {
                 return (argsCallback == null) ? 1 : argsCallback.getArity() + 1;
             }
 
             public void call(BodyCompiler context) {
                 if (argsCallback != nullargsCallback.call(context);
                 .getVariableCompiler().getTempLocal(temp);
             }
         };
         
         invokeAttrAssign(namereceiverCallbacknewArgumentsCallbackselfCallfalse);
     }
 
     public void invokeAttrAssign(String nameCompilerCallback receiverCallbackArgumentsCallback argsCallbackboolean isSelfboolean expr) {
 
         .loadThreadContext(); // [adapter, tc]
 
         // for visibility checking without requiring frame self
         // TODO: don't bother passing when fcall or vcall, and adjust callsite appropriately
         .loadSelf();
         
         if (receiverCallback != null) {
            receiverCallback.call();
        } else {
            .loadSelf();
        }
        
        String signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.class));
        argsCallback.call();
        int tmp = .getVariableCompiler().grabTempLocal();
        
        switch (argsCallback.getArity()) {
        case 1:
            signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.class));
            if (expr) {
                .dup();
                .astore(tmp);
            }
            break;
        case 2:
            signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.class));
            if (expr) {
                .dup();
                .astore(tmp);
            }
            break;
        case 3:
            signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.class));
            if (expr) {
                .dup();
                .astore(tmp);
            }
            break;
        default:
            signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].class));
            if (expr) {
                .dup();
                .invokeUtilityMethod("lastElement"sig(IRubyObject.classIRubyObject[].class));
                .astore(tmp);
            }
        }
        
        // invoke
        .invokevirtual(p(CallSite.class), "call"signature);
        
        // restore incoming value if expression
        .pop();
        if (expr.aload(tmp);
    }
    
    public void opElementAsgnWithOr(CompilerCallback receiverArgumentsCallback argsCompilerCallback valueCallback) {
        // get call site and thread context
        .loadSelf();
        
        // evaluate and save receiver and args
        receiver.call();
        args.call();
        .dup2();
        int argsLocal = .getVariableCompiler().grabTempLocal();
        .getVariableCompiler().setTempLocal(argsLocal);
        int receiverLocal = .getVariableCompiler().grabTempLocal();
        .getVariableCompiler().setTempLocal(receiverLocal);
        
        // invoke
        switch (args.getArity()) {
        case 1:
            .invokevirtual(p(CallSite.class), "call"sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.class));
            break;
        default:
            .invokevirtual(p(CallSite.class), "call"sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].class));
        }
        
        // check if it's true, ending if so
        .dup();
        .invokeIRubyObject("isTrue"sig(boolean.class));
        Label done = new Label();
        .ifne(done);
        
        // not true, eval value and assign
        .pop();
        // thread context, receiver and original args
        .loadSelf();
        .getVariableCompiler().getTempLocal(receiverLocal);
        .getVariableCompiler().getTempLocal(argsLocal);
        
        // eval value for assignment
        valueCallback.call();
        
        // call site
        
        // depending on size of original args, call appropriate utility method
        switch (args.getArity()) {
        case 0:
            throw new NotCompilableException("Op Element Asgn with zero-arity args");
        case 1:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoOneArg"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classCallSite.class));
            break;
        case 2:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoTwoArgs"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classIRubyObject.classCallSite.class));
            break;
        case 3:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoThreeArgs"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classIRubyObject.classCallSite.class));
            break;
        default:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoNArgs"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classIRubyObject.classCallSite.class));
            break;
        }
        
        .label(done);
        
    }
    
    public void opElementAsgnWithAnd(CompilerCallback receiverArgumentsCallback argsCompilerCallback valueCallback) {
        // get call site and thread context
        .loadSelf();
        
        // evaluate and save receiver and args
        receiver.call();
        args.call();
        .dup2();
        int argsLocal = .getVariableCompiler().grabTempLocal();
        .getVariableCompiler().setTempLocal(argsLocal);
        int receiverLocal = .getVariableCompiler().grabTempLocal();
        .getVariableCompiler().setTempLocal(receiverLocal);
        
        // invoke
        switch (args.getArity()) {
        case 1:
            .invokevirtual(p(CallSite.class), "call"sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.class));
            break;
        default:
            .invokevirtual(p(CallSite.class), "call"sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].class));
        }
        
        // check if it's true, ending if not
        .dup();
        .invokeIRubyObject("isTrue"sig(boolean.class));
        Label done = new Label();
        .ifeq(done);
        
        // not true, eval value and assign
        .pop();
        // thread context, receiver and original args
        .loadSelf();
        .getVariableCompiler().getTempLocal(receiverLocal);
        .getVariableCompiler().getTempLocal(argsLocal);
        
        // eval value and save it
        valueCallback.call();
        
        // call site
        
        // depending on size of original args, call appropriate utility method
        switch (args.getArity()) {
        case 0:
            throw new NotCompilableException("Op Element Asgn with zero-arity args");
        case 1:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoOneArg"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classCallSite.class));
            break;
        case 2:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoTwoArgs"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classIRubyObject.classCallSite.class));
            break;
        case 3:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoThreeArgs"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classIRubyObject.classCallSite.class));
            break;
        default:
            .invokeUtilityMethod("opElementAsgnWithOrPartTwoNArgs"
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classIRubyObject.classCallSite.class));
            break;
        }
        
        .label(done);
        
    }
    
    public void opElementAsgnWithMethod(CompilerCallback receiverArgumentsCallback argsCompilerCallback valueCallbackString operator) {
        .loadSelf();
        receiver.call();
        args.call();
        valueCallback.call(); // receiver, args, result, value
        
        switch (args.getArity()) {
        case 0:
            .invokeUtilityMethod("opElementAsgnWithMethod",
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classCallSite.classCallSite.classCallSite.class));
            break;
        case 1:
            .invokeUtilityMethod("opElementAsgnWithMethod",
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classCallSite.classCallSite.classCallSite.class));
            break;
        case 2:
            .invokeUtilityMethod("opElementAsgnWithMethod",
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classCallSite.classCallSite.classCallSite.class));
            break;
        case 3:
            .invokeUtilityMethod("opElementAsgnWithMethod",
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classCallSite.classCallSite.classCallSite.class));
            break;
        default:
            .invokeUtilityMethod("opElementAsgnWithMethod",
                    sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classIRubyObject.classCallSite.classCallSite.classCallSite.class));
            break;
        }
    }
    public void invokeBinaryFixnumRHS(String nameCompilerCallback receiverCallbacklong fixnum) {
        .loadThreadContext(); // [adapter, tc]
        // for visibility checking without requiring frame self
        // TODO: don't bother passing when fcall or vcall, and adjust callsite appropriately
        .loadSelf();
        if (receiverCallback != null) {
            receiverCallback.call();
        } else {
            .loadSelf();
        }
        .ldc(fixnum);
        String signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classlong.class));
        String callSiteMethod = "call";
        .invokevirtual(p(CallSite.class), callSiteMethodsignature);
    }
    public void invokeBinaryBooleanFixnumRHS(String nameCompilerCallback receiverCallbacklong fixnum) {
        invokeBinaryFixnumRHS(namereceiverCallbackfixnum);
        
        .isTrue();
    }
    public void invokeBinaryFloatRHS(String nameCompilerCallback receiverCallbackdouble flote) {
        .loadThreadContext(); // [adapter, tc]
        // for visibility checking without requiring frame self
        // TODO: don't bother passing when fcall or vcall, and adjust callsite appropriately
        .loadSelf();
        if (receiverCallback != null) {
            receiverCallback.call();
        } else {
            .loadSelf();
        }
        .ldc(flote);
        String signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classdouble.class));
        String callSiteMethod = "call";
        .invokevirtual(p(CallSite.class), callSiteMethodsignature);
    }
    
    public void invokeDynamic(String nameCompilerCallback receiverCallbackArgumentsCallback argsCallbackCallType callTypeCompilerCallback closureArgboolean iterator) {
        .loadThreadContext(); // [adapter, tc]
        // for visibility checking without requiring frame self
        // TODO: don't bother passing when fcall or vcall, and adjust callsite appropriately
        .loadSelf();
        
        if (receiverCallback != null) {
            receiverCallback.call();
        } else {
            .loadSelf();
        }
        // super uses current block if none given
        if (callType == . && closureArg == null) {
            closureArg = new CompilerCallback() {
                public void call(BodyCompiler context) {
                    .loadBlock();
                }
            };
        }
        
        String signature;
        String callSiteMethod = "call";
        // args
        if (argsCallback == null) {
            // block
            if (closureArg == null) {
                // no args, no block
                signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.class));
            } else {
                // no args, with block
                if (iteratorcallSiteMethod = "callIter";
                closureArg.call();
                signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classBlock.class));
            }
        } else {
            argsCallback.call();
            // block
            if (closureArg == null) {
                // with args, no block
                switch (argsCallback.getArity()) {
                case 1:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.class));
                    break;
                case 2:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.class));
                    break;
                case 3:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.class));
                    break;
                default:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].class));
                }
            } else {
                // with args, with block
                if (iteratorcallSiteMethod = "callIter";
                closureArg.call();
                
                switch (argsCallback.getArity()) {
                case 1:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classBlock.class));
                    break;
                case 2:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classBlock.class));
                    break;
                case 3:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classIRubyObject.classBlock.class));
                    break;
                default:
                    signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classBlock.class));
                }
            }
        }
        
        // adapter, tc, recv, args{0,1}, block{0,1}]
        .invokevirtual(p(CallSite.class), callSiteMethodsignature);
    }
    
    public void invokeDynamicVarargs(String nameCompilerCallback receiverCallbackArgumentsCallback argsCallbackCallType callTypeCompilerCallback closureArgboolean iterator) {
        assert argsCallback.getArity() == -1;
        
        .loadThreadContext(); // [adapter, tc]
        // for visibility checking without requiring frame self
        // TODO: don't bother passing when fcall or vcall, and adjust callsite appropriately
        .loadSelf();
        
        if (receiverCallback != null) {
            receiverCallback.call();
        } else {
            .loadSelf();
        }
        // super uses current block if none given
        if (callType == . && closureArg == null) {
            closureArg = new CompilerCallback() {
                public void call(BodyCompiler context) {
                    .loadBlock();
                }
            };
        }
        
        String signature;
        String callSiteMethod = "callVarargs";
        
        argsCallback.call();
        
        // block
        if (closureArg == null) {
            signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].class));
        } else {
            if (iteratorcallSiteMethod = "callVarargsIter";
            closureArg.call();
            signature = sig(IRubyObject.classparams(ThreadContext.classIRubyObject.classIRubyObject.classIRubyObject[].classBlock.class));
        }
        .invokevirtual(p(CallSite.class), callSiteMethodsignature);
    }
    public void invokeOpAsgnWithOr(String attrNameString attrAsgnNameCompilerCallback receiverCallbackArgumentsCallback argsCallback) {
        receiverCallback.call();
        .dup();
        .loadSelf();
        
        .invokeUtilityMethod("preOpAsgnWithOrAnd"sig(IRubyObject.classIRubyObject.classThreadContext.classIRubyObject.classCallSite.class));
        
        Label done = new Label();
        Label isTrue = new Label();
        
        .dup();
        .invokeIRubyObject("isTrue"sig(boolean.class));
        .ifne(isTrue);
        
        .pop(); // pop extra attr value
        argsCallback.call();
        .loadSelf();
        
        .invokeUtilityMethod("postOpAsgnWithOrAnd",
                sig(IRubyObject.classIRubyObject.classIRubyObject.classThreadContext.classIRubyObject.classCallSite.class));
        .go_to(done);
        
        .label(isTrue);
        .swap();
        .pop();
        
        .label(done);
    }
    public void invokeOpAsgnWithAnd(String attrNameString attrAsgnNameCompilerCallback receiverCallbackArgumentsCallback argsCallback) {
        receiverCallback.call();
        .dup();
        .loadSelf();
        
        .invokeUtilityMethod("preOpAsgnWithOrAnd"sig(IRubyObject.classIRubyObject.classThreadContext.classIRubyObject.classCallSite.class));
        
        Label done = new Label();
        Label isFalse = new Label();
        
        .dup();
        .invokeIRubyObject("isTrue"sig(boolean.class));
        .ifeq(isFalse);
        
        .pop(); // pop extra attr value
        argsCallback.call();
        .loadSelf();
        
        .invokeUtilityMethod("postOpAsgnWithOrAnd",
                sig(IRubyObject.classIRubyObject.classIRubyObject.classThreadContext.classIRubyObject.classCallSite.class));
        .go_to(done);
        
        .label(isFalse);
        .swap();
        .pop();
        
        .label(done);
    }
    public void invokeOpAsgnWithMethod(String operatorNameString attrNameString attrAsgnNameCompilerCallback receiverCallbackArgumentsCallback argsCallback) {
        .loadSelf();
        receiverCallback.call();
        argsCallback.call();
        
        .invokeUtilityMethod("opAsgnWithMethod",
                sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.classCallSite.classCallSite.classCallSite.class));
    }
    public void yield(CompilerCallback argsCallbackboolean unwrap) {
        .loadBlock();
        if (argsCallback != null) {
            argsCallback.call();
        } else {
            .aconst_null();
        }
        if (unwrap) {
            .aconst_null();
            .aconst_null();
            .invokevirtual(p(Block.class), "yieldArray"sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classRubyModule.class));
        } else {
            .invokevirtual(p(Block.class), "yield"sig(IRubyObject.classThreadContext.classIRubyObject.class));
        }
    }
    public void yield19(CompilerCallback argsCallbackboolean unsplat) {
        .loadBlock();
        if (argsCallback != null) {
            argsCallback.call();
        } else {
            .loadNil();
        }
        if (unsplat) {
            .loadBlock();
            .invokeUtilityMethod("unsplatValue19IfArityOne"sig(IRubyObject.classIRubyObject.classBlock.class));
        }
        .aconst_null();
        .aconst_null();
        .invokevirtual(p(Block.class), "yieldArray"sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classRubyModule.class));
    }
    public void yieldSpecific(ArgumentsCallback argsCallback) {
        .loadBlock();
        String signature;
        if (argsCallback == null) {
            signature = sig(IRubyObject.classThreadContext.class);
        } else {
            argsCallback.call();
            switch (argsCallback.getArity()) {
            case 1:
                signature = sig(IRubyObject.classThreadContext.classIRubyObject.class);
                break;
            case 2:
                signature = sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.class);
                break;
            case 3:
                signature = sig(IRubyObject.classThreadContext.classIRubyObject.classIRubyObject.classIRubyObject.class);
                break;
            default:
                throw new NotCompilableException("Can't do specific-arity call for > 3 args yet");
            }
        }
        .invokevirtual(p(Block.class), "yieldSpecific"signature);
    }
    public void invokeEqq(ArgumentsCallback receiversCompilerCallback argument) {
        if (argument == null) {
            receivers.call();
            switch (receivers.getArity()) {
            case 1:
                .invokeUtilityMethod("invokeEqqForCaselessWhen"sig(boolean.class,
                        IRubyObject.class /*receiver*/
                        ));
                break;
            case 2:
                .invokeUtilityMethod("invokeEqqForCaselessWhen"sig(boolean.class,
                        IRubyObject.class/*receiver*/
                        IRubyObject.class
                        ));
                break;
            case 3:
                .invokeUtilityMethod("invokeEqqForCaselessWhen"sig(boolean.class,
                        IRubyObject.class/*receiver*/
                        IRubyObject.class,
                        IRubyObject.class
                        ));
                break;
            default:
                .invokeUtilityMethod("invokeEqqForCaselessWhen"sig(boolean.class,
                        IRubyObject[].class /*receiver*/
                        ));
            }
        } else {
            // arg and receiver already present on the stack
            .loadThreadContext();
            .loadSelf();
            argument.call();
            receivers.call();
            switch (receivers.getArity()) {
            case 1:
                .invokeUtilityMethod("invokeEqqForCaseWhen"sig(boolean.class,
                        CallSite.class,
                        ThreadContext.class,
                        IRubyObject.class /*self*/,
                        IRubyObject.class/*arg*/
                        IRubyObject.class /*receiver*/
                        ));
                break;
            case 2:
                .invokeUtilityMethod("invokeEqqForCaseWhen"sig(boolean.class,
                        CallSite.class,
                        ThreadContext.class,
                        IRubyObject.class /*self*/,
                        IRubyObject.class/*arg*/
                        IRubyObject.class/*receiver*/
                        IRubyObject.class
                        ));
                break;
            case 3:
                .invokeUtilityMethod("invokeEqqForCaseWhen"sig(boolean.class,
                        CallSite.class,
                        ThreadContext.class,
                        IRubyObject.class /*self*/,
                        IRubyObject.class/*arg*/
                        IRubyObject.class/*receiver*/
                        IRubyObject.class,
                        IRubyObject.class
                        ));
                break;
            default:
                .invokeUtilityMethod("invokeEqqForCaseWhen"sig(boolean.class,
                        CallSite.class,
                        ThreadContext.class,
                        IRubyObject.class /*self*/,
                        IRubyObject.class/*arg*/
                        IRubyObject[].class /*receiver*/
                        ));
            }
        }
    }
New to GrepCode? Check out our FAQ X