src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
author attila
Wed, 20 Dec 2017 17:36:50 +0100
changeset 48354 c96d4c720995
parent 47276 bfa048898f11
permissions -rw-r--r--
8193371: Use Dynalink REMOVE operation in Nashorn Reviewed-by: hannesw, sundar
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     1
/*
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     2
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     4
 *
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    10
 *
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    15
 * accompanied this code).
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    16
 *
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    20
 *
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    23
 * questions.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    24
 */
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    25
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    26
package jdk.nashorn.internal.codegen;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    27
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
    28
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    29
import static jdk.nashorn.internal.ir.Expression.isAlwaysFalse;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    30
import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
27969
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
    31
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    32
import java.util.ArrayDeque;
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
    33
import java.util.ArrayList;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    34
import java.util.Collections;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    35
import java.util.Deque;
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
    36
import java.util.HashMap;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    37
import java.util.HashSet;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    38
import java.util.IdentityHashMap;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    39
import java.util.Iterator;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    40
import java.util.LinkedList;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    41
import java.util.List;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    42
import java.util.Map;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    43
import java.util.Set;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    44
import jdk.nashorn.internal.codegen.types.Type;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    45
import jdk.nashorn.internal.ir.AccessNode;
48354
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
    46
import jdk.nashorn.internal.ir.BaseNode;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    47
import jdk.nashorn.internal.ir.BinaryNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    48
import jdk.nashorn.internal.ir.Block;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    49
import jdk.nashorn.internal.ir.BreakNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    50
import jdk.nashorn.internal.ir.BreakableNode;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
    51
import jdk.nashorn.internal.ir.CallNode;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    52
import jdk.nashorn.internal.ir.CaseNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    53
import jdk.nashorn.internal.ir.CatchNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    54
import jdk.nashorn.internal.ir.ContinueNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    55
import jdk.nashorn.internal.ir.Expression;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
    56
import jdk.nashorn.internal.ir.ExpressionStatement;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    57
import jdk.nashorn.internal.ir.ForNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    58
import jdk.nashorn.internal.ir.FunctionNode;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
    59
import jdk.nashorn.internal.ir.GetSplitState;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    60
import jdk.nashorn.internal.ir.IdentNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    61
import jdk.nashorn.internal.ir.IfNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    62
import jdk.nashorn.internal.ir.IndexNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    63
import jdk.nashorn.internal.ir.JoinPredecessor;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    64
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    65
import jdk.nashorn.internal.ir.JumpStatement;
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
    66
import jdk.nashorn.internal.ir.JumpToInlinedFinally;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    67
import jdk.nashorn.internal.ir.LabelNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    68
import jdk.nashorn.internal.ir.LexicalContext;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    69
import jdk.nashorn.internal.ir.LexicalContextNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    70
import jdk.nashorn.internal.ir.LiteralNode;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
    71
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    72
import jdk.nashorn.internal.ir.LocalVariableConversion;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    73
import jdk.nashorn.internal.ir.LoopNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    74
import jdk.nashorn.internal.ir.Node;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
    75
import jdk.nashorn.internal.ir.ObjectNode;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    76
import jdk.nashorn.internal.ir.PropertyNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    77
import jdk.nashorn.internal.ir.ReturnNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    78
import jdk.nashorn.internal.ir.RuntimeNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    79
import jdk.nashorn.internal.ir.RuntimeNode.Request;
27206
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents: 26889
diff changeset
    80
import jdk.nashorn.internal.ir.SplitReturn;
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
    81
import jdk.nashorn.internal.ir.Statement;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    82
import jdk.nashorn.internal.ir.SwitchNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    83
import jdk.nashorn.internal.ir.Symbol;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    84
import jdk.nashorn.internal.ir.TernaryNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    85
import jdk.nashorn.internal.ir.ThrowNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    86
import jdk.nashorn.internal.ir.TryNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    87
import jdk.nashorn.internal.ir.UnaryNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    88
import jdk.nashorn.internal.ir.VarNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    89
import jdk.nashorn.internal.ir.WhileNode;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
    90
import jdk.nashorn.internal.ir.WithNode;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    91
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
32888
24f99be3d5ab 8134502: introduce abstraction for basic NodeVisitor usage
attila
parents: 32692
diff changeset
    92
import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    93
import jdk.nashorn.internal.parser.TokenType;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    94
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    95
/**
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    96
 * Calculates types for local variables. For purposes of local variable type calculation, the only types used are
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    97
 * Undefined, boolean, int, long, double, and Object. The calculation eagerly widens types of local variable to their
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    98
 * widest at control flow join points.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
    99
 * TODO: investigate a more sophisticated solution that uses use/def information to only widens the type of a local
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   100
 * variable to its widest used type after the join point. That would eliminate some widenings of undefined variables to
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   101
 * object, most notably those used only in loops. We need a full liveness analysis for that. Currently, we can establish
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   102
 * per-type liveness, which eliminates most of unwanted dead widenings.
27972
8ec664fdf8da 8066236: RuntimeNode forces copy creation on visitation
attila
parents: 27970
diff changeset
   103
 * NOTE: the way this class is implemented, it actually processes the AST in two passes. The first pass is top-down and
8ec664fdf8da 8066236: RuntimeNode forces copy creation on visitation
attila
parents: 27970
diff changeset
   104
 * implemented in {@code enterXxx} methods. This pass does not mutate the AST (except for one occurrence, noted below),
8ec664fdf8da 8066236: RuntimeNode forces copy creation on visitation
attila
parents: 27970
diff changeset
   105
 * as being able to find relevant labels for control flow joins is sensitive to their reference identity, and mutated
8ec664fdf8da 8066236: RuntimeNode forces copy creation on visitation
attila
parents: 27970
diff changeset
   106
 * label-carrying nodes will create copies of their labels. A second bottom-up pass applying the changes is implemented
8ec664fdf8da 8066236: RuntimeNode forces copy creation on visitation
attila
parents: 27970
diff changeset
   107
 * in the separate visitor sitting in {@link #leaveFunctionNode(FunctionNode)}. This visitor will also instantiate new
8ec664fdf8da 8066236: RuntimeNode forces copy creation on visitation
attila
parents: 27970
diff changeset
   108
 * instances of the calculator to be run on nested functions (when not lazy compiling).
8ec664fdf8da 8066236: RuntimeNode forces copy creation on visitation
attila
parents: 27970
diff changeset
   109
 *
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   110
 */
32888
24f99be3d5ab 8134502: introduce abstraction for basic NodeVisitor usage
attila
parents: 32692
diff changeset
   111
final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   112
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   113
    private static class JumpOrigin {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   114
        final JoinPredecessor node;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   115
        final Map<Symbol, LvarType> types;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   116
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   117
        JumpOrigin(final JoinPredecessor node, final Map<Symbol, LvarType> types) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   118
            this.node = node;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   119
            this.types = types;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   120
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   121
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   122
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   123
    private static class JumpTarget {
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
   124
        private final List<JumpOrigin> origins = new LinkedList<>();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   125
        private Map<Symbol, LvarType> types = Collections.emptyMap();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   126
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   127
        void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes, final LocalVariableTypesCalculator calc) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   128
            origins.add(new JumpOrigin(originNode, originTypes));
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   129
            this.types = calc.getUnionTypes(this.types, originTypes);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   130
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   131
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   132
    private enum LvarType {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   133
        UNDEFINED(Type.UNDEFINED),
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   134
        BOOLEAN(Type.BOOLEAN),
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   135
        INT(Type.INT),
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   136
        DOUBLE(Type.NUMBER),
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   137
        OBJECT(Type.OBJECT);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   138
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   139
        private final Type type;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   140
        private final TypeHolderExpression typeExpression;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   141
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   142
        private LvarType(final Type type) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   143
            this.type = type;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   144
            this.typeExpression = new TypeHolderExpression(type);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   145
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   146
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   147
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   148
    /**
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   149
     * A bogus Expression subclass that only reports its type. Used to interrogate BinaryNode and UnaryNode about their
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   150
     * types by creating temporary copies of them and replacing their operands with instances of these. An alternative
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   151
     * solution would be to add BinaryNode.getType(Type lhsType, Type rhsType) and UnaryNode.getType(Type exprType)
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   152
     * methods. For the time being though, this is easier to implement and is in fact fairly clean. It does result in
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   153
     * generation of higher number of temporary short lived nodes, though.
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   154
     */
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   155
    private static class TypeHolderExpression extends Expression {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   156
        private static final long serialVersionUID = 1L;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   157
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   158
        private final Type type;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   159
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   160
        TypeHolderExpression(final Type type) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   161
            super(0L, 0, 0);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   162
            this.type = type;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   163
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   164
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   165
        @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   166
        public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   167
            throw new AssertionError();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   168
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   169
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   170
        @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   171
        public Type getType() {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   172
            return type;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   173
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   174
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   175
        @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   176
        public void toString(final StringBuilder sb, final boolean printType) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   177
            throw new AssertionError();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   178
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   179
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   180
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   181
    private static final Map<Type, LvarType> TO_LVAR_TYPE = new IdentityHashMap<>();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   182
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   183
    static {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   184
        for(final LvarType lvarType: LvarType.values()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   185
            TO_LVAR_TYPE.put(lvarType.type, lvarType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   186
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   187
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   188
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   189
    @SuppressWarnings("unchecked")
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   190
    private static HashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   191
        return (HashMap<Symbol, LvarType>)((HashMap<?,?>)map).clone();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   192
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   193
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   194
    private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType,
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   195
            final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) {
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   196
        if (invalidatedSymbols.contains(symbol)) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   197
            return next;
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   198
        }
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
   199
        final LvarType targetType = joinLvarTypes.get(symbol);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   200
        assert targetType != null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   201
        if(targetType == branchLvarType) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   202
            return next;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   203
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   204
        // NOTE: we could naively just use symbolIsUsed(symbol, branchLvarType) here, but that'd be wrong. While
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   205
        // technically a conversion will read the value of the symbol with that type, but it will also write it to a new
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   206
        // type, and that type might be dead (we can't know yet). For this reason, we don't treat conversion reads as
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   207
        // real uses until we know their target type is live. If we didn't do this, and just did a symbolIsUsed here,
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   208
        // we'd introduce false live variables which could nevertheless turn into dead ones in a subsequent
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   209
        // deoptimization, causing a shift in the list of live locals that'd cause erroneous restoration of
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   210
        // continuations (since RewriteException's byteCodeSlots carries an array and not a name-value map).
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   211
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   212
        symbolIsConverted(symbol, branchLvarType, targetType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   213
        return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   214
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   215
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   216
    private Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   217
        if(types1 == types2 || types1.isEmpty()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   218
            return types2;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   219
        } else if(types2.isEmpty()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   220
            return types1;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   221
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   222
        final Set<Symbol> commonSymbols = new HashSet<>(types1.keySet());
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   223
        commonSymbols.retainAll(types2.keySet());
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   224
        // We have a chance of returning an unmodified set if both sets have the same keys and one is strictly wider
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   225
        // than the other.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   226
        final int commonSize = commonSymbols.size();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   227
        final int types1Size = types1.size();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   228
        final int types2Size = types2.size();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   229
        if(commonSize == types1Size && commonSize == types2Size) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   230
            boolean matches1 = true, matches2 = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   231
            Map<Symbol, LvarType> union = null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   232
            for(final Symbol symbol: commonSymbols) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   233
                final LvarType type1 = types1.get(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   234
                final LvarType type2 = types2.get(symbol);
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   235
                final LvarType widest = widestLvarType(type1, type2);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   236
                if(widest != type1 && matches1) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   237
                    matches1 = false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   238
                    if(!matches2) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   239
                        union = cloneMap(types1);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   240
                    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   241
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   242
                if (widest != type2 && matches2) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   243
                    matches2 = false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   244
                    if(!matches1) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   245
                        union = cloneMap(types2);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   246
                    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   247
                }
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   248
                if(!(matches1 || matches2)) {
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
   249
                    assert union != null;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   250
                    union.put(symbol, widest);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   251
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   252
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   253
            return matches1 ? types1 : matches2 ? types2 : union;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   254
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   255
        // General case
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   256
        final Map<Symbol, LvarType> union;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   257
        if(types1Size > types2Size) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   258
            union = cloneMap(types1);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   259
            union.putAll(types2);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   260
        } else {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   261
            union = cloneMap(types2);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   262
            union.putAll(types1);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   263
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   264
        for(final Symbol symbol: commonSymbols) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   265
            final LvarType type1 = types1.get(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   266
            final LvarType type2 = types2.get(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   267
            union.put(symbol, widestLvarType(type1,  type2));
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   268
        }
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   269
        // If the two sets of symbols differ, there's a good chance that some of
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   270
        // symbols only appearing in one of the sets are lexically invalidated,
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   271
        // so we remove them from further consideration.
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   272
        // This is not strictly necessary, just a working set size optimization.
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   273
        union.keySet().removeAll(invalidatedSymbols);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   274
        return union;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   275
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   276
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   277
    private static void symbolIsUsed(final Symbol symbol, final LvarType type) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   278
        if(type != LvarType.UNDEFINED) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   279
            symbol.setHasSlotFor(type.type);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   280
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   281
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   282
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   283
    private static class SymbolConversions {
34732
6605efbe8447 8144020: Remove long as an internal numeric type
hannesw
parents: 32888
diff changeset
   284
        private static final byte I2D = 1 << 0;
6605efbe8447 8144020: Remove long as an internal numeric type
hannesw
parents: 32888
diff changeset
   285
        private static final byte I2O = 1 << 1;
6605efbe8447 8144020: Remove long as an internal numeric type
hannesw
parents: 32888
diff changeset
   286
        private static final byte D2O = 1 << 2;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   287
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   288
        private byte conversions;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   289
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   290
        void recordConversion(final LvarType from, final LvarType to) {
27361
86c4ddb4797b 8060204: Fix warnings in Joni and tests
lagergren
parents: 27206
diff changeset
   291
            switch (from) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   292
            case UNDEFINED:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   293
                return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   294
            case INT:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   295
            case BOOLEAN:
27361
86c4ddb4797b 8060204: Fix warnings in Joni and tests
lagergren
parents: 27206
diff changeset
   296
                switch (to) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   297
                case DOUBLE:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   298
                    recordConversion(I2D);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   299
                    return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   300
                case OBJECT:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   301
                    recordConversion(I2O);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   302
                    return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   303
                default:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   304
                    illegalConversion(from, to);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   305
                    return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   306
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   307
            case DOUBLE:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   308
                if(to == LvarType.OBJECT) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   309
                    recordConversion(D2O);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   310
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   311
                return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   312
            default:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   313
                illegalConversion(from, to);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   314
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   315
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   316
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   317
        private static void illegalConversion(final LvarType from, final LvarType to) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   318
            throw new AssertionError("Invalid conversion from " + from + " to " + to);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   319
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   320
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   321
        void recordConversion(final byte convFlag) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   322
            conversions = (byte)(conversions | convFlag);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   323
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   324
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   325
        boolean hasConversion(final byte convFlag) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   326
            return (conversions & convFlag) != 0;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   327
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   328
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   329
        void calculateTypeLiveness(final Symbol symbol) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   330
            if(symbol.hasSlotFor(Type.OBJECT)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   331
                if(hasConversion(D2O)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   332
                    symbol.setHasSlotFor(Type.NUMBER);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   333
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   334
                if(hasConversion(I2O)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   335
                    symbol.setHasSlotFor(Type.INT);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   336
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   337
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   338
            if(symbol.hasSlotFor(Type.NUMBER)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   339
                if(hasConversion(I2D)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   340
                    symbol.setHasSlotFor(Type.INT);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   341
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   342
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   343
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   344
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   345
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   346
    private void symbolIsConverted(final Symbol symbol, final LvarType from, final LvarType to) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   347
        SymbolConversions conversions = symbolConversions.get(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   348
        if(conversions == null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   349
            conversions = new SymbolConversions();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   350
            symbolConversions.put(symbol, conversions);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   351
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   352
        conversions.recordConversion(from, to);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   353
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   354
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   355
    private static LvarType toLvarType(final Type type) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   356
        assert type != null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   357
        final LvarType lvarType = TO_LVAR_TYPE.get(type);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   358
        if(lvarType != null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   359
            return lvarType;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   360
        }
34732
6605efbe8447 8144020: Remove long as an internal numeric type
hannesw
parents: 32888
diff changeset
   361
        assert type.isObject() : "Unsupported primitive type: " + type;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   362
        return LvarType.OBJECT;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   363
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   364
    private static LvarType widestLvarType(final LvarType t1, final LvarType t2) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   365
        if(t1 == t2) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   366
            return t1;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   367
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   368
        // Undefined or boolean to anything always widens to object.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   369
        if(t1.ordinal() < LvarType.INT.ordinal() || t2.ordinal() < LvarType.INT.ordinal()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   370
            return LvarType.OBJECT;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   371
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   372
        return LvarType.values()[Math.max(t1.ordinal(), t2.ordinal())];
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   373
    }
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
   374
    private final Compiler compiler;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   375
    private final Map<Label, JumpTarget> jumpTargets = new IdentityHashMap<>();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   376
    // Local variable type mapping at the currently evaluated point. No map instance is ever modified; setLvarType() always
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   377
    // allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   378
    // value.
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   379
    private Map<Symbol, LvarType> localVariableTypes = Collections.emptyMap();
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   380
    // Set of symbols whose lexical scope has already ended.
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   381
    private final Set<Symbol> invalidatedSymbols = new HashSet<>();
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   382
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   383
    // Stack for evaluated expression types.
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   384
    private final Deque<LvarType> typeStack = new ArrayDeque<>();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   385
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   386
    // Whether the current point in the AST is reachable code
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   387
    private boolean reachable = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   388
    // Return type of the function
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   389
    private Type returnType = Type.UNKNOWN;
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
   390
    // Synthetic return node that we must insert at the end of the function if it's end is reachable.
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
   391
    private ReturnNode syntheticReturn;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   392
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   393
    private boolean alreadyEnteredTopLevelFunction;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   394
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   395
    // LvarType and conversion information gathered during the top-down pass; applied to nodes in the bottom-up pass.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   396
    private final Map<JoinPredecessor, LocalVariableConversion> localVariableConversions = new IdentityHashMap<>();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   397
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   398
    private final Map<IdentNode, LvarType> identifierLvarTypes = new IdentityHashMap<>();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   399
    private final Map<Symbol, SymbolConversions> symbolConversions = new IdentityHashMap<>();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   400
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   401
    // Stack of open labels for starts of catch blocks, one for every currently traversed try block; for inserting
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   402
    // control flow edges to them. Note that we currently don't insert actual control flow edges, but instead edges that
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   403
    // help us with type calculations. This means that some operations that can result in an exception being thrown
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   404
    // aren't considered (function calls, side effecting property getters and setters etc.), while some operations that
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   405
    // don't result in control flow transfers do originate an edge to the catch blocks (namely, assignments to local
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   406
    // variables).
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   407
    private final Deque<Label> catchLabels = new ArrayDeque<>();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   408
47276
bfa048898f11 8187962: Optimistic types ignore JavaAdapter return types
hannesw
parents: 47216
diff changeset
   409
    private LocalVariableTypesCalculator(final Compiler compiler) {
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
   410
        this.compiler = compiler;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   411
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   412
47276
bfa048898f11 8187962: Optimistic types ignore JavaAdapter return types
hannesw
parents: 47216
diff changeset
   413
    LocalVariableTypesCalculator(final Compiler compiler, final Type returnType) {
bfa048898f11 8187962: Optimistic types ignore JavaAdapter return types
hannesw
parents: 47216
diff changeset
   414
        this(compiler);
bfa048898f11 8187962: Optimistic types ignore JavaAdapter return types
hannesw
parents: 47216
diff changeset
   415
        this.returnType = returnType;
bfa048898f11 8187962: Optimistic types ignore JavaAdapter return types
hannesw
parents: 47216
diff changeset
   416
    }
bfa048898f11 8187962: Optimistic types ignore JavaAdapter return types
hannesw
parents: 47216
diff changeset
   417
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   418
    private JumpTarget createJumpTarget(final Label label) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   419
        assert !jumpTargets.containsKey(label);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   420
        final JumpTarget jumpTarget = new JumpTarget();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   421
        jumpTargets.put(label, jumpTarget);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   422
        return jumpTarget;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   423
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   424
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   425
    private void doesNotContinueSequentially() {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   426
        reachable = false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   427
        localVariableTypes = Collections.emptyMap();
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   428
        assertTypeStackIsEmpty();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   429
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   430
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   431
    private boolean pushExpressionType(final Expression expr) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   432
        typeStack.push(toLvarType(expr.getType()));
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   433
        return false;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   434
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   435
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   436
    @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   437
    public boolean enterAccessNode(final AccessNode accessNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   438
        visitExpression(accessNode.getBase());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   439
        return pushExpressionType(accessNode);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   440
    }
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   441
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   442
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   443
    public boolean enterBinaryNode(final BinaryNode binaryNode) {
27969
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   444
        // NOTE: regardless of operator's lexical associativity, lhs is always evaluated first.
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   445
        final Expression lhs = binaryNode.lhs();
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   446
        final LvarType lhsType;
30392
dc4a419b2982 8079362: Enforce best practices for Node token API usage
attila
parents: 29404
diff changeset
   447
        if (!(lhs instanceof IdentNode && binaryNode.isTokenType(TokenType.ASSIGN))) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   448
            lhsType = visitExpression(lhs);
27969
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   449
        } else {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   450
            // Can't visit IdentNode on LHS of a simple assignment, as visits imply use, and this is def.
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   451
            // The type is irrelevant, as only RHS is used to determine the type anyway.
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   452
            lhsType = LvarType.UNDEFINED;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   453
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   454
27969
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   455
        final boolean isLogical = binaryNode.isLogical();
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   456
        final Label joinLabel = isLogical ? new Label("") : null;
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   457
        if(isLogical) {
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   458
            jumpToLabel((JoinPredecessor)lhs, joinLabel);
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   459
        }
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   460
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   461
        final Expression rhs = binaryNode.rhs();
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   462
        final LvarType rhsType = visitExpression(rhs);
27969
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   463
        if(isLogical) {
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   464
            jumpToLabel((JoinPredecessor)rhs, joinLabel);
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   465
        }
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   466
        joinOnLabel(joinLabel);
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
   467
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   468
        final LvarType type = toLvarType(binaryNode.setOperands(lhsType.typeExpression, rhsType.typeExpression).getType());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   469
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   470
        if(binaryNode.isAssignment() && lhs instanceof IdentNode) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   471
            if(binaryNode.isSelfModifying()) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   472
                onSelfAssignment((IdentNode)lhs, type);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   473
            } else {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   474
                onAssignment((IdentNode)lhs, type);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   475
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   476
        }
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   477
        typeStack.push(type);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   478
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   479
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   480
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   481
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   482
    public boolean enterBlock(final Block block) {
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   483
        boolean cloned = false;
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
   484
        for(final Symbol symbol: block.getSymbols()) {
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   485
            if(symbol.isBytecodeLocal()) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   486
                if (getLocalVariableTypeOrNull(symbol) == null) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   487
                    if (!cloned) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   488
                        cloneOrNewLocalVariableTypes();
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   489
                        cloned = true;
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   490
                    }
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   491
                    localVariableTypes.put(symbol, LvarType.UNDEFINED);
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   492
                }
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   493
                // In case we're repeating analysis of a lexical scope (e.g. it's in a loop),
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   494
                // make sure all symbols lexically scoped by the block become valid again.
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
   495
                invalidatedSymbols.remove(symbol);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   496
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   497
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   498
        return true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   499
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   500
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   501
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   502
    public boolean enterBreakNode(final BreakNode breakNode) {
26889
dba314d7a634 8059371: Code duplication in handling of break and continue
attila
parents: 26766
diff changeset
   503
        return enterJumpStatement(breakNode);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   504
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   505
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   506
    @Override
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   507
    public boolean enterCallNode(final CallNode callNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   508
        visitExpression(callNode.getFunction());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   509
        visitExpressions(callNode.getArgs());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   510
        final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   511
        if (evalArgs != null) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   512
            visitExpressions(evalArgs.getArgs());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   513
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   514
        return pushExpressionType(callNode);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   515
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   516
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   517
    @Override
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   518
    public boolean enterContinueNode(final ContinueNode continueNode) {
26889
dba314d7a634 8059371: Code duplication in handling of break and continue
attila
parents: 26766
diff changeset
   519
        return enterJumpStatement(continueNode);
dba314d7a634 8059371: Code duplication in handling of break and continue
attila
parents: 26766
diff changeset
   520
    }
dba314d7a634 8059371: Code duplication in handling of break and continue
attila
parents: 26766
diff changeset
   521
dba314d7a634 8059371: Code duplication in handling of break and continue
attila
parents: 26766
diff changeset
   522
    private boolean enterJumpStatement(final JumpStatement jump) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   523
        if(!reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   524
            return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   525
        }
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   526
        assertTypeStackIsEmpty();
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
   527
        jumpToLabel(jump, jump.getTargetLabel(lc), getBreakTargetTypes(jump.getPopScopeLimit(lc)));
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   528
        doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   529
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   530
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   531
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   532
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   533
    protected boolean enterDefault(final Node node) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   534
        return reachable;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   535
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   536
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   537
    private void enterDoWhileLoop(final WhileNode loopNode) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   538
        assertTypeStackIsEmpty();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   539
        final JoinPredecessorExpression test = loopNode.getTest();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   540
        final Block body = loopNode.getBody();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   541
        final Label continueLabel = loopNode.getContinueLabel();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   542
        final Label breakLabel = loopNode.getBreakLabel();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   543
        final Map<Symbol, LvarType> beforeLoopTypes = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   544
        final Label repeatLabel = new Label("");
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   545
        for(;;) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   546
            jumpToLabel(loopNode, repeatLabel, beforeLoopTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   547
            final Map<Symbol, LvarType> beforeRepeatTypes = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   548
            body.accept(this);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   549
            if(reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   550
                jumpToLabel(body, continueLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   551
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   552
            joinOnLabel(continueLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   553
            if(!reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   554
                break;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   555
            }
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   556
            visitExpressionOnEmptyStack(test);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   557
            jumpToLabel(test, breakLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   558
            if(isAlwaysFalse(test)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   559
                break;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   560
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   561
            jumpToLabel(test, repeatLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   562
            joinOnLabel(repeatLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   563
            if(localVariableTypes.equals(beforeRepeatTypes)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   564
                break;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   565
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   566
            resetJoinPoint(continueLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   567
            resetJoinPoint(breakLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   568
            resetJoinPoint(repeatLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   569
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   570
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   571
        if(isAlwaysTrue(test)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   572
            doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   573
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   574
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   575
        leaveBreakable(loopNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   576
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   577
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   578
    @Override
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   579
    public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   580
        if (reachable) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   581
            visitExpressionOnEmptyStack(expressionStatement.getExpression());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   582
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   583
        return false;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   584
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   585
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   586
    private void assertTypeStackIsEmpty() {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   587
        assert typeStack.isEmpty();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   588
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   589
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   590
    @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   591
    protected Node leaveDefault(final Node node) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   592
        assert !(node instanceof Expression); // All expressions were handled
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   593
        assert !(node instanceof Statement) || typeStack.isEmpty(); // No statements leave with a non-empty stack
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   594
        return node;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   595
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   596
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   597
    private LvarType visitExpressionOnEmptyStack(final Expression expr) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   598
        assertTypeStackIsEmpty();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   599
        return visitExpression(expr);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   600
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   601
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   602
    private LvarType visitExpression(final Expression expr) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   603
        final int stackSize = typeStack.size();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   604
        expr.accept(this);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   605
        assert typeStack.size() == stackSize + 1;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   606
        return typeStack.pop();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   607
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   608
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   609
    private void visitExpressions(final List<Expression> exprs) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   610
        for(final Expression expr: exprs) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   611
            if (expr != null) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   612
                visitExpression(expr);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   613
            }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   614
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   615
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   616
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   617
    @Override
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   618
    public boolean enterForNode(final ForNode forNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   619
        if(!reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   620
            return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   621
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   622
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   623
        final Expression init = forNode.getInit();
36696
39ff39c8e396 8151700: Add support for ES6 for-of
hannesw
parents: 34732
diff changeset
   624
        if(forNode.isForInOrOf()) {
26507
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   625
            final JoinPredecessorExpression iterable = forNode.getModify();
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   626
            visitExpression(iterable);
26507
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   627
            enterTestFirstLoop(forNode, null, init,
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   628
                    // If we're iterating over property names, and we can discern from the runtime environment
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   629
                    // of the compilation that the object being iterated over must use strings for property
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   630
                    // names (e.g., it is a native JS object or array), then we'll not bother trying to treat
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   631
                    // the property names optimistically.
26766
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
   632
                    !compiler.useOptimisticTypes() || (!forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression())));
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   633
        } else {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   634
            if(init != null) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   635
                visitExpressionOnEmptyStack(init);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   636
            }
26507
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   637
            enterTestFirstLoop(forNode, forNode.getModify(), null, false);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   638
        }
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   639
        assertTypeStackIsEmpty();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   640
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   641
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   642
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   643
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   644
    public boolean enterFunctionNode(final FunctionNode functionNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   645
        if(alreadyEnteredTopLevelFunction) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   646
            typeStack.push(LvarType.OBJECT);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   647
            return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   648
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   649
        int pos = 0;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   650
        if(!functionNode.isVarArg()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   651
            for (final IdentNode param : functionNode.getParameters()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   652
                final Symbol symbol = param.getSymbol();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   653
                // Parameter is not necessarily bytecode local as it can be scoped due to nested context use, but it
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   654
                // must have a slot if we aren't in a function with vararg signature.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   655
                assert symbol.hasSlot();
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
   656
                final Type callSiteParamType = compiler.getParamType(functionNode, pos);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   657
                final LvarType paramType = callSiteParamType == null ? LvarType.OBJECT : toLvarType(callSiteParamType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   658
                setType(symbol, paramType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   659
                // Make sure parameter slot for its incoming value is not marked dead. NOTE: this is a heuristic. Right
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   660
                // now, CodeGenerator.expandParameters() relies on the fact that every parameter's final slot width will
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   661
                // be at least the same as incoming width, therefore even if a parameter is never read, we'll still keep
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   662
                // its slot.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   663
                symbolIsUsed(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   664
                setIdentifierLvarType(param, paramType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   665
                pos++;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   666
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   667
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   668
        setCompilerConstantAsObject(functionNode, CompilerConstants.THIS);
25238
28476bdc25ce 8047728: (function(x){var o={x:0}; with(o){delete x} return o.x})() evaluates to 0 instead of undefined
sundar
parents: 25234
diff changeset
   669
25240
f92c14b1ca11 8047959: bindings created for declarations in eval code are not mutable
sundar
parents: 25238
diff changeset
   670
        // TODO: coarse-grained. If we wanted to solve it completely precisely,
25238
28476bdc25ce 8047728: (function(x){var o={x:0}; with(o){delete x} return o.x})() evaluates to 0 instead of undefined
sundar
parents: 25234
diff changeset
   671
        // we'd also need to push/pop its type when handling WithNode (so that
28476bdc25ce 8047728: (function(x){var o={x:0}; with(o){delete x} return o.x})() evaluates to 0 instead of undefined
sundar
parents: 25234
diff changeset
   672
        // it can go back to undefined after a 'with' block.
28476bdc25ce 8047728: (function(x){var o={x:0}; with(o){delete x} return o.x})() evaluates to 0 instead of undefined
sundar
parents: 25234
diff changeset
   673
        if(functionNode.hasScopeBlock() || functionNode.needsParentScope()) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   674
            setCompilerConstantAsObject(functionNode, CompilerConstants.SCOPE);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   675
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   676
        if(functionNode.needsCallee()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   677
            setCompilerConstantAsObject(functionNode, CompilerConstants.CALLEE);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   678
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   679
        if(functionNode.needsArguments()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   680
            setCompilerConstantAsObject(functionNode, CompilerConstants.ARGUMENTS);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   681
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   682
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   683
        alreadyEnteredTopLevelFunction = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   684
        return true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   685
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   686
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   687
    @Override
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   688
    public boolean enterGetSplitState(final GetSplitState getSplitState) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   689
        return pushExpressionType(getSplitState);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   690
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   691
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   692
    @Override
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   693
    public boolean enterIdentNode(final IdentNode identNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   694
        final Symbol symbol = identNode.getSymbol();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   695
        if(symbol.isBytecodeLocal()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   696
            symbolIsUsed(symbol);
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   697
            final LvarType type = getLocalVariableType(symbol);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   698
            setIdentifierLvarType(identNode, type);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   699
            typeStack.push(type);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   700
        } else {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   701
            pushExpressionType(identNode);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   702
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   703
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   704
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   705
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   706
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   707
    public boolean enterIfNode(final IfNode ifNode) {
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   708
        processIfNode(ifNode);
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   709
        return false;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   710
    }
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   711
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   712
    private void processIfNode(final IfNode ifNode) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   713
        if(!reachable) {
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   714
            return;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   715
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   716
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   717
        final Expression test = ifNode.getTest();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   718
        final Block pass = ifNode.getPass();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   719
        final Block fail = ifNode.getFail();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   720
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   721
        visitExpressionOnEmptyStack(test);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   722
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   723
        final Map<Symbol, LvarType> passLvarTypes;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   724
        final boolean reachableFromPass;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   725
        final boolean isTestAlwaysTrue = isAlwaysTrue(test);
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   726
        if(isAlwaysFalse(test)) {
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   727
            passLvarTypes = null;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   728
            reachableFromPass = false;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   729
        } else {
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   730
            final Map<Symbol, LvarType> afterTestLvarTypes = localVariableTypes;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   731
            pass.accept(this);
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   732
            assertTypeStackIsEmpty();
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   733
            if (isTestAlwaysTrue) {
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   734
                return;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   735
            }
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   736
            passLvarTypes = localVariableTypes;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   737
            reachableFromPass = reachable;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   738
            localVariableTypes = afterTestLvarTypes;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   739
            reachable = true;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   740
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   741
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   742
        // If we get here, then we need to consider the case where pass block is not executed
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   743
        assert !isTestAlwaysTrue;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   744
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   745
        if (fail != null) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   746
            fail.accept(this);
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   747
            assertTypeStackIsEmpty();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   748
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   749
29404
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   750
        if(reachable) {
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   751
            if(reachableFromPass) {
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   752
                final Map<Symbol, LvarType> failLvarTypes = localVariableTypes;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   753
                localVariableTypes = getUnionTypes(passLvarTypes, failLvarTypes);
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   754
                setConversion(pass, passLvarTypes, localVariableTypes);
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   755
                // IfNode itself is associated with conversions that might need to be performed after the test if
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   756
                // there's no else branch. E.g.
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   757
                // if(x = 1, cond) { x = 1.0 } must widen "x = 1" to a double.
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   758
                setConversion(fail != null ? fail : ifNode, failLvarTypes, localVariableTypes);
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   759
            }
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   760
        } else if (reachableFromPass) {
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   761
            assert passLvarTypes != null;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   762
            localVariableTypes = passLvarTypes;
d9023e6faff1 8074487: Static analysis of IfNode should consider terminating branches
attila
parents: 29283
diff changeset
   763
            reachable = true;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   764
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   765
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   766
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   767
    @Override
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   768
    public boolean enterIndexNode(final IndexNode indexNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   769
        visitExpression(indexNode.getBase());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   770
        visitExpression(indexNode.getIndex());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   771
        return pushExpressionType(indexNode);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   772
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   773
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   774
    @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   775
    public boolean enterJoinPredecessorExpression(final JoinPredecessorExpression joinExpr) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   776
        final Expression expr = joinExpr.getExpression();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   777
        if (expr != null) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   778
            expr.accept(this);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   779
        } else {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   780
            typeStack.push(LvarType.UNDEFINED);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   781
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   782
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   783
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   784
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   785
    @Override
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
   786
    public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
   787
        return enterJumpStatement(jumpToInlinedFinally);
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
   788
    }
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
   789
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
   790
    @Override
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   791
    public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   792
        if (literalNode instanceof ArrayLiteralNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   793
            final List<Expression> expressions = ((ArrayLiteralNode)literalNode).getElementExpressions();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   794
            if (expressions != null) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   795
                visitExpressions(expressions);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   796
            }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   797
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   798
        pushExpressionType(literalNode);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   799
        return false;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   800
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   801
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   802
    @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   803
    public boolean enterObjectNode(final ObjectNode objectNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   804
        for(final PropertyNode propertyNode: objectNode.getElements()) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   805
            // Avoid falsely adding property keys to the control flow graph
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   806
            final Expression value = propertyNode.getValue();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   807
            if (value != null) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   808
                visitExpression(value);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   809
            }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   810
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   811
        return pushExpressionType(objectNode);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   812
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   813
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   814
    @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   815
    public boolean enterPropertyNode(final PropertyNode propertyNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   816
        // Property nodes are only accessible through object literals, and we handled that case above
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   817
        throw new AssertionError();
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   818
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   819
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   820
    @Override
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   821
    public boolean enterReturnNode(final ReturnNode returnNode) {
26766
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
   822
        if(!reachable) {
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
   823
            return false;
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
   824
        }
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
   825
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   826
        final Expression returnExpr = returnNode.getExpression();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   827
        final Type returnExprType;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   828
        if(returnExpr != null) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   829
            returnExprType = visitExpressionOnEmptyStack(returnExpr).type;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   830
        } else {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   831
            assertTypeStackIsEmpty();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   832
            returnExprType = Type.UNDEFINED;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   833
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   834
        returnType = Type.widestReturnType(returnType, returnExprType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   835
        doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   836
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   837
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   838
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   839
    @Override
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   840
    public boolean enterRuntimeNode(final RuntimeNode runtimeNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   841
        visitExpressions(runtimeNode.getArgs());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   842
        return pushExpressionType(runtimeNode);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   843
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   844
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   845
    @Override
27206
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents: 26889
diff changeset
   846
    public boolean enterSplitReturn(final SplitReturn splitReturn) {
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents: 26889
diff changeset
   847
        doesNotContinueSequentially();
d4a707c9db5a 8059844: Implement optimistic splitter
attila
parents: 26889
diff changeset
   848
        return false;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   849
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   850
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   851
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   852
    public boolean enterSwitchNode(final SwitchNode switchNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   853
        if(!reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   854
            return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   855
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   856
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   857
        visitExpressionOnEmptyStack(switchNode.getExpression());
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   858
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   859
        final List<CaseNode> cases = switchNode.getCases();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   860
        if(cases.isEmpty()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   861
            return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   862
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   863
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   864
        // Control flow is different for all-integer cases where we dispatch by switch table, and for all other cases
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   865
        // where we do sequential comparison. Note that CaseNode objects act as join points.
27970
7b0048b90967 8066225: NPE in MethodEmitter with duplicate integer switch cases
attila
parents: 27969
diff changeset
   866
        final boolean isInteger = switchNode.isUniqueInteger();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   867
        final Label breakLabel = switchNode.getBreakLabel();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   868
        final boolean hasDefault = switchNode.getDefaultCase() != null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   869
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   870
        boolean tagUsed = false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   871
        for(final CaseNode caseNode: cases) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   872
            final Expression test = caseNode.getTest();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   873
            if(!isInteger && test != null) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   874
                visitExpressionOnEmptyStack(test);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   875
                if(!tagUsed) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   876
                    symbolIsUsed(switchNode.getTag(), LvarType.OBJECT);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   877
                    tagUsed = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   878
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   879
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   880
            // CaseNode carries the conversions that need to be performed on its entry from the test.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   881
            // CodeGenerator ensures these are only emitted when arriving on the branch and not through a
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   882
            // fallthrough.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   883
            jumpToLabel(caseNode, caseNode.getBody().getEntryLabel());
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   884
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   885
        if(!hasDefault) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   886
            // No default case means we can arrive at the break label without entering any cases. In that case
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   887
            // SwitchNode will carry the conversions that need to be performed before it does that jump.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   888
            jumpToLabel(switchNode, breakLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   889
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   890
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   891
        // All cases are arrived at through jumps
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   892
        doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   893
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   894
        Block previousBlock = null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   895
        for(final CaseNode caseNode: cases) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   896
            final Block body = caseNode.getBody();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   897
            final Label entryLabel = body.getEntryLabel();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   898
            if(previousBlock != null && reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   899
                jumpToLabel(previousBlock, entryLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   900
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   901
            joinOnLabel(entryLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   902
            assert reachable == true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   903
            body.accept(this);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   904
            previousBlock = body;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   905
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   906
        if(previousBlock != null && reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   907
            jumpToLabel(previousBlock, breakLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   908
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   909
        leaveBreakable(switchNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   910
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   911
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   912
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   913
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   914
    public boolean enterTernaryNode(final TernaryNode ternaryNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   915
        final Expression test = ternaryNode.getTest();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   916
        final Expression trueExpr = ternaryNode.getTrueExpression();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   917
        final Expression falseExpr = ternaryNode.getFalseExpression();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   918
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   919
        visitExpression(test);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   920
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   921
        final Map<Symbol, LvarType> testExitLvarTypes = localVariableTypes;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   922
        final LvarType trueType;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   923
        if(!isAlwaysFalse(test)) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   924
            trueType = visitExpression(trueExpr);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   925
        } else {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   926
            trueType = null;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   927
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   928
        final Map<Symbol, LvarType> trueExitLvarTypes = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   929
        localVariableTypes = testExitLvarTypes;
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   930
        final LvarType falseType;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   931
        if(!isAlwaysTrue(test)) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   932
            falseType = visitExpression(falseExpr);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   933
        } else {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   934
            falseType = null;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   935
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   936
        final Map<Symbol, LvarType> falseExitLvarTypes = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   937
        localVariableTypes = getUnionTypes(trueExitLvarTypes, falseExitLvarTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   938
        setConversion((JoinPredecessor)trueExpr, trueExitLvarTypes, localVariableTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   939
        setConversion((JoinPredecessor)falseExpr, falseExitLvarTypes, localVariableTypes);
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   940
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   941
        typeStack.push(trueType != null ? falseType != null ? widestLvarType(trueType, falseType) : trueType : assertNotNull(falseType));
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   942
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   943
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   944
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   945
    private static <T> T assertNotNull(final T t) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   946
        assert t != null;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   947
        return t;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   948
    }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   949
26507
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   950
    private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify,
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   951
            final Expression iteratorValues, final boolean iteratorValuesAreObject) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   952
        final JoinPredecessorExpression test = loopNode.getTest();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   953
        if(isAlwaysFalse(test)) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   954
            visitExpressionOnEmptyStack(test);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   955
            return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   956
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   957
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   958
        final Label continueLabel = loopNode.getContinueLabel();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   959
        final Label breakLabel = loopNode.getBreakLabel();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   960
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   961
        final Label repeatLabel = modify == null ? continueLabel : new Label("");
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   962
        final Map<Symbol, LvarType> beforeLoopTypes = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   963
        for(;;) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   964
            jumpToLabel(loopNode, repeatLabel, beforeLoopTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   965
            final Map<Symbol, LvarType> beforeRepeatTypes = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   966
            if(test != null) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   967
                visitExpressionOnEmptyStack(test);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   968
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   969
            if(!isAlwaysTrue(test)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   970
                jumpToLabel(test, breakLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   971
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   972
            if(iteratorValues instanceof IdentNode) {
26507
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   973
                final IdentNode ident = (IdentNode)iteratorValues;
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   974
                // Receives iterator values; the optimistic type of the iterator values is tracked on the
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   975
                // identifier, but we override optimism if it's known that the object being iterated over will
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   976
                // never have primitive property names.
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   977
                onAssignment(ident, iteratorValuesAreObject ? LvarType.OBJECT :
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
   978
                    toLvarType(compiler.getOptimisticType(ident)));
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   979
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   980
            final Block body = loopNode.getBody();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   981
            body.accept(this);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   982
            if(reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   983
                jumpToLabel(body, continueLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   984
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   985
            joinOnLabel(continueLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   986
            if(!reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   987
                break;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   988
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   989
            if(modify != null) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
   990
                visitExpressionOnEmptyStack(modify);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   991
                jumpToLabel(modify, repeatLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   992
                joinOnLabel(repeatLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   993
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   994
            if(localVariableTypes.equals(beforeRepeatTypes)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   995
                break;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   996
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   997
            // Reset the join points and repeat the analysis
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   998
            resetJoinPoint(continueLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
   999
            resetJoinPoint(breakLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1000
            resetJoinPoint(repeatLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1001
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1002
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1003
        if(isAlwaysTrue(test) && iteratorValues == null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1004
            doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1005
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1006
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1007
        leaveBreakable(loopNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1008
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1009
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1010
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1011
    public boolean enterThrowNode(final ThrowNode throwNode) {
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1012
        if(!reachable) {
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1013
            return false;
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1014
        }
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1015
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1016
        visitExpressionOnEmptyStack(throwNode.getExpression());
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1017
        jumpToCatchBlock(throwNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1018
        doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1019
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1020
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1021
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1022
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1023
    public boolean enterTryNode(final TryNode tryNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1024
        if(!reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1025
            return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1026
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1027
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1028
        // This is the label for the join point at the entry of the catch blocks.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1029
        final Label catchLabel = new Label("");
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1030
        catchLabels.push(catchLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1031
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1032
        // Presume that even the start of the try block can immediately go to the catch
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1033
        jumpToLabel(tryNode, catchLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1034
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1035
        final Block body = tryNode.getBody();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1036
        body.accept(this);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1037
        catchLabels.pop();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1038
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1039
        // Final exit label for the whole try/catch construct (after the try block and after all catches).
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1040
        final Label endLabel = new Label("");
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1041
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1042
        boolean canExit = false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1043
        if(reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1044
            jumpToLabel(body, endLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1045
            canExit = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1046
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1047
        doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1048
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1049
        for (final Block inlinedFinally : tryNode.getInlinedFinallies()) {
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1050
            final Block finallyBody = TryNode.getLabelledInlinedFinallyBlock(inlinedFinally);
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1051
            joinOnLabel(finallyBody.getEntryLabel());
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1052
            // NOTE: the jump to inlined finally can end up in dead code, so it is not necessarily reachable.
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1053
            if (reachable) {
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1054
                finallyBody.accept(this);
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1055
                // All inlined finallies end with a jump or a return
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1056
                assert !reachable;
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1057
            }
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1058
        }
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1059
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1060
        joinOnLabel(catchLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1061
        for(final CatchNode catchNode: tryNode.getCatches()) {
41983
eb674141ab03 8156615: Catch parameter can be a BindingPattern in ES6 mode
sdama
parents: 41981
diff changeset
  1062
            final IdentNode exception = catchNode.getExceptionIdentifier();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1063
            onAssignment(exception, LvarType.OBJECT);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1064
            final Expression condition = catchNode.getExceptionCondition();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1065
            if(condition != null) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1066
                visitExpression(condition);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1067
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1068
            final Map<Symbol, LvarType> afterConditionTypes = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1069
            final Block catchBody = catchNode.getBody();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1070
            // TODO: currently, we consider that the catch blocks are always reachable from the try block as currently
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1071
            // we lack enough analysis to prove that no statement before a break/continue/return in the try block can
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1072
            // throw an exception.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1073
            reachable = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1074
            catchBody.accept(this);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1075
            if(reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1076
                jumpToLabel(catchBody, endLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1077
                canExit = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1078
            }
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1079
            localVariableTypes = afterConditionTypes;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1080
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1081
        // NOTE: if we had one or more conditional catch blocks with no unconditional catch block following them, then
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1082
        // there will be an unconditional rethrow, so the join point can never be reached from the last
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1083
        // conditionExpression.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1084
        doesNotContinueSequentially();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1085
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1086
        if(canExit) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1087
            joinOnLabel(endLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1088
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1089
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1090
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1091
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1092
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1093
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1094
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1095
    public boolean enterUnaryNode(final UnaryNode unaryNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1096
        final Expression expr = unaryNode.getExpression();
48354
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1097
        final LvarType unaryType;
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1098
        if (unaryNode.tokenType() == TokenType.DELETE && expr instanceof IdentNode) {
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1099
            // not visiting deleted identifiers; they don't count as use
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1100
            unaryType = toLvarType(unaryNode.getType());
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1101
        } else {
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1102
            unaryType = toLvarType(unaryNode.setExpression(visitExpression(expr).typeExpression).getType());
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1103
            if (unaryNode.isSelfModifying() && expr instanceof IdentNode) {
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1104
                onSelfAssignment((IdentNode) expr, unaryType);
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1105
            }
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1106
        }
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1107
        typeStack.push(unaryType);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1108
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1109
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1110
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1111
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1112
    public boolean enterVarNode(final VarNode varNode) {
26766
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
  1113
        if (!reachable) {
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
  1114
            return false;
523242aab20f 8058561: NPE in LocalVariableTypesCalculator
attila
parents: 26507
diff changeset
  1115
        }
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1116
        final Expression init = varNode.getInit();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1117
        if(init != null) {
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1118
            onAssignment(varNode.getName(), visitExpression(init));
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1119
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1120
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1121
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1122
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1123
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1124
    public boolean enterWhileNode(final WhileNode whileNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1125
        if(!reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1126
            return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1127
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1128
        if(whileNode.isDoWhile()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1129
            enterDoWhileLoop(whileNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1130
        } else {
26507
9d6e3ec59878 8034954: Optimistic iteration in for-in and for-each
attila
parents: 25865
diff changeset
  1131
            enterTestFirstLoop(whileNode, null, null, false);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1132
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1133
        return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1134
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1135
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1136
    @Override
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1137
    public boolean enterWithNode(final WithNode withNode) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1138
        if (reachable) {
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1139
            visitExpression(withNode.getExpression());
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1140
            withNode.getBody().accept(this);
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1141
        }
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1142
        return false;
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1143
    };
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1144
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1145
    private Map<Symbol, LvarType> getBreakTargetTypes(final LexicalContextNode target) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1146
        // Remove symbols defined in the the blocks that are being broken out of.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1147
        Map<Symbol, LvarType> types = localVariableTypes;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1148
        for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1149
            final LexicalContextNode node = it.next();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1150
            if(node instanceof Block) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1151
                for(final Symbol symbol: ((Block)node).getSymbols()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1152
                    if(localVariableTypes.containsKey(symbol)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1153
                        if(types == localVariableTypes) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1154
                            types = cloneMap(localVariableTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1155
                        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1156
                        types.remove(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1157
                    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1158
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1159
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1160
            if(node == target) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1161
                break;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1162
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1163
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1164
        return types;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1165
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1166
27969
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1167
    /**
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1168
     * Returns the current type of the local variable represented by the symbol. This is the most strict of all
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1169
     * {@code getLocalVariableType*} methods, as it will throw an assertion if the type is null. Therefore, it is only
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1170
     * safe to be invoked on symbols known to be bytecode locals, and only after they have been initialized.
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1171
     * Regardless, it is recommended to use this method in majority of cases, as because of its strictness it is the
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1172
     * best suited for catching missing type calculation bugs early.
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1173
     * @param symbol a symbol representing a bytecode local variable.
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1174
     * @return the current type of the local variable represented by the symbol
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1175
     */
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1176
    private LvarType getLocalVariableType(final Symbol symbol) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1177
        final LvarType type = getLocalVariableTypeOrNull(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1178
        assert type != null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1179
        return type;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1180
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1181
27969
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1182
    /**
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1183
     * Gets the type for a variable represented by a symbol, or null if the type is not know. This is the least strict
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1184
     * of all local variable type getters, and as such its use is discouraged except in initialization scenarios (where
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1185
     * a just-defined symbol might still be null).
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1186
     * @param symbol the symbol
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1187
     * @return the current type for the symbol, or null if the type is not known either because the symbol has not been
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1188
     * initialized, or because the symbol does not represent a bytecode local variable.
c03b64ccbd0f 8066227: CodeGenerator load unitialized slot
attila
parents: 27361
diff changeset
  1189
     */
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1190
    private LvarType getLocalVariableTypeOrNull(final Symbol symbol) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1191
        return localVariableTypes.get(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1192
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1193
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1194
    private JumpTarget getOrCreateJumpTarget(final Label label) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1195
        JumpTarget jumpTarget = jumpTargets.get(label);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1196
        if(jumpTarget == null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1197
            jumpTarget = createJumpTarget(label);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1198
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1199
        return jumpTarget;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1200
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1201
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1202
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1203
    /**
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1204
     * If there's a join point associated with a label, insert the join point into the flow.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1205
     * @param label the label to insert a join point for.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1206
     */
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1207
    private void joinOnLabel(final Label label) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1208
        final JumpTarget jumpTarget = jumpTargets.remove(label);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1209
        if(jumpTarget == null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1210
            return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1211
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1212
        assert !jumpTarget.origins.isEmpty();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1213
        reachable = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1214
        localVariableTypes = getUnionTypes(jumpTarget.types, localVariableTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1215
        for(final JumpOrigin jumpOrigin: jumpTarget.origins) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1216
            setConversion(jumpOrigin.node, jumpOrigin.types, localVariableTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1217
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1218
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1219
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1220
    /**
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1221
     * If we're in a try/catch block, add an edge from the specified node to the try node's pre-catch label.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1222
     */
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1223
    private void jumpToCatchBlock(final JoinPredecessor jumpOrigin) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1224
        final Label currentCatchLabel = catchLabels.peek();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1225
        if(currentCatchLabel != null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1226
            jumpToLabel(jumpOrigin, currentCatchLabel);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1227
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1228
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1229
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1230
    private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1231
        jumpToLabel(jumpOrigin, label, localVariableTypes);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1232
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1233
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1234
    private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label, final Map<Symbol, LvarType> types) {
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1235
        getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types, this);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1236
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1237
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1238
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1239
    public Node leaveBlock(final Block block) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1240
        if(lc.isFunctionBody()) {
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1241
            if(reachable) {
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1242
                // reachable==true means we can reach the end of the function without an explicit return statement. We
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1243
                // need to insert a synthetic one then. This logic used to be in Lower.leaveBlock(), but Lower's
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1244
                // reachability analysis (through Terminal.isTerminal() flags) is not precise enough so
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1245
                // Lower$BlockLexicalContext.afterSetStatements will sometimes think the control flow terminates even
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1246
                // when it didn't. Example: function() { switch((z)) { default: {break; } throw x; } }.
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1247
                createSyntheticReturn(block);
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1248
                assert !reachable;
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1249
            }
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1250
            // We must calculate the return type here (and not in leaveFunctionNode) as it can affect the liveness of
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1251
            // the :return symbol and thus affect conversion type liveness calculations for it.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1252
            calculateReturnType();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1253
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1254
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1255
        boolean cloned = false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1256
        for(final Symbol symbol: block.getSymbols()) {
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1257
            if(symbol.hasSlot()) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1258
                // Invalidate the symbol when its defining block ends
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1259
                if (symbol.isBytecodeLocal()) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1260
                    if(localVariableTypes.containsKey(symbol)) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1261
                        if(!cloned) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1262
                            localVariableTypes = cloneMap(localVariableTypes);
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1263
                            cloned = true;
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1264
                        }
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1265
                    }
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1266
                    invalidateSymbol(symbol);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1267
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1268
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1269
                final SymbolConversions conversions = symbolConversions.get(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1270
                if(conversions != null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1271
                    // Potentially make some currently dead types live if they're needed as a source of a type
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1272
                    // conversion at a join.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1273
                    conversions.calculateTypeLiveness(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1274
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1275
                if(symbol.slotCount() == 0) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1276
                    // This is a local variable that is never read. It won't need a slot.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1277
                    symbol.setNeedsSlot(false);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1278
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1279
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1280
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1281
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1282
        if(reachable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1283
            // TODO: this is totally backwards. Block should not be breakable, LabelNode should be breakable.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1284
            final LabelNode labelNode = lc.getCurrentBlockLabelNode();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1285
            if(labelNode != null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1286
                jumpToLabel(labelNode, block.getBreakLabel());
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1287
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1288
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1289
        leaveBreakable(block);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1290
        return block;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1291
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1292
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1293
    private void calculateReturnType() {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1294
        // NOTE: if return type is unknown, then the function does not explicitly return a value. Such a function under
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1295
        // ECMAScript rules returns Undefined, which has Type.OBJECT. We might consider an optimization in the future
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1296
        // where we can return void functions.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1297
        if(returnType.isUnknown()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1298
            returnType = Type.OBJECT;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1299
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1300
    }
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1301
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1302
    private void createSyntheticReturn(final Block body) {
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1303
        final FunctionNode functionNode = lc.getCurrentFunction();
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1304
        final long token = functionNode.getToken();
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1305
        final int finish = functionNode.getFinish();
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1306
        final List<Statement> statements = body.getStatements();
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1307
        final int lineNumber = statements.isEmpty() ? functionNode.getLineNumber() : statements.get(statements.size() - 1).getLineNumber();
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1308
        final IdentNode returnExpr;
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1309
        if(functionNode.isProgram()) {
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1310
            returnExpr = new IdentNode(token, finish, RETURN.symbolName()).setSymbol(getCompilerConstantSymbol(functionNode, RETURN));
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1311
        } else {
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1312
            returnExpr = null;
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1313
        }
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1314
        syntheticReturn = new ReturnNode(lineNumber, token, finish, returnExpr);
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1315
        syntheticReturn.accept(this);
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1316
    }
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1317
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1318
    /**
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1319
     * Leave a breakable node. If there's a join point associated with its break label (meaning there was at least one
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1320
     * break statement to the end of the node), insert the join point into the flow.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1321
     * @param breakable the breakable node being left.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1322
     */
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1323
    private void leaveBreakable(final BreakableNode breakable) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1324
        joinOnLabel(breakable.getBreakLabel());
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1325
        assertTypeStackIsEmpty();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1326
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1327
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1328
    @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1329
    public Node leaveFunctionNode(final FunctionNode functionNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1330
        // Sets the return type of the function and also performs the bottom-up pass of applying type and conversion
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1331
        // information to nodes as well as doing the calculation on nested functions as required.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1332
        FunctionNode newFunction = functionNode;
32888
24f99be3d5ab 8134502: introduce abstraction for basic NodeVisitor usage
attila
parents: 32692
diff changeset
  1333
        final SimpleNodeVisitor applyChangesVisitor = new SimpleNodeVisitor() {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1334
            private boolean inOuterFunction = true;
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1335
            private final Deque<JoinPredecessor> joinPredecessors = new ArrayDeque<>();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1336
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1337
            @Override
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1338
            protected boolean enterDefault(final Node node) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1339
                if(!inOuterFunction) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1340
                    return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1341
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1342
                if(node instanceof JoinPredecessor) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1343
                    joinPredecessors.push((JoinPredecessor)node);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1344
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1345
                return inOuterFunction;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1346
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1347
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1348
            @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1349
            public boolean enterFunctionNode(final FunctionNode fn) {
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1350
                if(compiler.isOnDemandCompilation()) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1351
                    // Only calculate nested function local variable types if we're doing eager compilation
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1352
                    return false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1353
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1354
                inOuterFunction = false;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1355
                return true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1356
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1357
48354
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1358
            @Override
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1359
            public boolean enterUnaryNode(final UnaryNode unaryNode) {
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1360
                // not visiting deleted identifiers; they don't count as use
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1361
                return !(unaryNode.tokenType() == TokenType.DELETE && unaryNode.getExpression() instanceof IdentNode);
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1362
            }
c96d4c720995 8193371: Use Dynalink REMOVE operation in Nashorn
attila
parents: 47276
diff changeset
  1363
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1364
            @SuppressWarnings("fallthrough")
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1365
            @Override
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1366
            public Node leaveBinaryNode(final BinaryNode binaryNode) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1367
                if(binaryNode.isComparison()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1368
                    final Expression lhs = binaryNode.lhs();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1369
                    final Expression rhs = binaryNode.rhs();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1370
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1371
                    final TokenType tt = binaryNode.tokenType();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1372
                    switch (tt) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1373
                    case EQ_STRICT:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1374
                    case NE_STRICT:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1375
                        // Specialize comparison with undefined
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1376
                        final Expression undefinedNode = createIsUndefined(binaryNode, lhs, rhs,
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1377
                                tt == TokenType.EQ_STRICT ? Request.IS_UNDEFINED : Request.IS_NOT_UNDEFINED);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1378
                        if(undefinedNode != binaryNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1379
                            return undefinedNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1380
                        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1381
                        // Specialize comparison of boolean with non-boolean
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1382
                        if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
29283
fb47e4d25a9f 8035712: Restore some of the RuntimeCallSite specializations
attila
parents: 28690
diff changeset
  1383
                            return new RuntimeNode(binaryNode);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1384
                        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1385
                        // fallthrough
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1386
                    default:
29283
fb47e4d25a9f 8035712: Restore some of the RuntimeCallSite specializations
attila
parents: 28690
diff changeset
  1387
                        if (lhs.getType().isObject() && rhs.getType().isObject()) {
fb47e4d25a9f 8035712: Restore some of the RuntimeCallSite specializations
attila
parents: 28690
diff changeset
  1388
                            return new RuntimeNode(binaryNode);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1389
                        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1390
                    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1391
                } else if(binaryNode.isOptimisticUndecidedType()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1392
                    // At this point, we can assign a static type to the optimistic binary ADD operator as now we know
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1393
                    // the types of its operands.
25829
1a5e1de71e57 8051439: Wrong type calculated for ADD operator with undefined operand
attila
parents: 25249
diff changeset
  1394
                    return binaryNode.decideType();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1395
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1396
                return binaryNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1397
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1398
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1399
            @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1400
            protected Node leaveDefault(final Node node) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1401
                if(node instanceof JoinPredecessor) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1402
                    final JoinPredecessor original = joinPredecessors.pop();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1403
                    assert original.getClass() == node.getClass() : original.getClass().getName() + "!=" + node.getClass().getName();
28690
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1404
                    final JoinPredecessor newNode = setLocalVariableConversion(original, (JoinPredecessor)node);
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1405
                    if (newNode instanceof LexicalContextNode) {
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1406
                        lc.replace((LexicalContextNode)node, (LexicalContextNode)newNode);
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1407
                    }
78317797ab62 8067139: Finally blocks inlined incorrectly
attila
parents: 28130
diff changeset
  1408
                    return (Node)newNode;
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1409
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1410
                return node;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1411
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1412
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1413
            @Override
25244
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1414
            public Node leaveBlock(final Block block) {
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1415
                if(inOuterFunction && syntheticReturn != null && lc.isFunctionBody()) {
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1416
                    final ArrayList<Statement> stmts = new ArrayList<>(block.getStatements());
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1417
                    stmts.add((ReturnNode)syntheticReturn.accept(this));
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1418
                    return block.setStatements(lc, stmts);
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1419
                }
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1420
                return super.leaveBlock(block);
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1421
            }
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1422
627d7e86f3b5 8047357: More precise synthetic return + unreachable throw
attila
parents: 25240
diff changeset
  1423
            @Override
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1424
            public Node leaveFunctionNode(final FunctionNode nestedFunctionNode) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1425
                inOuterFunction = true;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1426
                final FunctionNode newNestedFunction = (FunctionNode)nestedFunctionNode.accept(
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1427
                        new LocalVariableTypesCalculator(compiler));
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1428
                lc.replace(nestedFunctionNode, newNestedFunction);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1429
                return newNestedFunction;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1430
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1431
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1432
            @Override
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1433
            public Node leaveIdentNode(final IdentNode identNode) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1434
                final IdentNode original = (IdentNode)joinPredecessors.pop();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1435
                final Symbol symbol = identNode.getSymbol();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1436
                if(symbol == null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1437
                    assert identNode.isPropertyName();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1438
                    return identNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1439
                } else if(symbol.hasSlot()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1440
                    assert !symbol.isScope() || symbol.isParam(); // Only params can be slotted and scoped.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1441
                    assert original.getName().equals(identNode.getName());
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1442
                    final LvarType lvarType = identifierLvarTypes.remove(original);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1443
                    if(lvarType != null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1444
                        return setLocalVariableConversion(original, identNode.setType(lvarType.type));
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1445
                    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1446
                    // If there's no type, then the identifier must've been in unreachable code. In that case, it can't
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1447
                    // have assigned conversions either.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1448
                    assert localVariableConversions.get(original) == null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1449
                } else {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1450
                    assert identIsDeadAndHasNoLiveConversions(original);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1451
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1452
                return identNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1453
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1454
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1455
            @Override
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1456
            public Node leaveLiteralNode(final LiteralNode<?> literalNode) {
25234
e2f9df6b8797 8047078: Fuzzing bug discovered when ArrayLiteralNodes weren't immutable
lagergren
parents: 24759
diff changeset
  1457
                //for e.g. ArrayLiteralNodes the initial types may have been narrowed due to the
e2f9df6b8797 8047078: Fuzzing bug discovered when ArrayLiteralNodes weren't immutable
lagergren
parents: 24759
diff changeset
  1458
                //introduction of optimistic behavior - hence ensure that all literal nodes are
e2f9df6b8797 8047078: Fuzzing bug discovered when ArrayLiteralNodes weren't immutable
lagergren
parents: 24759
diff changeset
  1459
                //reinitialized
e2f9df6b8797 8047078: Fuzzing bug discovered when ArrayLiteralNodes weren't immutable
lagergren
parents: 24759
diff changeset
  1460
                return literalNode.initialize(lc);
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1461
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1462
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1463
            @Override
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1464
            public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1465
                final Request request = runtimeNode.getRequest();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1466
                final boolean isEqStrict = request == Request.EQ_STRICT;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1467
                if(isEqStrict || request == Request.NE_STRICT) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1468
                    return createIsUndefined(runtimeNode, runtimeNode.getArgs().get(0), runtimeNode.getArgs().get(1),
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1469
                            isEqStrict ? Request.IS_UNDEFINED : Request.IS_NOT_UNDEFINED);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1470
                }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1471
                return runtimeNode;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1472
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1473
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1474
            @SuppressWarnings("unchecked")
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1475
            private <T extends JoinPredecessor> T setLocalVariableConversion(final JoinPredecessor original, final T jp) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1476
                // NOTE: can't use Map.remove() as our copy-on-write AST semantics means some nodes appear twice (in
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1477
                // finally blocks), so we need to be able to access conversions for them multiple times.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1478
                return (T)jp.setLocalVariableConversion(lc, localVariableConversions.get(original));
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1479
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1480
        };
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1481
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1482
        newFunction = newFunction.setBody(lc, (Block)newFunction.getBody().accept(applyChangesVisitor));
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1483
        newFunction = newFunction.setReturnType(lc, returnType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1484
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1485
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1486
        newFunction = newFunction.setParameters(lc, newFunction.visitParameters(applyChangesVisitor));
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1487
        return newFunction;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1488
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1489
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1490
    private static Expression createIsUndefined(final Expression parent, final Expression lhs, final Expression rhs, final Request request) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1491
        if (isUndefinedIdent(lhs) || isUndefinedIdent(rhs)) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1492
            return new RuntimeNode(parent, request, lhs, rhs);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1493
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1494
        return parent;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1495
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1496
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1497
    private static boolean isUndefinedIdent(final Expression expr) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1498
        return expr instanceof IdentNode && "undefined".equals(((IdentNode)expr).getName());
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1499
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1500
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1501
    private boolean identIsDeadAndHasNoLiveConversions(final IdentNode identNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1502
        final LocalVariableConversion conv = localVariableConversions.get(identNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1503
        return conv == null || !conv.isLive();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1504
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1505
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1506
    private void onAssignment(final IdentNode identNode, final LvarType type) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1507
        final Symbol symbol = identNode.getSymbol();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1508
        assert symbol != null : identNode.getName();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1509
        if(!symbol.isBytecodeLocal()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1510
            return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1511
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1512
        assert type != null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1513
        final LvarType finalType;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1514
        if(type == LvarType.UNDEFINED && getLocalVariableType(symbol) != LvarType.UNDEFINED) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1515
            // Explicit assignment of a known undefined local variable to a local variable that is not undefined will
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1516
            // materialize that undefined in the assignment target. Note that assigning known undefined to known
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1517
            // undefined will *not* initialize the variable, e.g. "var x; var y = x;" compiles to no-op.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1518
            finalType = LvarType.OBJECT;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1519
            symbol.setFlag(Symbol.HAS_OBJECT_VALUE);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1520
        } else {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1521
            finalType = type;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1522
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1523
        setType(symbol, finalType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1524
        // Explicit assignment of an undefined value. Make sure the variable can store an object
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1525
        // TODO: if we communicated the fact to codegen with a flag on the IdentNode that the value was already
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1526
        // undefined before the assignment, we could just ignore it. In general, we could ignore an assignment if we
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1527
        // know that the value assigned is the same as the current value of the variable, but we'd need constant
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1528
        // propagation for that.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1529
        setIdentifierLvarType(identNode, finalType);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1530
        // For purposes of type calculation, we consider an assignment to a local variable to be followed by
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1531
        // the catch nodes of the current (if any) try block. This will effectively enforce that narrower
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1532
        // assignments to a local variable in a try block will also have to store a widened value as well. Code
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1533
        // within the try block will be able to keep loading the narrower value, but after the try block only
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1534
        // the widest value will remain live.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1535
        // Rationale for this is that if there's an use for that variable in any of the catch blocks, or
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1536
        // following the catch blocks, they must use the widest type.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1537
        // Example:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1538
        /*
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1539
            Originally:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1540
            ===========
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1541
            var x;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1542
            try {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1543
              x = 1; <-- stores into int slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1544
              f(x); <-- loads the int slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1545
              x = 3.14 <-- stores into the double slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1546
              f(x); <-- loads the double slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1547
              x = 1; <-- stores into int slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1548
              f(x); <-- loads the int slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1549
            } finally {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1550
              f(x); <-- loads the double slot for x, but can be reached by a path where x is int, so we need
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1551
                           to go back and ensure that double values are also always stored along with int
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1552
                           values.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1553
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1554
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1555
            After correction:
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1556
            =================
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1557
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1558
            var x;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1559
            try {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1560
              x = 1; <-- stores into both int and double slots for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1561
              f(x); <-- loads the int slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1562
              x = 3.14 <-- stores into the double slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1563
              f(x); <-- loads the double slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1564
              x = 1; <-- stores into both int and double slots for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1565
              f(x); <-- loads the int slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1566
            } finally {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1567
              f(x); <-- loads the double slot for x
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1568
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1569
         */
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1570
        jumpToCatchBlock(identNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1571
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1572
28130
433d6755c5f8 8067774: Use a stack of types when calculating local variable types
attila
parents: 27972
diff changeset
  1573
    private void onSelfAssignment(final IdentNode identNode, final LvarType type) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1574
        final Symbol symbol = identNode.getSymbol();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1575
        assert symbol != null : identNode.getName();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1576
        if(!symbol.isBytecodeLocal()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1577
            return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1578
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1579
        // Self-assignment never produce either a boolean or undefined
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1580
        assert type != null && type != LvarType.UNDEFINED && type != LvarType.BOOLEAN;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1581
        setType(symbol, type);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1582
        jumpToCatchBlock(identNode);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1583
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1584
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1585
    private void resetJoinPoint(final Label label) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1586
        jumpTargets.remove(label);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1587
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1588
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1589
    private void setCompilerConstantAsObject(final FunctionNode functionNode, final CompilerConstants cc) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1590
        final Symbol symbol = getCompilerConstantSymbol(functionNode, cc);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1591
        setType(symbol, LvarType.OBJECT);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1592
        // never mark compiler constants as dead
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1593
        symbolIsUsed(symbol);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1594
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1595
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1596
    private static Symbol getCompilerConstantSymbol(final FunctionNode functionNode, final CompilerConstants cc) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1597
        return functionNode.getBody().getExistingSymbol(cc.symbolName());
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1598
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1599
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1600
    private void setConversion(final JoinPredecessor node, final Map<Symbol, LvarType> branchLvarTypes, final Map<Symbol, LvarType> joinLvarTypes) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1601
        if(node == null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1602
            return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1603
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1604
        if(branchLvarTypes.isEmpty() || joinLvarTypes.isEmpty()) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1605
            localVariableConversions.remove(node);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1606
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1607
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1608
        LocalVariableConversion conversion = null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1609
        if(node instanceof IdentNode) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1610
            // conversions on variable assignment in try block are special cases, as they only apply to the variable
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1611
            // being assigned and all other conversions should be ignored.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1612
            final Symbol symbol = ((IdentNode)node).getSymbol();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1613
            conversion = createConversion(symbol, branchLvarTypes.get(symbol), joinLvarTypes, null);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1614
        } else {
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1615
            for(final Map.Entry<Symbol, LvarType> entry: branchLvarTypes.entrySet()) {
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1616
                final Symbol symbol = entry.getKey();
24759
31aed7d9c02a 8034206: Make parts of code pipeline reusable in order to facilitate faster warmup and faster lazy compilation.
lagergren
parents: 24751
diff changeset
  1617
                final LvarType branchLvarType = entry.getValue();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1618
                conversion = createConversion(symbol, branchLvarType, joinLvarTypes, conversion);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1619
            }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1620
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1621
        if(conversion != null) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1622
            localVariableConversions.put(node, conversion);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1623
        } else {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1624
            localVariableConversions.remove(node);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1625
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1626
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1627
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1628
    private void setIdentifierLvarType(final IdentNode identNode, final LvarType type) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1629
        assert type != null;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1630
        identifierLvarTypes.put(identNode, type);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1631
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1632
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1633
    /**
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1634
     * Marks a local variable as having a specific type from this point onward. Invoked by stores to local variables.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1635
     * @param symbol the symbol representing the variable
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1636
     * @param type the type
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1637
     */
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1638
    private void setType(final Symbol symbol, final LvarType type) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1639
        if(getLocalVariableTypeOrNull(symbol) == type) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1640
            return;
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1641
        }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1642
        assert symbol.hasSlot();
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1643
        assert !symbol.isGlobal();
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1644
        cloneOrNewLocalVariableTypes();
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1645
        localVariableTypes.put(symbol, type);
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1646
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1647
41981
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1648
    private void cloneOrNewLocalVariableTypes() {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1649
        localVariableTypes = localVariableTypes.isEmpty() ? new HashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1650
    }
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1651
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1652
    private void invalidateSymbol(final Symbol symbol) {
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1653
        localVariableTypes.remove(symbol);
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1654
        invalidatedSymbols.add(symbol);
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1655
    }
10375379aeac 8168373: don't emit conversions for symbols outside their lexical scope
attila
parents: 36696
diff changeset
  1656
24751
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1657
    /**
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1658
     * Set a flag in the symbol marking it as needing to be able to store a value of a particular type. Every symbol for
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1659
     * a local variable will be assigned between 1 and 6 local variable slots for storing all types it is known to need
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1660
     * to store.
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1661
     * @param symbol the symbol
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1662
     */
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1663
    private void symbolIsUsed(final Symbol symbol) {
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1664
        symbolIsUsed(symbol, getLocalVariableType(symbol));
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1665
    }
ccbd9cd3f720 8042118: Separate types from symbols
attila
parents:
diff changeset
  1666
}