Package org.jruby.ast.executable

Source Code of org.jruby.ast.executable.RubiniusMachine

/***** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common 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/cpl-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.
*
* Copyright (C) 2007 Ola Bini <ola.bini@gmail.com>
*
* 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 CPL, 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 CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby.ast.executable;

import org.jruby.MetaClass;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyFixnum;
import org.jruby.RubyModule;
import org.jruby.RubyString;
import org.jruby.parser.StaticScope;
import org.jruby.parser.LocalStaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallType;
import org.jruby.runtime.MethodIndex;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.internal.runtime.methods.WrapperMethod;
import org.jruby.internal.runtime.methods.RubiniusMethod;
import org.jruby.javasupport.util.RuntimeHelpers;

/**
* @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
*/
public class RubiniusMachine {
    public final static RubiniusMachine INSTANCE = new RubiniusMachine();

    public final static int getInt(char[] bytecodes, int ix) {
        int val = 0;
        val += (bytecodes[ix+0]<<24);
        val += (bytecodes[ix+1]<<16);
        val += (bytecodes[ix+2]<<8);
        val += (bytecodes[ix+3]);
        return val;
    }

    public IRubyObject exec(ThreadContext context, IRubyObject self, char[] bytecodes, IRubyObject[] literals, IRubyObject[] args) {
        IRubyObject[] stack = new IRubyObject[20];
        int stackTop = 0;
        stack[stackTop] = context.getRuntime().getNil();
        for(int i=0;i<args.length;i++) {
            stack[++stackTop] = args[i];
        }
        int ip = 0;
        int call_flags = -1;
        int cache_index = -1;
        Ruby runtime = context.getRuntime();
        IRubyObject recv;
        IRubyObject other;

        loop: while (ip < bytecodes.length) {
            int ix = ip;
            int code = bytecodes[ip++];
            /*
                System.err.print(RubiniusInstructions.NAMES[code] + " (" + code + ") ");
                if(RubiniusInstructions.ONE_INT[code]) {
                    System.err.print("[" + getInt(bytecodes, ip) + "] ");
                } else if(RubiniusInstructions.TWO_INT[code]) {
                    System.err.print("[" + getInt(bytecodes, ip) + ", " + getInt(bytecodes, ip+4) + "] ");
                }
                System.err.println("{" + ix + "}");

                for(int i=stackTop; i>=0; i--) {
                    System.err.println(" [" + i + "]=" + stack[i].callMethod(context, "inspect"));
                    }*/
            switch(code) {
            case RubiniusInstructions.NOOP: {
                break;
            }
            case RubiniusInstructions.ADD_METHOD: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                String name = literals[val].toString();
                RubyModule clzz = (RubyModule)stack[stackTop--];
                RubyArray method = (RubyArray)stack[stackTop--];
               
                Visibility visibility = context.getCurrentVisibility();
                if (name == "initialize" || visibility == Visibility.MODULE_FUNCTION) {
                    visibility = Visibility.PRIVATE;
                }
               
                RubiniusCMethod cmethod = new RubiniusCMethod(method);
               
                StaticScope staticScope = new LocalStaticScope(context.getCurrentScope().getStaticScope());
                staticScope.setVariables(new String[cmethod.locals]);
                staticScope.determineModule();

                RubiniusMethod newMethod = new RubiniusMethod(clzz, cmethod, staticScope, visibility);

                clzz.addMethod(name, newMethod);
   
                if (context.getCurrentVisibility() == Visibility.MODULE_FUNCTION) {
                    clzz.getSingletonClass().addMethod(
                            name,
                            new WrapperMethod(clzz.getSingletonClass(), newMethod,
                                    Visibility.PUBLIC));
                    clzz.callMethod(context, "singleton_method_added", literals[val]);
                }
   
                if (clzz.isSingleton()) {
                    ((MetaClass) clzz).getAttached().callMethod(
                            context, "singleton_method_added", literals[val]);
                } else {
                    clzz.callMethod(context, "method_added", literals[val]);
                }
                stack[++stackTop] = method;
                break;
            }
            case RubiniusInstructions.META_PUSH_NEG_1: {
                stack[++stackTop] = RubyFixnum.minus_one(runtime);
                break;
            }
            case RubiniusInstructions.CHECK_ARGCOUNT: {
                int min = getInt(bytecodes, ip);
                ip += 4;
                int max = getInt(bytecodes, ip);
                ip += 4;

                if(args.length < min) {
                    throw runtime.newArgumentError("wrong # of arguments(" + args.length + " for " + min + ")");
                } else if(max>0 && args.length>max) {
                    throw runtime.newArgumentError("wrong # of arguments(" + args.length + " for " + max + ")");
                }
                break;
            }
            case RubiniusInstructions.META_PUSH_0: {
                stack[++stackTop] = RubyFixnum.zero(runtime);
                break;
            }
            case RubiniusInstructions.META_PUSH_1: {
                stack[++stackTop] = RubyFixnum.one(runtime);
                break;
            }
            case RubiniusInstructions.META_PUSH_2: {
                stack[++stackTop] = runtime.newFixnum(2);
                break;
            }
            case RubiniusInstructions.SET_LOCAL: {
                int local = getInt(bytecodes, ip);
                ip += 4;
                context.getCurrentScope().setValue(local,stack[stackTop],0);
                break;
            }
            case RubiniusInstructions.PUSH_LOCAL: {
                int local = getInt(bytecodes, ip);
                ip += 4;
                stack[++stackTop] = context.getCurrentScope().getValue(local,0);
                break;
            }
            case RubiniusInstructions.PUSH_NIL: {
                stack[++stackTop] = runtime.getNil();
                break;
            }
            case RubiniusInstructions.PUSH_TRUE: {
                stack[++stackTop] = runtime.getTrue();
                break;
            }
            case RubiniusInstructions.PUSH_FALSE: {
                stack[++stackTop] = runtime.getFalse();
                break;
            }
            case RubiniusInstructions.PUSH_SELF: {
                stack[++stackTop] = self;
                break;
            }
            case RubiniusInstructions.STRING_DUP: {
                stack[stackTop] = ((RubyString)stack[stackTop]).strDup(context.getRuntime());
                break;
            }
            case RubiniusInstructions.PUSH_LITERAL: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                stack[++stackTop] = literals[val];
                break;
            }
            case RubiniusInstructions.META_SEND_OP_LT: {
                IRubyObject t1 = stack[stackTop--];
                IRubyObject t2 = stack[stackTop--];
                if((t1 instanceof RubyFixnum) && (t1 instanceof RubyFixnum)) {
                    stack[++stackTop] = (((RubyFixnum)t1).getLongValue() < ((RubyFixnum)t2).getLongValue()) ? runtime.getTrue() : runtime.getFalse();
                } else {
                    stack[++stackTop] = t1.callMethod(context, MethodIndex.OP_LT, "<", t2);
                }
                break;
            }

            case RubiniusInstructions.META_SEND_OP_GT: {
                IRubyObject t1 = stack[stackTop--];
                IRubyObject t2 = stack[stackTop--];
                if((t1 instanceof RubyFixnum) && (t1 instanceof RubyFixnum)) {
                    stack[++stackTop] = (((RubyFixnum)t1).getLongValue() > ((RubyFixnum)t1).getLongValue()) ? runtime.getTrue() : runtime.getFalse();
                } else {
                    stack[++stackTop] = t1.callMethod(context, MethodIndex.OP_GT, ">", t2);
                }
                break;
            }

            case RubiniusInstructions.META_SEND_OP_PLUS: {
                IRubyObject t1 = stack[stackTop--];
                IRubyObject t2 = stack[stackTop--];
                if((t1 instanceof RubyFixnum) && (t2 instanceof RubyFixnum)) {
                    stack[++stackTop] = ((RubyFixnum)t1).op_plus(context, t2);
                } else {
                    stack[++stackTop] = t1.callMethod(context, MethodIndex.OP_PLUS, "+", t2);
                }
                break;
            }
            case RubiniusInstructions.META_SEND_OP_MINUS: {

                IRubyObject t1 = stack[stackTop--];
                IRubyObject t2 = stack[stackTop--];
                if((t1 instanceof RubyFixnum) && (t2 instanceof RubyFixnum)) {
                    stack[++stackTop] = ((RubyFixnum)t1).op_minus(context, t2);
                } else {
                    stack[++stackTop] = t1.callMethod(context, MethodIndex.OP_MINUS, "-", t2);
                }
                break;
            }
            case RubiniusInstructions.POP: {
                stackTop--;
                break;
            }
            case RubiniusInstructions.SET_CALL_FLAGS: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                call_flags = val;
                break;
            }
            case RubiniusInstructions.SET_CACHE_INDEX: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                cache_index = val;
                break;
            }
            case RubiniusInstructions.SEND_STACK: {
                int index = getInt(bytecodes, ip);
                ip += 4;
                int num_args = getInt(bytecodes, ip);
                ip += 4;
               
                String name = literals[index].toString();
                int ixi = MethodIndex.getIndex(name);
                recv = stack[stackTop--];
                IRubyObject[] argu = new IRubyObject[num_args];
                for(int i=0;i<num_args;i++) {
                    argu[i] = stack[stackTop--];
                }
                if((call_flags & 0x01) == 0x01) { //Functional
                    stack[++stackTop] = RuntimeHelpers.invoke(context, recv, name, argu, Block.NULL_BLOCK);
                } else {
                    stack[++stackTop] = RuntimeHelpers.invoke(context, recv, name, argu, CallType.NORMAL, Block.NULL_BLOCK);
                }
                break;
            }
            case RubiniusInstructions.GOTO_IF_FALSE: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                if(!stack[stackTop--].isTrue()) {
                    ip = val;
                }
                break;
            }
            case RubiniusInstructions.GOTO_IF_TRUE: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                if(stack[stackTop--].isTrue()) {
                    ip = val;
                }
                break;
            }
            case RubiniusInstructions.SWAP_STACK: {
                IRubyObject swap = stack[stackTop];
                stack[stackTop] = stack[stackTop-1];
                stack[stackTop-1] = swap;
                break;
            }
            case RubiniusInstructions.DUP_TOP: {
                stack[stackTop+1] = stack[stackTop];
                stackTop++;
                break;
            }
            case RubiniusInstructions.GOTO: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                ip = val;
                break;
            }
            case RubiniusInstructions.RET: {
                return stack[stackTop];
            }
            case RubiniusInstructions.PUSH_INT: {
                int val = getInt(bytecodes, ip);
                ip += 4;
                stack[++stackTop] = runtime.newFixnum(val);
                break;
            }
            case RubiniusInstructions.PUSH_CONST: {
                int index = getInt(bytecodes, ip);
                ip += 4;
               
                String name = literals[index].toString();
                stack[++stackTop] = context.getConstant(name);
                break;
            }
            default:
                System.err.println("--COULDN'T");
                if(RubiniusInstructions.ONE_INT[code]) {
                    ip+=4;
                } else if(RubiniusInstructions.TWO_INT[code]) {
                    ip+=8;
                }
                break;
            }
        }
        return null;
    }
}// RubiniusMachine
TOP

Related Classes of org.jruby.ast.executable.RubiniusMachine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.