nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
author attila
Wed, 28 Jan 2015 17:58:08 +0100
changeset 28690 78317797ab62
parent 27206 d4a707c9db5a
child 30984 844283fdfa54
permissions -rw-r--r--
8067139: Finally blocks inlined incorrectly Reviewed-by: hannesw, lagergren
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
27206
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     1
/*
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     2
 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     4
 *
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    10
 *
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    15
 * accompanied this code).
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    16
 *
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    20
 *
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    23
 * questions.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    24
 */
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    25
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    26
package jdk.nashorn.internal.codegen;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    27
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    28
import static jdk.nashorn.internal.ir.Node.NO_FINISH;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    29
import static jdk.nashorn.internal.ir.Node.NO_LINE_NUMBER;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    30
import static jdk.nashorn.internal.ir.Node.NO_TOKEN;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    31
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    32
import java.util.ArrayDeque;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    33
import java.util.ArrayList;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    34
import java.util.Arrays;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    35
import java.util.Collections;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    36
import java.util.Deque;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    37
import java.util.List;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    38
import java.util.Objects;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    39
import jdk.nashorn.internal.ir.AccessNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    40
import jdk.nashorn.internal.ir.BinaryNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    41
import jdk.nashorn.internal.ir.Block;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    42
import jdk.nashorn.internal.ir.BlockLexicalContext;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    43
import jdk.nashorn.internal.ir.BreakNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    44
import jdk.nashorn.internal.ir.CallNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    45
import jdk.nashorn.internal.ir.CaseNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    46
import jdk.nashorn.internal.ir.ContinueNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    47
import jdk.nashorn.internal.ir.Expression;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    48
import jdk.nashorn.internal.ir.ExpressionStatement;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    49
import jdk.nashorn.internal.ir.FunctionNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    50
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    51
import jdk.nashorn.internal.ir.GetSplitState;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    52
import jdk.nashorn.internal.ir.IdentNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    53
import jdk.nashorn.internal.ir.IfNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    54
import jdk.nashorn.internal.ir.JumpStatement;
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 27206
diff changeset
    55
import jdk.nashorn.internal.ir.JumpToInlinedFinally;
27206
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    56
import jdk.nashorn.internal.ir.LiteralNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    57
import jdk.nashorn.internal.ir.Node;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    58
import jdk.nashorn.internal.ir.ReturnNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    59
import jdk.nashorn.internal.ir.SetSplitState;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    60
import jdk.nashorn.internal.ir.SplitNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    61
import jdk.nashorn.internal.ir.SplitReturn;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    62
import jdk.nashorn.internal.ir.Statement;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    63
import jdk.nashorn.internal.ir.SwitchNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    64
import jdk.nashorn.internal.ir.VarNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    65
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    66
import jdk.nashorn.internal.parser.Token;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    67
import jdk.nashorn.internal.parser.TokenType;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    68
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    69
/**
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    70
 * A node visitor that replaces {@link SplitNode}s with anonymous function invocations and some additional constructs
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    71
 * to support control flow across splits. By using this transformation, split functions are translated into ordinary
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    72
 * JavaScript functions with nested anonymous functions. The transformations however introduce several AST nodes that
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    73
 * have no JavaScript source representations ({@link GetSplitState}, {@link SetSplitState}, and {@link SplitReturn}),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    74
 * and therefore such function is no longer reparseable from its source. For that reason, split functions and their
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    75
 * fragments are serialized in-memory and deserialized when they need to be recompiled either for deoptimization or
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    76
 * for type specialization.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    77
 * NOTE: all {@code leave*()} methods for statements are returning their input nodes. That way, they will not mutate
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    78
 * the original statement list in the block containing the statement, which is fine, as it'll be replaced by the
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    79
 * lexical context when the block is left. If we returned something else (e.g. null), we'd cause a mutation in the
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    80
 * enclosing block's statement list that is otherwise overwritten later anyway.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    81
 */
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    82
final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    83
    private static final int FALLTHROUGH_STATE = -1;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    84
    private static final int RETURN_STATE = 0;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    85
    private static final int BREAK_STATE = 1;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    86
    private static final int FIRST_JUMP_STATE = 2;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    87
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    88
    private static final String THIS_NAME = CompilerConstants.THIS.symbolName();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    89
    private static final String RETURN_NAME = CompilerConstants.RETURN.symbolName();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    90
    // Used as the name of the formal parameter for passing the current value of :return symbol into a split fragment.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    91
    private static final String RETURN_PARAM_NAME = RETURN_NAME + "-in";
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    92
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    93
    private final Deque<FunctionState> functionStates = new ArrayDeque<>();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    94
    private final Deque<SplitState> splitStates = new ArrayDeque<>();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    95
    private final Namespace namespace;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    96
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    97
    private boolean artificialBlock = false;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    98
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
    99
    // -1 is program; we need to use negative ones
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   100
    private int nextFunctionId = -2;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   101
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   102
    public SplitIntoFunctions(final Compiler compiler) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   103
        super(new BlockLexicalContext() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   104
            @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   105
            protected Block afterSetStatements(Block block) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   106
                for(Statement stmt: block.getStatements()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   107
                    assert !(stmt instanceof SplitNode);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   108
                }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   109
                return block;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   110
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   111
        });
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   112
        namespace = new Namespace(compiler.getScriptEnvironment().getNamespace());
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   113
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   114
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   115
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   116
    public boolean enterFunctionNode(final FunctionNode functionNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   117
        functionStates.push(new FunctionState(functionNode));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   118
        return true;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   119
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   120
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   121
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   122
    public Node leaveFunctionNode(final FunctionNode functionNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   123
        functionStates.pop();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   124
        return functionNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   125
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   126
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   127
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   128
    protected Node leaveDefault(final Node node) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   129
        if (node instanceof Statement) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   130
            appendStatement((Statement)node);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   131
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   132
        return node;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   133
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   134
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   135
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   136
    public boolean enterSplitNode(final SplitNode splitNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   137
        getCurrentFunctionState().splitDepth++;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   138
        splitStates.push(new SplitState(splitNode));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   139
        return true;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   140
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   141
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   142
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   143
    public Node leaveSplitNode(final SplitNode splitNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   144
        // Replace the split node with an anonymous function expression call.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   145
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   146
        final FunctionState fnState = getCurrentFunctionState();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   147
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   148
        final String name = splitNode.getName();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   149
        Block body = splitNode.getBody();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   150
        final int firstLineNumber = body.getFirstStatementLineNumber();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   151
        final long token = body.getToken();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   152
        final int finish = body.getFinish();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   153
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   154
        final FunctionNode originalFn = fnState.fn;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   155
        assert originalFn == lc.getCurrentFunction();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   156
        final boolean isProgram = originalFn.isProgram();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   157
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   158
        // Change SplitNode({...}) into "function () { ... }", or "function (:return-in) () { ... }" (for program)
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   159
        final long newFnToken = Token.toDesc(TokenType.FUNCTION, nextFunctionId--, 0);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   160
        final FunctionNode fn = new FunctionNode(
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   161
                originalFn.getSource(),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   162
                body.getFirstStatementLineNumber(),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   163
                newFnToken,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   164
                finish,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   165
                newFnToken,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   166
                NO_TOKEN,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   167
                namespace,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   168
                createIdent(name),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   169
                originalFn.getName() + "$" + name,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   170
                isProgram ? Collections.singletonList(createReturnParamIdent()) : Collections.<IdentNode>emptyList(),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   171
                FunctionNode.Kind.NORMAL,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   172
                // We only need IS_SPLIT conservatively, in case it contains any array units so that we force
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   173
                // the :callee's existence, to force :scope to never be in a slot lower than 2. This is actually
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   174
                // quite a horrible hack to do with CodeGenerator.fixScopeSlot not trampling other parameters
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   175
                // and should go away once we no longer have array unit handling in codegen. Note however that
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   176
                // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   177
                FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   178
                body,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   179
                CompilationState.INITIALIZED,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   180
                null
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   181
        )
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   182
        .setCompileUnit(lc, splitNode.getCompileUnit())
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   183
        .copyCompilationState(lc, originalFn);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   184
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   185
        // Call the function:
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   186
        //     either "(function () { ... }).call(this)"
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   187
        //     or     "(function (:return-in) { ... }).call(this, :return)"
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   188
        // NOTE: Function.call() has optimized linking that basically does a pass-through to the function being invoked.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   189
        // NOTE: CompilationPhase.PROGRAM_POINT_PHASE happens after this, so these calls are subject to optimistic
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   190
        // assumptions on their return value (when they return a value), as they should be.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   191
        final IdentNode thisIdent = createIdent(THIS_NAME);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   192
        final CallNode callNode = new CallNode(firstLineNumber, token, finish, new AccessNode(NO_TOKEN, NO_FINISH, fn, "call"),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   193
                isProgram ? Arrays.<Expression>asList(thisIdent, createReturnIdent())
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   194
                          : Collections.<Expression>singletonList(thisIdent),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   195
                false);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   196
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   197
        final SplitState splitState = splitStates.pop();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   198
        fnState.splitDepth--;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   199
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   200
        final Expression callWithReturn;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   201
        final boolean hasReturn = splitState.hasReturn;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   202
        if (hasReturn && fnState.splitDepth > 0) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   203
            final SplitState parentSplit = splitStates.peek();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   204
            if (parentSplit != null) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   205
                // Propagate hasReturn to parent split
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   206
                parentSplit.hasReturn = true;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   207
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   208
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   209
        if (hasReturn || isProgram) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   210
            // capture return value: ":return = (function () { ... })();"
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   211
            callWithReturn = new BinaryNode(Token.recast(token, TokenType.ASSIGN), createReturnIdent(), callNode);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   212
        } else {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   213
            // no return value, just call : "(function () { ... })();"
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   214
            callWithReturn = callNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   215
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   216
        appendStatement(new ExpressionStatement(firstLineNumber, token, finish, callWithReturn));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   217
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   218
        Statement splitStateHandler;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   219
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   220
        final List<JumpStatement> jumpStatements = splitState.jumpStatements;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   221
        final int jumpCount = jumpStatements.size();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   222
        // There are jumps (breaks or continues) that need to be propagated outside the split node. We need to
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   223
        // set up a switch statement for them:
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   224
        // switch(:scope.getScopeState()) { ... }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   225
        if (jumpCount > 0) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   226
            final List<CaseNode> cases = new ArrayList<>(jumpCount + (hasReturn ? 1 : 0));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   227
            if (hasReturn) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   228
                // If the split node also contained a return, we'll slip it as a case in the switch statement
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   229
                addCase(cases, RETURN_STATE, createReturnFromSplit());
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   230
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   231
            int i = FIRST_JUMP_STATE;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   232
            for (final JumpStatement jump: jumpStatements) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   233
                addCase(cases, i++, enblockAndVisit(jump));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   234
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   235
            splitStateHandler = new SwitchNode(NO_LINE_NUMBER, token, finish, GetSplitState.INSTANCE, cases, null);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   236
        } else {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   237
            splitStateHandler = null;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   238
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   239
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   240
        // As the switch statement itself is breakable, an unlabelled break can't be in the switch statement,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   241
        // so we need to test for it separately.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   242
        if (splitState.hasBreak) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   243
            // if(:scope.getScopeState() == Scope.BREAK) { break; }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   244
            splitStateHandler = makeIfStateEquals(firstLineNumber, token, finish, BREAK_STATE,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   245
                    enblockAndVisit(new BreakNode(NO_LINE_NUMBER, token, finish, null)), splitStateHandler);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   246
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   247
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   248
        // Finally, if the split node had a return statement, but there were no external jumps, we didn't have
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   249
        // the switch statement to handle the return, so we need a separate if for it.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   250
        if (hasReturn && jumpCount == 0) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   251
            // if (:scope.getScopeState() == Scope.RETURN) { return :return; }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   252
            splitStateHandler = makeIfStateEquals(NO_LINE_NUMBER, token, finish, RETURN_STATE,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   253
                    createReturnFromSplit(), splitStateHandler);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   254
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   255
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   256
        if (splitStateHandler != null) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   257
            appendStatement(splitStateHandler);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   258
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   259
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   260
        return splitNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   261
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   262
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   263
    private static void addCase(final List<CaseNode> cases, final int i, final Block body) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   264
        cases.add(new CaseNode(NO_TOKEN, NO_FINISH, intLiteral(i), body));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   265
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   266
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   267
    private static LiteralNode<Number> intLiteral(final int i) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   268
        return LiteralNode.newInstance(NO_TOKEN, NO_FINISH, i);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   269
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   270
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   271
    private static Block createReturnFromSplit() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   272
        return new Block(NO_TOKEN, NO_FINISH, createReturnReturn());
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   273
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   274
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   275
    private static ReturnNode createReturnReturn() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   276
        return new ReturnNode(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH, createReturnIdent());
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   277
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   278
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   279
    private static IdentNode createReturnIdent() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   280
        return createIdent(RETURN_NAME);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   281
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   282
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   283
    private static IdentNode createReturnParamIdent() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   284
        return createIdent(RETURN_PARAM_NAME);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   285
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   286
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   287
    private static IdentNode createIdent(final String name) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   288
        return new IdentNode(NO_TOKEN, NO_FINISH, name);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   289
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   290
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   291
    private Block enblockAndVisit(final JumpStatement jump) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   292
        artificialBlock = true;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   293
        final Block block = (Block)new Block(NO_TOKEN, NO_FINISH, jump).accept(this);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   294
        artificialBlock = false;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   295
        return block;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   296
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   297
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   298
    private static IfNode makeIfStateEquals(final int lineNumber, final long token, final int finish,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   299
            final int value, final Block pass, final Statement fail) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   300
        return new IfNode(lineNumber, token, finish,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   301
                new BinaryNode(Token.recast(token, TokenType.EQ_STRICT),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   302
                        GetSplitState.INSTANCE, intLiteral(value)),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   303
                pass,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   304
                fail == null ? null : new Block(NO_TOKEN, NO_FINISH, fail));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   305
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   306
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   307
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   308
    public boolean enterVarNode(VarNode varNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   309
        if (!inSplitNode()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   310
            return super.enterVarNode(varNode);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   311
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   312
        assert !varNode.isBlockScoped(); //TODO: we must handle these too, but we currently don't
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   313
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   314
        final Expression init = varNode.getInit();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   315
        if (varNode.isAnonymousFunctionDeclaration()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   316
            // We ain't moving anonymous function declarations.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   317
            return super.enterVarNode(varNode);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   318
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   319
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   320
        // Move a declaration-only var statement to the top of the outermost function.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   321
        getCurrentFunctionState().varStatements.add(varNode.setInit(null));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   322
        // If it had an initializer, replace it with an assignment expression statement. Note that "var" is a
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   323
        // statement, so it doesn't contribute to :return of the programs, therefore we are _not_ adding a
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   324
        // ":return = ..." assignment around the original assignment.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   325
        if (init != null) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   326
            final long token = Token.recast(varNode.getToken(), TokenType.ASSIGN);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   327
            new ExpressionStatement(varNode.getLineNumber(), token, varNode.getFinish(),
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   328
                    new BinaryNode(token, varNode.getName(), varNode.getInit())).accept(this);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   329
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   330
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   331
        return false;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   332
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   333
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   334
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   335
    public Node leaveBlock(final Block block) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   336
        if (!artificialBlock) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   337
            if (lc.isFunctionBody()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   338
                // Prepend declaration-only var statements to the top of the statement list.
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   339
                lc.prependStatements(getCurrentFunctionState().varStatements);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   340
            } else if (lc.isSplitBody()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   341
                appendSplitReturn(FALLTHROUGH_STATE, NO_LINE_NUMBER);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   342
                if (getCurrentFunctionState().fn.isProgram()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   343
                    // If we're splitting the program, make sure every shard ends with "return :return" and
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   344
                    // begins with ":return = :return-in;".
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   345
                    lc.prependStatement(new ExpressionStatement(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH,
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   346
                            new BinaryNode(Token.toDesc(TokenType.ASSIGN, 0, 0), createReturnIdent(), createReturnParamIdent())));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   347
                }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   348
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   349
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   350
        return block;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   351
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   352
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   353
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   354
    public Node leaveBreakNode(final BreakNode breakNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   355
        return leaveJumpNode(breakNode);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   356
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   357
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   358
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   359
    public Node leaveContinueNode(final ContinueNode continueNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   360
        return leaveJumpNode(continueNode);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   361
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   362
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 27206
diff changeset
   363
    @Override
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 27206
diff changeset
   364
    public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 27206
diff changeset
   365
        return leaveJumpNode(jumpToInlinedFinally);
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 27206
diff changeset
   366
    }
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 27206
diff changeset
   367
27206
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   368
    private JumpStatement leaveJumpNode(final JumpStatement jump) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   369
        if (inSplitNode()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   370
            final SplitState splitState = getCurrentSplitState();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   371
            final SplitNode splitNode = splitState.splitNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   372
            if (lc.isExternalTarget(splitNode, jump.getTarget(lc))) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   373
                appendSplitReturn(splitState.getSplitStateIndex(jump), jump.getLineNumber());
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   374
                return jump;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   375
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   376
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   377
        appendStatement(jump);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   378
        return jump;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   379
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   380
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   381
    private void appendSplitReturn(final int splitState, final int lineNumber) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   382
        appendStatement(new SetSplitState(splitState, lineNumber));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   383
        if (getCurrentFunctionState().fn.isProgram()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   384
            // If we're splitting the program, make sure every fragment passes back :return
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   385
            appendStatement(createReturnReturn());
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   386
        } else {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   387
            appendStatement(SplitReturn.INSTANCE);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   388
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   389
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   390
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   391
    @Override
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   392
    public Node leaveReturnNode(final ReturnNode returnNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   393
        if(inSplitNode()) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   394
            appendStatement(new SetSplitState(RETURN_STATE, returnNode.getLineNumber()));
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   395
            getCurrentSplitState().hasReturn = true;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   396
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   397
        appendStatement(returnNode);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   398
        return returnNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   399
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   400
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   401
    private void appendStatement(final Statement statement) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   402
        lc.appendStatement(statement);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   403
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   404
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   405
    private boolean inSplitNode() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   406
        return getCurrentFunctionState().splitDepth > 0;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   407
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   408
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   409
    private FunctionState getCurrentFunctionState() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   410
        return functionStates.peek();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   411
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   412
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   413
    private SplitState getCurrentSplitState() {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   414
        return splitStates.peek();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   415
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   416
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   417
    private static class FunctionState {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   418
        final FunctionNode fn;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   419
        final List<Statement> varStatements = new ArrayList<>();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   420
        int splitDepth;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   421
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   422
        FunctionState(final FunctionNode fn) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   423
            this.fn = fn;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   424
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   425
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   426
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   427
    private static class SplitState {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   428
        final SplitNode splitNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   429
        boolean hasReturn;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   430
        boolean hasBreak;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   431
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   432
        final List<JumpStatement> jumpStatements = new ArrayList<>();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   433
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   434
        int getSplitStateIndex(final JumpStatement jump) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   435
            if (jump instanceof BreakNode && jump.getLabelName() == null) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   436
                // Unlabelled break is a special case
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   437
                hasBreak = true;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   438
                return BREAK_STATE;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   439
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   440
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   441
            int i = 0;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   442
            for(final JumpStatement exJump: jumpStatements) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   443
                if (jump.getClass() == exJump.getClass() && Objects.equals(jump.getLabelName(), exJump.getLabelName())) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   444
                    return i + FIRST_JUMP_STATE;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   445
                }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   446
                ++i;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   447
            }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   448
            jumpStatements.add(jump);
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   449
            return i + FIRST_JUMP_STATE;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   450
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   451
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   452
        SplitState(final SplitNode splitNode) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   453
            this.splitNode = splitNode;
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   454
        }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   455
    }
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents:
diff changeset
   456
}