Package org.jruby.compiler.impl

Source Code of org.jruby.compiler.impl.ChildScopedBodyCompiler

package org.jruby.compiler.impl;

import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.jruby.compiler.ASTInspector;
import org.jruby.compiler.ArrayCallback;
import org.jruby.compiler.CompilerCallback;
import org.jruby.compiler.NotCompilableException;
import org.jruby.exceptions.JumpException;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.objectweb.asm.Label;
import static org.jruby.util.CodegenUtils.*;

public class ChildScopedBodyCompiler extends BaseBodyCompiler {

    public ChildScopedBodyCompiler(StandardASMCompiler scriptCompiler, String closureMethodName, ASTInspector inspector, StaticScope scope) {
        super(scriptCompiler, closureMethodName, inspector, scope);
    }

    protected String getSignature() {
        return StandardASMCompiler.CLOSURE_SIGNATURE;
    }

    protected void createVariableCompiler() {
        if (inspector == null) {
            variableCompiler = new HeapBasedVariableCompiler(this, method, scope, false, StandardASMCompiler.ARGS_INDEX, getFirstTempIndex());
        } else if (inspector.hasClosure() || inspector.hasScopeAwareMethods()) {
            if (RubyInstanceConfig.BOXED_COMPILE_ENABLED && !inspector.hasScopeAwareMethods()) {
                variableCompiler = new BoxedVariableCompiler(this, method, scope, false, StandardASMCompiler.ARGS_INDEX, getFirstTempIndex());
            } else {
                variableCompiler = new HeapBasedVariableCompiler(this, method, scope, false, StandardASMCompiler.ARGS_INDEX, getFirstTempIndex());
            }
        } else {
            variableCompiler = new StackBasedVariableCompiler(this, method, scope, false, StandardASMCompiler.ARGS_INDEX, getFirstTempIndex());
        }
    }

    public void beginMethod(CompilerCallback args, StaticScope scope) {
        method.start();

        // set up a local IRuby variable
        method.aload(StandardASMCompiler.THREADCONTEXT_INDEX);
        invokeThreadContext("getRuntime", sig(Ruby.class));
        method.dup();
        method.astore(getRuntimeIndex());

        // grab nil for local variables
        invokeIRuby("getNil", sig(IRubyObject.class));
        method.astore(getNilIndex());

        variableCompiler.beginClosure(args, scope);
        redoJump = new Label();
        method.label(scopeStart);
    }

    public void beginClass(CompilerCallback bodyPrep, StaticScope scope) {
        throw new NotCompilableException("ERROR: closure compiler should not be used for class bodies");
    }

    public ChainedChildBodyCompiler outline(String methodName) {
        // chain to the next segment of this giant method
        method.aload(StandardASMCompiler.THIS);

        // load all arguments straight through
        for (int i = 1; i <= 3; i++) {
            method.aload(i);
        }
        // we append an index to ensure two identical method names will not conflict
        methodName = methodName + "_" + script.getAndIncrementMethodIndex();
        method.invokevirtual(script.getClassname(), methodName, getSignature());

        ChainedChildBodyCompiler methodCompiler = new ChainedChildBodyCompiler(script, methodName, inspector, scope, this);

        methodCompiler.beginChainedMethod();

        return methodCompiler;
    }

    public void endBody() {
        // end of scoping for closure's vars
        method.areturn();
        method.label(scopeEnd);

        // handle redos by restarting the block
        method.pop();
        method.go_to(scopeStart);

        method.trycatch(scopeStart, scopeEnd, scopeEnd, p(JumpException.RedoJump.class));

        // method is done, declare all variables
        variableCompiler.declareLocals(scope, scopeStart, scopeEnd);

        method.end();
    }

    @Override
    public void loadBlock() {
        loadThreadContext();
        invokeThreadContext("getFrameBlock", sig(Block.class));
    }

    public void performReturn() {
        loadThreadContext();
        invokeUtilityMethod("returnJump", sig(JumpException.ReturnJump.class, IRubyObject.class, ThreadContext.class));
        method.athrow();
    }

    public void processRequiredArgs(Arity arity, int requiredArgs, int optArgs, int restArg) {
        throw new NotCompilableException("Shouldn\'t be calling this...");
    }

    public void assignOptionalArgs(Object object, int expectedArgsCount, int size, ArrayCallback optEval) {
        throw new NotCompilableException("Shouldn\'t be calling this...");
    }

    public void processRestArg(int startIndex, int restArg) {
        throw new NotCompilableException("Shouldn\'t be calling this...");
    }

    public void processBlockArgument(int index) {
        loadRuntime();
        loadThreadContext();
        loadBlock();
        method.pushInt(index);
        invokeUtilityMethod("processBlockArgument", sig(void.class, params(Ruby.class, ThreadContext.class, Block.class, int.class)));
    }

    public void issueBreakEvent(CompilerCallback value) {
        if (currentLoopLabels != null) {
            value.call(this);
            issueLoopBreak();
        } else {
            loadThreadContext();
            value.call(this);
            invokeUtilityMethod("breakJump", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class));
        }
    }

    public void issueNextEvent(CompilerCallback value) {
        if (currentLoopLabels != null) {
            value.call(this);
            issueLoopNext();
        } else {
            value.call(this);
            invokeUtilityMethod("nextJump", sig(IRubyObject.class, IRubyObject.class));
        }
    }

    public void issueRedoEvent() {
        // FIXME: This isn't right for within ensured/rescued code
        if (currentLoopLabels != null) {
            issueLoopRedo();
        } else if (inNestedMethod) {
            invokeUtilityMethod("redoJump", sig(IRubyObject.class));
        } else {
            // jump back to the top of the main body of this closure
            method.go_to(scopeStart);
        }
    }
}
TOP

Related Classes of org.jruby.compiler.impl.ChildScopedBodyCompiler

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.