author | attila |
Wed, 05 Jun 2013 10:44:32 +0200 | |
changeset 17981 | 9b8e085aa1fe |
parent 17969 | 0a4ddfce5b84 |
child 18618 | 136279c4cbe6 |
permissions | -rw-r--r-- |
16147 | 1 |
/* |
16151 | 2 |
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
16147 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package jdk.nashorn.internal.codegen; |
|
27 |
||
28 |
import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE; |
|
29 |
import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC; |
|
17233 | 30 |
import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; |
31 |
import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; |
|
16147 | 32 |
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; |
33 |
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; |
|
34 |
import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX; |
|
35 |
import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX; |
|
17233 | 36 |
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; |
16147 | 37 |
import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; |
38 |
import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG; |
|
39 |
import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX; |
|
17233 | 40 |
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; |
41 |
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
42 |
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; |
16147 | 43 |
import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; |
44 |
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; |
|
45 |
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; |
|
46 |
import static jdk.nashorn.internal.codegen.CompilerConstants.staticField; |
|
47 |
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; |
|
48 |
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; |
|
49 |
import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; |
|
50 |
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE; |
|
51 |
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_SCOPE; |
|
52 |
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; |
|
53 |
||
54 |
import java.io.PrintWriter; |
|
55 |
import java.util.ArrayList; |
|
56 |
import java.util.Arrays; |
|
57 |
import java.util.EnumSet; |
|
58 |
import java.util.Iterator; |
|
59 |
import java.util.LinkedList; |
|
60 |
import java.util.List; |
|
17778 | 61 |
import java.util.Locale; |
16147 | 62 |
import java.util.TreeMap; |
63 |
import jdk.nashorn.internal.codegen.ClassEmitter.Flag; |
|
64 |
import jdk.nashorn.internal.codegen.CompilerConstants.Call; |
|
65 |
import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; |
|
66 |
import jdk.nashorn.internal.codegen.types.ArrayType; |
|
67 |
import jdk.nashorn.internal.codegen.types.Type; |
|
68 |
import jdk.nashorn.internal.ir.AccessNode; |
|
69 |
import jdk.nashorn.internal.ir.BaseNode; |
|
70 |
import jdk.nashorn.internal.ir.BinaryNode; |
|
71 |
import jdk.nashorn.internal.ir.Block; |
|
72 |
import jdk.nashorn.internal.ir.BreakNode; |
|
17233 | 73 |
import jdk.nashorn.internal.ir.BreakableNode; |
16147 | 74 |
import jdk.nashorn.internal.ir.CallNode; |
75 |
import jdk.nashorn.internal.ir.CaseNode; |
|
76 |
import jdk.nashorn.internal.ir.CatchNode; |
|
77 |
import jdk.nashorn.internal.ir.ContinueNode; |
|
78 |
import jdk.nashorn.internal.ir.EmptyNode; |
|
79 |
import jdk.nashorn.internal.ir.ExecuteNode; |
|
80 |
import jdk.nashorn.internal.ir.ForNode; |
|
81 |
import jdk.nashorn.internal.ir.FunctionNode; |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
82 |
import jdk.nashorn.internal.ir.FunctionNode.CompilationState; |
16147 | 83 |
import jdk.nashorn.internal.ir.IdentNode; |
84 |
import jdk.nashorn.internal.ir.IfNode; |
|
85 |
import jdk.nashorn.internal.ir.IndexNode; |
|
17968
108ba976aa02
8015684: FieldObjectCreator.putField ignores getValueType
attila
parents:
17778
diff
changeset
|
86 |
import jdk.nashorn.internal.ir.LexicalContext; |
17255 | 87 |
import jdk.nashorn.internal.ir.LexicalContextNode; |
16147 | 88 |
import jdk.nashorn.internal.ir.LiteralNode; |
89 |
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; |
|
90 |
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; |
|
17233 | 91 |
import jdk.nashorn.internal.ir.LoopNode; |
16147 | 92 |
import jdk.nashorn.internal.ir.Node; |
93 |
import jdk.nashorn.internal.ir.ObjectNode; |
|
94 |
import jdk.nashorn.internal.ir.PropertyNode; |
|
95 |
import jdk.nashorn.internal.ir.ReturnNode; |
|
96 |
import jdk.nashorn.internal.ir.RuntimeNode; |
|
97 |
import jdk.nashorn.internal.ir.RuntimeNode.Request; |
|
98 |
import jdk.nashorn.internal.ir.SplitNode; |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
99 |
import jdk.nashorn.internal.ir.Statement; |
16147 | 100 |
import jdk.nashorn.internal.ir.SwitchNode; |
101 |
import jdk.nashorn.internal.ir.Symbol; |
|
102 |
import jdk.nashorn.internal.ir.TernaryNode; |
|
103 |
import jdk.nashorn.internal.ir.ThrowNode; |
|
104 |
import jdk.nashorn.internal.ir.TryNode; |
|
105 |
import jdk.nashorn.internal.ir.UnaryNode; |
|
106 |
import jdk.nashorn.internal.ir.VarNode; |
|
107 |
import jdk.nashorn.internal.ir.WhileNode; |
|
108 |
import jdk.nashorn.internal.ir.WithNode; |
|
109 |
import jdk.nashorn.internal.ir.debug.ASTWriter; |
|
110 |
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; |
|
111 |
import jdk.nashorn.internal.ir.visitor.NodeVisitor; |
|
112 |
import jdk.nashorn.internal.parser.Lexer.RegexToken; |
|
113 |
import jdk.nashorn.internal.parser.TokenType; |
|
114 |
import jdk.nashorn.internal.runtime.Context; |
|
17233 | 115 |
import jdk.nashorn.internal.runtime.Debug; |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
116 |
import jdk.nashorn.internal.runtime.DebugLogger; |
16147 | 117 |
import jdk.nashorn.internal.runtime.ECMAException; |
17241
c337fefb8c84
8012334: ToUint32, ToInt32, and ToUint16 don't conform to spec
hannesw
parents:
17239
diff
changeset
|
118 |
import jdk.nashorn.internal.runtime.JSType; |
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
119 |
import jdk.nashorn.internal.runtime.Property; |
16147 | 120 |
import jdk.nashorn.internal.runtime.PropertyMap; |
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16268
diff
changeset
|
121 |
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; |
16147 | 122 |
import jdk.nashorn.internal.runtime.Scope; |
123 |
import jdk.nashorn.internal.runtime.ScriptFunction; |
|
124 |
import jdk.nashorn.internal.runtime.ScriptObject; |
|
125 |
import jdk.nashorn.internal.runtime.ScriptRuntime; |
|
126 |
import jdk.nashorn.internal.runtime.Source; |
|
127 |
import jdk.nashorn.internal.runtime.Undefined; |
|
128 |
import jdk.nashorn.internal.runtime.linker.LinkerCallSite; |
|
129 |
||
130 |
/** |
|
131 |
* This is the lowest tier of the code generator. It takes lowered ASTs emitted |
|
132 |
* from Lower and emits Java byte code. The byte code emission logic is broken |
|
133 |
* out into MethodEmitter. MethodEmitter works internally with a type stack, and |
|
134 |
* keeps track of the contents of the byte code stack. This way we avoid a large |
|
135 |
* number of special cases on the form |
|
136 |
* <pre> |
|
137 |
* if (type == INT) { |
|
138 |
* visitInsn(ILOAD, slot); |
|
139 |
* } else if (type == DOUBLE) { |
|
140 |
* visitInsn(DOUBLE, slot); |
|
141 |
* } |
|
142 |
* </pre> |
|
143 |
* This quickly became apparent when the code generator was generalized to work |
|
144 |
* with all types, and not just numbers or objects. |
|
145 |
* <p> |
|
146 |
* The CodeGenerator visits nodes only once, tags them as resolved and emits |
|
147 |
* bytecode for them. |
|
148 |
*/ |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
149 |
final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContext> { |
16147 | 150 |
|
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
151 |
/** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
152 |
private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global"; |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
153 |
|
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
154 |
/** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */ |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
155 |
private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl"; |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
156 |
|
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
157 |
/** Constant data & installation. The only reason the compiler keeps this is because it is assigned |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
158 |
* by reflection in class installation */ |
16147 | 159 |
private final Compiler compiler; |
160 |
||
161 |
/** Call site flags given to the code generator to be used for all generated call sites */ |
|
162 |
private final int callSiteFlags; |
|
163 |
||
164 |
/** How many regexp fields have been emitted */ |
|
165 |
private int regexFieldCount; |
|
166 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
167 |
/** Line number for last statement. If we encounter a new line number, line number bytecode information |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
168 |
* needs to be generated */ |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
169 |
private int lastLineNumber = -1; |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
170 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
171 |
/** When should we stop caching regexp expressions in fields to limit bytecode size? */ |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
172 |
private static final int MAX_REGEX_FIELDS = 2 * 1024; |
17233 | 173 |
|
174 |
/** Current method emitter */ |
|
175 |
private MethodEmitter method; |
|
176 |
||
177 |
/** Current compile unit */ |
|
178 |
private CompileUnit unit; |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
179 |
|
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
180 |
private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug"); |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
181 |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
182 |
|
16147 | 183 |
/** |
184 |
* Constructor. |
|
185 |
* |
|
186 |
* @param compiler |
|
187 |
*/ |
|
188 |
CodeGenerator(final Compiler compiler) { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
189 |
super(new CodeGeneratorLexicalContext()); |
16147 | 190 |
this.compiler = compiler; |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
191 |
this.callSiteFlags = compiler.getEnv()._callsite_flags; |
16147 | 192 |
} |
193 |
||
194 |
/** |
|
195 |
* Gets the call site flags, adding the strict flag if the current function |
|
196 |
* being generated is in strict mode |
|
197 |
* |
|
198 |
* @return the correct flags for a call site in the current function |
|
199 |
*/ |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
200 |
int getCallSiteFlags() { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
201 |
return lc.getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; |
16147 | 202 |
} |
203 |
||
204 |
/** |
|
205 |
* Load an identity node |
|
206 |
* |
|
207 |
* @param identNode an identity node to load |
|
208 |
* @return the method generator used |
|
209 |
*/ |
|
210 |
private MethodEmitter loadIdent(final IdentNode identNode) { |
|
211 |
final Symbol symbol = identNode.getSymbol(); |
|
212 |
||
213 |
if (!symbol.isScope()) { |
|
16209
18e55b352d56
8007460: var assignment to a parameter in a varargs method causes compilation error
attila
parents:
16206
diff
changeset
|
214 |
assert symbol.hasSlot() || symbol.isParam(); |
16147 | 215 |
return method.load(symbol); |
216 |
} |
|
217 |
||
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
218 |
final String name = symbol.getName(); |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
219 |
final Source source = lc.getCurrentFunction().getSource(); |
16147 | 220 |
|
221 |
if (CompilerConstants.__FILE__.name().equals(name)) { |
|
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
222 |
return method.load(source.getName()); |
16147 | 223 |
} else if (CompilerConstants.__DIR__.name().equals(name)) { |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
224 |
return method.load(source.getBase()); |
16147 | 225 |
} else if (CompilerConstants.__LINE__.name().equals(name)) { |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
226 |
return method.load(source.getLine(identNode.position())).convert(Type.OBJECT); |
16147 | 227 |
} else { |
228 |
assert identNode.getSymbol().isScope() : identNode + " is not in scope!"; |
|
229 |
||
230 |
final int flags = CALLSITE_SCOPE | getCallSiteFlags(); |
|
17233 | 231 |
method.loadCompilerConstant(SCOPE); |
16147 | 232 |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
233 |
if (isFastScope(symbol)) { |
16147 | 234 |
// Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. |
235 |
if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { |
|
236 |
return loadSharedScopeVar(identNode.getType(), symbol, flags); |
|
237 |
} |
|
238 |
return loadFastScopeVar(identNode.getType(), symbol, flags, identNode.isFunction()); |
|
239 |
} |
|
240 |
return method.dynamicGet(identNode.getType(), identNode.getName(), flags, identNode.isFunction()); |
|
241 |
} |
|
242 |
} |
|
243 |
||
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
244 |
/** |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
245 |
* Check if this symbol can be accessed directly with a putfield or getfield or dynamic load |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
246 |
* |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
247 |
* @param function function to check for fast scope |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
248 |
* @return true if fast scope |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
249 |
*/ |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
250 |
private boolean isFastScope(final Symbol symbol) { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
251 |
if (!symbol.isScope()) { |
17255 | 252 |
return false; |
253 |
} |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
254 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
255 |
if (!lc.inDynamicScope()) { |
17255 | 256 |
// If there's no with or eval in context, and the symbol is marked as scoped, it is fast scoped. Such a |
257 |
// symbol must either be global, or its defining block must need scope. |
|
258 |
assert symbol.isGlobal() || lc.getDefiningBlock(symbol).needsScope() : symbol.getName(); |
|
259 |
return true; |
|
260 |
} |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
261 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
262 |
if (symbol.isGlobal()) { |
17255 | 263 |
// Shortcut: if there's a with or eval in context, globals can't be fast scoped |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
264 |
return false; |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
265 |
} |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
266 |
|
17255 | 267 |
// Otherwise, check if there's a dynamic scope between use of the symbol and its definition |
268 |
final String name = symbol.getName(); |
|
269 |
boolean previousWasBlock = false; |
|
270 |
for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { |
|
271 |
final LexicalContextNode node = it.next(); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
272 |
if (node instanceof Block) { |
17255 | 273 |
// If this block defines the symbol, then we can fast scope the symbol. |
274 |
final Block block = (Block)node; |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
275 |
if (block.getExistingSymbol(name) == symbol) { |
17255 | 276 |
assert block.needsScope(); |
277 |
return true; |
|
278 |
} |
|
279 |
previousWasBlock = true; |
|
280 |
} else { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
281 |
if ((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node))) { |
17255 | 282 |
// If we hit a scope that can have symbols introduced into it at run time before finding the defining |
283 |
// block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block |
|
284 |
// before - its block. Otherwise, we are currently processing the WithNode's expression, and that's |
|
285 |
// obviously not subjected to introducing new symbols. |
|
286 |
return false; |
|
287 |
} |
|
288 |
previousWasBlock = false; |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
289 |
} |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
290 |
} |
17255 | 291 |
// Should've found the symbol defined in a block |
292 |
throw new AssertionError(); |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
293 |
} |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
294 |
|
16147 | 295 |
private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
296 |
method.load(isFastScope(symbol) ? getScopeProtoDepth(lc.getCurrentBlock(), symbol) : -1); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
297 |
final SharedScopeCall scopeCall = lc.getScopeGet(unit, valueType, symbol, flags | CALLSITE_FAST_SCOPE); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
298 |
return scopeCall.generateInvoke(method); |
16147 | 299 |
} |
300 |
||
301 |
private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) { |
|
302 |
loadFastScopeProto(symbol, false); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
303 |
return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); |
16147 | 304 |
} |
305 |
||
306 |
private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) { |
|
307 |
loadFastScopeProto(symbol, true); |
|
308 |
method.dynamicSet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE); |
|
309 |
return method; |
|
310 |
} |
|
311 |
||
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
312 |
private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
313 |
int depth = 0; |
17233 | 314 |
final String name = symbol.getName(); |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
315 |
for(final Iterator<Block> blocks = lc.getBlocks(startingBlock); blocks.hasNext();) { |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
316 |
final Block currentBlock = blocks.next(); |
17233 | 317 |
if (currentBlock.getExistingSymbol(name) == symbol) { |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
318 |
return depth; |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
319 |
} |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
320 |
if (currentBlock.needsScope()) { |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
321 |
++depth; |
16147 | 322 |
} |
323 |
} |
|
324 |
return -1; |
|
325 |
} |
|
326 |
||
327 |
private void loadFastScopeProto(final Symbol symbol, final boolean swap) { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
328 |
final int depth = getScopeProtoDepth(lc.getCurrentBlock(), symbol); |
16147 | 329 |
assert depth != -1; |
17233 | 330 |
if (depth > 0) { |
16147 | 331 |
if (swap) { |
332 |
method.swap(); |
|
333 |
} |
|
334 |
for (int i = 0; i < depth; i++) { |
|
335 |
method.invoke(ScriptObject.GET_PROTO); |
|
336 |
} |
|
337 |
if (swap) { |
|
338 |
method.swap(); |
|
339 |
} |
|
340 |
} |
|
341 |
} |
|
342 |
||
343 |
/** |
|
344 |
* Generate code that loads this node to the stack. This method is only |
|
345 |
* public to be accessible from the maps sub package. Do not call externally |
|
346 |
* |
|
347 |
* @param node node to load |
|
348 |
* |
|
349 |
* @return the method emitter used |
|
350 |
*/ |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
351 |
MethodEmitter load(final Node node) { |
16147 | 352 |
return load(node, false); |
353 |
} |
|
354 |
||
355 |
private MethodEmitter load(final Node node, final boolean baseAlreadyOnStack) { |
|
356 |
final Symbol symbol = node.getSymbol(); |
|
357 |
||
358 |
// If we lack symbols, we just generate what we see. |
|
359 |
if (symbol == null) { |
|
360 |
node.accept(this); |
|
361 |
return method; |
|
362 |
} |
|
363 |
||
364 |
/* |
|
365 |
* The load may be of type IdentNode, e.g. "x", AccessNode, e.g. "x.y" |
|
366 |
* or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are |
|
367 |
* BaseNodes and the logic for loading the base object is reused |
|
368 |
*/ |
|
369 |
final CodeGenerator codegen = this; |
|
370 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
371 |
node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
16147 | 372 |
@Override |
17233 | 373 |
public boolean enterIdentNode(final IdentNode identNode) { |
16147 | 374 |
loadIdent(identNode); |
17233 | 375 |
return false; |
16147 | 376 |
} |
377 |
||
378 |
@Override |
|
17233 | 379 |
public boolean enterAccessNode(final AccessNode accessNode) { |
16147 | 380 |
if (!baseAlreadyOnStack) { |
381 |
load(accessNode.getBase()).convert(Type.OBJECT); |
|
382 |
} |
|
383 |
assert method.peekType().isObject(); |
|
384 |
method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); |
|
17233 | 385 |
return false; |
16147 | 386 |
} |
387 |
||
388 |
@Override |
|
17233 | 389 |
public boolean enterIndexNode(final IndexNode indexNode) { |
16147 | 390 |
if (!baseAlreadyOnStack) { |
16190
23e52f635bb6
8006575: Error in codegen for element access on primitive value
sundar
parents:
16176
diff
changeset
|
391 |
load(indexNode.getBase()).convert(Type.OBJECT); |
16147 | 392 |
load(indexNode.getIndex()); |
393 |
} |
|
394 |
method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction()); |
|
17233 | 395 |
return false; |
16147 | 396 |
} |
397 |
||
398 |
@Override |
|
17233 | 399 |
public boolean enterFunctionNode(FunctionNode functionNode) { |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
400 |
// function nodes will always leave a constructed function object on stack, no need to load the symbol |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
401 |
// separately as in enterDefault() |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
402 |
functionNode.accept(codegen); |
17233 | 403 |
return false; |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
404 |
} |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
405 |
|
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
406 |
@Override |
17233 | 407 |
public boolean enterDefault(final Node otherNode) { |
16147 | 408 |
otherNode.accept(codegen); // generate code for whatever we are looking at. |
409 |
method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) |
|
17233 | 410 |
return false; |
16147 | 411 |
} |
412 |
}); |
|
413 |
||
414 |
return method; |
|
415 |
} |
|
416 |
||
417 |
@Override |
|
17233 | 418 |
public boolean enterAccessNode(final AccessNode accessNode) { |
16147 | 419 |
load(accessNode); |
17233 | 420 |
return false; |
16147 | 421 |
} |
422 |
||
423 |
/** |
|
424 |
* Initialize a specific set of vars to undefined. This has to be done at |
|
425 |
* the start of each method for local variables that aren't passed as |
|
426 |
* parameters. |
|
427 |
* |
|
428 |
* @param symbols list of symbols. |
|
429 |
*/ |
|
430 |
private void initSymbols(final Iterable<Symbol> symbols) { |
|
431 |
final LinkedList<Symbol> numbers = new LinkedList<>(); |
|
432 |
final LinkedList<Symbol> objects = new LinkedList<>(); |
|
433 |
||
434 |
for (final Symbol symbol : symbols) { |
|
435 |
/* |
|
436 |
* The following symbols are guaranteed to be defined and thus safe |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
437 |
* from having undefined written to them: parameters internals this |
16147 | 438 |
* |
439 |
* Otherwise we must, unless we perform control/escape analysis, |
|
440 |
* assign them undefined. |
|
441 |
*/ |
|
442 |
final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined(); |
|
443 |
||
444 |
if (symbol.hasSlot() && !isInternal) { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
445 |
assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + lc.getCurrentFunction(); |
16147 | 446 |
if (symbol.getSymbolType().isNumber()) { |
447 |
numbers.add(symbol); |
|
448 |
} else if (symbol.getSymbolType().isObject()) { |
|
449 |
objects.add(symbol); |
|
450 |
} |
|
451 |
} |
|
452 |
} |
|
453 |
||
454 |
initSymbols(numbers, Type.NUMBER); |
|
455 |
initSymbols(objects, Type.OBJECT); |
|
456 |
} |
|
457 |
||
458 |
private void initSymbols(final LinkedList<Symbol> symbols, final Type type) { |
|
17969 | 459 |
final Iterator<Symbol> it = symbols.iterator(); |
460 |
if(it.hasNext()) { |
|
461 |
method.loadUndefined(type); |
|
462 |
boolean hasNext; |
|
463 |
do { |
|
464 |
final Symbol symbol = it.next(); |
|
465 |
hasNext = it.hasNext(); |
|
466 |
if(hasNext) { |
|
467 |
method.dup(); |
|
468 |
} |
|
469 |
method.store(symbol); |
|
470 |
} while(hasNext); |
|
16147 | 471 |
} |
472 |
} |
|
473 |
||
474 |
/** |
|
475 |
* Create symbol debug information. |
|
476 |
* |
|
477 |
* @param block block containing symbols. |
|
478 |
*/ |
|
479 |
private void symbolInfo(final Block block) { |
|
17518
2225a4f929c0
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
lagergren
parents:
17255
diff
changeset
|
480 |
for (final Symbol symbol : block.getSymbols()) { |
17233 | 481 |
if (symbol.hasSlot()) { |
482 |
method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); |
|
483 |
} |
|
16147 | 484 |
} |
485 |
} |
|
486 |
||
487 |
@Override |
|
17233 | 488 |
public boolean enterBlock(final Block block) { |
16147 | 489 |
method.label(block.getEntryLabel()); |
490 |
initLocals(block); |
|
491 |
||
17233 | 492 |
return true; |
16147 | 493 |
} |
494 |
||
495 |
@Override |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
496 |
public Node leaveBlock(final Block block) { |
16147 | 497 |
method.label(block.getBreakLabel()); |
498 |
symbolInfo(block); |
|
499 |
||
17233 | 500 |
if (block.needsScope() && !block.isTerminal()) { |
16147 | 501 |
popBlockScope(block); |
502 |
} |
|
503 |
return block; |
|
504 |
} |
|
505 |
||
506 |
private void popBlockScope(final Block block) { |
|
507 |
final Label exitLabel = new Label("block_exit"); |
|
508 |
final Label recoveryLabel = new Label("block_catch"); |
|
509 |
final Label skipLabel = new Label("skip_catch"); |
|
510 |
||
511 |
/* pop scope a la try-finally */ |
|
17233 | 512 |
method.loadCompilerConstant(SCOPE); |
16147 | 513 |
method.invoke(ScriptObject.GET_PROTO); |
17233 | 514 |
method.storeCompilerConstant(SCOPE); |
16147 | 515 |
method._goto(skipLabel); |
516 |
method.label(exitLabel); |
|
517 |
||
518 |
method._catch(recoveryLabel); |
|
17233 | 519 |
method.loadCompilerConstant(SCOPE); |
16147 | 520 |
method.invoke(ScriptObject.GET_PROTO); |
17233 | 521 |
method.storeCompilerConstant(SCOPE); |
16147 | 522 |
method.athrow(); |
523 |
method.label(skipLabel); |
|
524 |
method._try(block.getEntryLabel(), exitLabel, recoveryLabel, Throwable.class); |
|
525 |
} |
|
526 |
||
527 |
@Override |
|
17233 | 528 |
public boolean enterBreakNode(final BreakNode breakNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
529 |
lineNumber(breakNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
530 |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
531 |
final BreakableNode breakFrom = lc.getBreakable(breakNode.getLabel()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
532 |
for (int i = 0; i < lc.getScopeNestingLevelTo(breakFrom); i++) { |
16147 | 533 |
closeWith(); |
534 |
} |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
535 |
method.splitAwareGoto(lc, breakFrom.getBreakLabel()); |
17233 | 536 |
|
537 |
return false; |
|
16147 | 538 |
} |
539 |
||
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
540 |
private int loadArgs(final List<Node> args) { |
16147 | 541 |
return loadArgs(args, null, false, args.size()); |
542 |
} |
|
543 |
||
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
544 |
private int loadArgs(final List<Node> args, final String signature, final boolean isVarArg, final int argCount) { |
16147 | 545 |
// arg have already been converted to objects here. |
546 |
if (isVarArg || argCount > LinkerCallSite.ARGLIMIT) { |
|
547 |
loadArgsArray(args); |
|
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
548 |
return 1; |
16147 | 549 |
} |
550 |
||
551 |
// pad with undefined if size is too short. argCount is the real number of args |
|
552 |
int n = 0; |
|
553 |
final Type[] params = signature == null ? null : Type.getMethodArguments(signature); |
|
554 |
for (final Node arg : args) { |
|
555 |
assert arg != null; |
|
556 |
load(arg); |
|
16175
13ac6c5cc6a4
8006337: Discarded arguments for INVOKESTATIC must still be evaluated for side effects
attila
parents:
16174
diff
changeset
|
557 |
if (n >= argCount) { |
13ac6c5cc6a4
8006337: Discarded arguments for INVOKESTATIC must still be evaluated for side effects
attila
parents:
16174
diff
changeset
|
558 |
method.pop(); // we had to load the arg for its side effects |
13ac6c5cc6a4
8006337: Discarded arguments for INVOKESTATIC must still be evaluated for side effects
attila
parents:
16174
diff
changeset
|
559 |
} else if (params != null) { |
16147 | 560 |
method.convert(params[n]); |
561 |
} |
|
562 |
n++; |
|
563 |
} |
|
564 |
||
565 |
while (n < argCount) { |
|
566 |
method.loadUndefined(Type.OBJECT); |
|
567 |
n++; |
|
568 |
} |
|
569 |
||
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
570 |
return argCount; |
16147 | 571 |
} |
572 |
||
573 |
@Override |
|
17233 | 574 |
public boolean enterCallNode(final CallNode callNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
575 |
lineNumber(callNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
576 |
|
16147 | 577 |
final List<Node> args = callNode.getArgs(); |
578 |
final Node function = callNode.getFunction(); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
579 |
final Block currentBlock = lc.getCurrentBlock(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
580 |
final CodeGeneratorLexicalContext codegenLexicalContext = lc; |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
581 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
582 |
function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
583 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
584 |
private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) { |
16147 | 585 |
final Symbol symbol = identNode.getSymbol(); |
586 |
int scopeCallFlags = flags; |
|
17233 | 587 |
method.loadCompilerConstant(SCOPE); |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
588 |
if (isFastScope(symbol)) { |
16147 | 589 |
method.load(getScopeProtoDepth(currentBlock, symbol)); |
590 |
scopeCallFlags |= CALLSITE_FAST_SCOPE; |
|
591 |
} else { |
|
592 |
method.load(-1); // Bypass fast-scope code in shared callsite |
|
593 |
} |
|
594 |
loadArgs(args); |
|
595 |
final Type[] paramTypes = method.getTypesFromStack(args.size()); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
596 |
final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
597 |
return scopeCall.generateInvoke(method); |
16147 | 598 |
} |
599 |
||
600 |
private void scopeCall(final IdentNode node, final int flags) { |
|
601 |
load(node); |
|
602 |
method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 |
|
603 |
// ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly. |
|
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
604 |
method.loadNull(); //the 'this' |
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
605 |
method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags); |
16147 | 606 |
} |
607 |
||
608 |
private void evalCall(final IdentNode node, final int flags) { |
|
609 |
load(node); |
|
610 |
method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 |
|
611 |
||
612 |
final Label not_eval = new Label("not_eval"); |
|
613 |
final Label eval_done = new Label("eval_done"); |
|
614 |
||
615 |
// check if this is the real built-in eval |
|
616 |
method.dup(); |
|
617 |
globalIsEval(); |
|
618 |
||
619 |
method.ifeq(not_eval); |
|
620 |
// We don't need ScriptFunction object for 'eval' |
|
621 |
method.pop(); |
|
622 |
||
17233 | 623 |
method.loadCompilerConstant(SCOPE); // Load up self (scope). |
16147 | 624 |
|
625 |
final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); |
|
626 |
// load evaluated code |
|
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
627 |
load(evalArgs.getCode()); |
16147 | 628 |
method.convert(Type.OBJECT); |
629 |
// special/extra 'eval' arguments |
|
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
630 |
load(evalArgs.getThis()); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
631 |
method.load(evalArgs.getLocation()); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
632 |
method.load(evalArgs.getStrictMode()); |
16147 | 633 |
method.convert(Type.OBJECT); |
634 |
||
635 |
// direct call to Global.directEval |
|
636 |
globalDirectEval(); |
|
637 |
method.convert(callNode.getType()); |
|
638 |
method._goto(eval_done); |
|
639 |
||
640 |
method.label(not_eval); |
|
641 |
// This is some scope 'eval' or global eval replaced by user |
|
642 |
// but not the built-in ECMAScript 'eval' function call |
|
643 |
method.loadNull(); |
|
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
644 |
method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags); |
16147 | 645 |
|
646 |
method.label(eval_done); |
|
647 |
} |
|
648 |
||
649 |
@Override |
|
17233 | 650 |
public boolean enterIdentNode(final IdentNode node) { |
16147 | 651 |
final Symbol symbol = node.getSymbol(); |
652 |
||
653 |
if (symbol.isScope()) { |
|
654 |
final int flags = getCallSiteFlags() | CALLSITE_SCOPE; |
|
655 |
final int useCount = symbol.getUseCount(); |
|
656 |
||
657 |
// Threshold for generating shared scope callsite is lower for fast scope symbols because we know |
|
17239
6dd68632cdcd
8011065: Problems when script implements an interface with variadic methods
attila
parents:
17233
diff
changeset
|
658 |
// we can dial in the correct scope. However, we also need to enable it for non-fast scopes to |
16147 | 659 |
// support huge scripts like mandreel.js. |
660 |
if (callNode.isEval()) { |
|
661 |
evalCall(node, flags); |
|
662 |
} else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
663 |
|| (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
664 |
|| CodeGenerator.this.lc.inDynamicScope()) { |
16147 | 665 |
scopeCall(node, flags); |
666 |
} else { |
|
667 |
sharedScopeCall(node, flags); |
|
668 |
} |
|
17233 | 669 |
assert method.peekType().equals(callNode.getType()) : method.peekType() + "!=" + callNode.getType(); |
16147 | 670 |
} else { |
671 |
enterDefault(node); |
|
672 |
} |
|
673 |
||
17233 | 674 |
return false; |
16147 | 675 |
} |
676 |
||
677 |
@Override |
|
17233 | 678 |
public boolean enterAccessNode(final AccessNode node) { |
16147 | 679 |
load(node.getBase()); |
680 |
method.convert(Type.OBJECT); |
|
681 |
method.dup(); |
|
682 |
method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true); |
|
683 |
method.swap(); |
|
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
684 |
method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags()); |
16147 | 685 |
assert method.peekType().equals(callNode.getType()); |
686 |
||
17233 | 687 |
return false; |
16147 | 688 |
} |
689 |
||
690 |
@Override |
|
17233 | 691 |
public boolean enterFunctionNode(final FunctionNode origCallee) { |
692 |
// NOTE: visiting the callee will leave a constructed ScriptFunction object on the stack if |
|
693 |
// callee.needsCallee() == true |
|
694 |
final FunctionNode callee = (FunctionNode)origCallee.accept(CodeGenerator.this); |
|
695 |
||
16147 | 696 |
final boolean isVarArg = callee.isVarArg(); |
697 |
final int argCount = isVarArg ? -1 : callee.getParameters().size(); |
|
698 |
||
699 |
final String signature = new FunctionSignature(true, callee.needsCallee(), callee.getReturnType(), isVarArg ? null : callee.getParameters()).toString(); |
|
700 |
||
17233 | 701 |
if (callee.isStrict()) { // self is undefined |
16147 | 702 |
method.loadUndefined(Type.OBJECT); |
703 |
} else { // get global from scope (which is the self) |
|
704 |
globalInstance(); |
|
705 |
} |
|
706 |
loadArgs(args, signature, isVarArg, argCount); |
|
17233 | 707 |
assert callee.getCompileUnit() != null : "no compile unit for " + callee.getName() + " " + Debug.id(callee) + " " + callNode; |
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
708 |
method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); |
16147 | 709 |
assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); |
17233 | 710 |
return false; |
16147 | 711 |
} |
712 |
||
713 |
@Override |
|
17233 | 714 |
public boolean enterIndexNode(final IndexNode node) { |
16147 | 715 |
load(node.getBase()); |
716 |
method.convert(Type.OBJECT); |
|
717 |
method.dup(); |
|
718 |
load(node.getIndex()); |
|
719 |
final Type indexType = node.getIndex().getType(); |
|
720 |
if (indexType.isObject() || indexType.isBoolean()) { |
|
721 |
method.convert(Type.OBJECT); //TODO |
|
722 |
} |
|
723 |
method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true); |
|
724 |
method.swap(); |
|
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
725 |
method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags()); |
16147 | 726 |
assert method.peekType().equals(callNode.getType()); |
727 |
||
17233 | 728 |
return false; |
16147 | 729 |
} |
730 |
||
731 |
@Override |
|
17233 | 732 |
protected boolean enterDefault(final Node node) { |
16147 | 733 |
// Load up function. |
734 |
load(function); |
|
735 |
method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions |
|
736 |
method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE |
|
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
737 |
method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE); |
16147 | 738 |
assert method.peekType().equals(callNode.getType()); |
739 |
||
17233 | 740 |
return false; |
16147 | 741 |
} |
742 |
}); |
|
743 |
||
744 |
method.store(callNode.getSymbol()); |
|
745 |
||
17233 | 746 |
return false; |
16147 | 747 |
} |
748 |
||
749 |
@Override |
|
17233 | 750 |
public boolean enterContinueNode(final ContinueNode continueNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
751 |
lineNumber(continueNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
752 |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
753 |
final LoopNode continueTo = lc.getContinueTo(continueNode.getLabel()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
754 |
for (int i = 0; i < lc.getScopeNestingLevelTo(continueTo); i++) { |
16147 | 755 |
closeWith(); |
756 |
} |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
757 |
method.splitAwareGoto(lc, continueTo.getContinueLabel()); |
17233 | 758 |
|
759 |
return false; |
|
16147 | 760 |
} |
761 |
||
762 |
@Override |
|
17233 | 763 |
public boolean enterEmptyNode(final EmptyNode emptyNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
764 |
lineNumber(emptyNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
765 |
|
17233 | 766 |
return false; |
16147 | 767 |
} |
768 |
||
769 |
@Override |
|
17233 | 770 |
public boolean enterExecuteNode(final ExecuteNode executeNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
771 |
lineNumber(executeNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
772 |
|
16147 | 773 |
final Node expression = executeNode.getExpression(); |
774 |
expression.accept(this); |
|
775 |
||
17233 | 776 |
return false; |
16147 | 777 |
} |
778 |
||
779 |
@Override |
|
17233 | 780 |
public boolean enterForNode(final ForNode forNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
781 |
lineNumber(forNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
782 |
|
16147 | 783 |
if (forNode.isForIn()) { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
784 |
enterForIn(forNode); |
16147 | 785 |
} else { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
786 |
enterFor(forNode); |
16147 | 787 |
} |
788 |
||
17233 | 789 |
return false; |
790 |
} |
|
791 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
792 |
private void enterFor(final ForNode forNode) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
793 |
final Node init = forNode.getInit(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
794 |
final Node test = forNode.getTest(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
795 |
final Block body = forNode.getBody(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
796 |
final Node modify = forNode.getModify(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
797 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
798 |
if (init != null) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
799 |
init.accept(this); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
800 |
} |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
801 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
802 |
final Label loopLabel = new Label("loop"); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
803 |
final Label testLabel = new Label("test"); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
804 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
805 |
method._goto(testLabel); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
806 |
method.label(loopLabel); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
807 |
body.accept(this); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
808 |
method.label(forNode.getContinueLabel()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
809 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
810 |
if (!body.isTerminal() && modify != null) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
811 |
load(modify); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
812 |
} |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
813 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
814 |
method.label(testLabel); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
815 |
if (test != null) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
816 |
new BranchOptimizer(this, method).execute(test, loopLabel, true); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
817 |
} else { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
818 |
method._goto(loopLabel); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
819 |
} |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
820 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
821 |
method.label(forNode.getBreakLabel()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
822 |
} |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
823 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
824 |
private void enterForIn(final ForNode forNode) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
825 |
final Block body = forNode.getBody(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
826 |
final Node modify = forNode.getModify(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
827 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
828 |
final Symbol iter = forNode.getIterator(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
829 |
final Label loopLabel = new Label("loop"); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
830 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
831 |
Node init = forNode.getInit(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
832 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
833 |
// We have to evaluate the optional initializer expression |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
834 |
// of the iterator variable of the for-in statement. |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
835 |
if (init instanceof VarNode) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
836 |
init.accept(this); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
837 |
init = ((VarNode)init).getName(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
838 |
} |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
839 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
840 |
load(modify); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
841 |
assert modify.getType().isObject(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
842 |
method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
843 |
method.store(iter); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
844 |
method._goto(forNode.getContinueLabel()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
845 |
method.label(loopLabel); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
846 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
847 |
new Store<Node>(init) { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
848 |
@Override |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
849 |
protected void storeNonDiscard() { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
850 |
return; |
17233 | 851 |
} |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
852 |
@Override |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
853 |
protected void evaluate() { |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
854 |
method.load(iter); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
855 |
method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
856 |
} |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
857 |
}.store(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
858 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
859 |
body.accept(this); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
860 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
861 |
method.label(forNode.getContinueLabel()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
862 |
method.load(iter); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
863 |
method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class)); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
864 |
method.ifne(loopLabel); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
865 |
method.label(forNode.getBreakLabel()); |
16147 | 866 |
} |
867 |
||
868 |
/** |
|
869 |
* Initialize the slots in a frame to undefined. |
|
870 |
* |
|
871 |
* @param block block with local vars. |
|
872 |
*/ |
|
16168
f0c208287983
8005976: Break out AccessSpecializer into one pass before CodeGenerator instead of iterative applications from CodeGenerator
lagergren
parents:
16152
diff
changeset
|
873 |
private void initLocals(final Block block) { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
874 |
lc.nextFreeSlot(block); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
875 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
876 |
final boolean isFunctionBody = lc.isFunctionBody(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
877 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
878 |
final FunctionNode function = lc.getCurrentFunction(); |
17233 | 879 |
if (isFunctionBody) { |
880 |
/* Fix the predefined slots so they have numbers >= 0, like varargs. */ |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
881 |
if (function.needsParentScope()) { |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
882 |
initParentScope(); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
883 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
884 |
if (function.needsArguments()) { |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
885 |
initArguments(function); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
886 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
887 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
888 |
|
16147 | 889 |
/* |
890 |
* Determine if block needs scope, if not, just do initSymbols for this block. |
|
891 |
*/ |
|
892 |
if (block.needsScope()) { |
|
893 |
/* |
|
894 |
* Determine if function is varargs and consequently variables have to |
|
895 |
* be in the scope. |
|
896 |
*/ |
|
16252
3bfe9b68a0fa
8008648: Lazy JIT scope and callee semantics bugfixes. Broke out wallclock timer.
lagergren
parents:
16240
diff
changeset
|
897 |
final boolean varsInScope = function.allVarsInScope(); |
16147 | 898 |
|
899 |
// TODO for LET we can do better: if *block* does not contain any eval/with, we don't need its vars in scope. |
|
900 |
||
901 |
final List<String> nameList = new ArrayList<>(); |
|
902 |
final List<Symbol> locals = new ArrayList<>(); |
|
903 |
||
904 |
// Initalize symbols and values |
|
905 |
final List<Symbol> newSymbols = new ArrayList<>(); |
|
906 |
final List<Symbol> values = new ArrayList<>(); |
|
907 |
||
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
908 |
final boolean hasArguments = function.needsArguments(); |
17233 | 909 |
|
17518
2225a4f929c0
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
lagergren
parents:
17255
diff
changeset
|
910 |
for (final Symbol symbol : block.getSymbols()) { |
17233 | 911 |
|
912 |
if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { |
|
16147 | 913 |
continue; |
914 |
} |
|
915 |
||
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
916 |
if (symbol.isVar()) { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
917 |
if (varsInScope || symbol.isScope()) { |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
918 |
nameList.add(symbol.getName()); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
919 |
newSymbols.add(symbol); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
920 |
values.add(null); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
921 |
assert symbol.isScope() : "scope for " + symbol + " should have been set in Lower already " + function.getName(); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
922 |
assert !symbol.hasSlot() : "slot for " + symbol + " should have been removed in Lower already" + function.getName(); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
923 |
} else { |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
924 |
assert symbol.hasSlot() : symbol + " should have a slot only, no scope"; |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
925 |
locals.add(symbol); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
926 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
927 |
} else if (symbol.isParam() && (varsInScope || hasArguments || symbol.isScope())) { |
16147 | 928 |
nameList.add(symbol.getName()); |
929 |
newSymbols.add(symbol); |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
930 |
values.add(hasArguments ? null : symbol); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
931 |
assert symbol.isScope() : "scope for " + symbol + " should have been set in Lower already " + function.getName() + " varsInScope="+varsInScope+" hasArguments="+hasArguments+" symbol.isScope()=" + symbol.isScope(); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
932 |
assert !(hasArguments && symbol.hasSlot()) : "slot for " + symbol + " should have been removed in Lower already " + function.getName(); |
16147 | 933 |
} |
934 |
} |
|
935 |
||
936 |
// we may have locals that need to be initialized |
|
937 |
initSymbols(locals); |
|
938 |
||
939 |
/* |
|
940 |
* Create a new object based on the symbols and values, generate |
|
941 |
* bootstrap code for object |
|
942 |
*/ |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
943 |
final FieldObjectCreator<Symbol> foc = new FieldObjectCreator<Symbol>(this, nameList, newSymbols, values, true, hasArguments) { |
16147 | 944 |
@Override |
945 |
protected void loadValue(final Symbol value) { |
|
946 |
method.load(value); |
|
947 |
} |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
948 |
|
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
949 |
@Override |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
950 |
protected void loadScope(MethodEmitter m) { |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
951 |
if (function.needsParentScope()) { |
17233 | 952 |
m.loadCompilerConstant(SCOPE); |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
953 |
} else { |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
954 |
m.loadNull(); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
955 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
956 |
} |
16147 | 957 |
}; |
958 |
foc.makeObject(method); |
|
959 |
||
960 |
// runScript(): merge scope into global |
|
17233 | 961 |
if (isFunctionBody && function.isProgram()) { |
16147 | 962 |
method.invoke(ScriptRuntime.MERGE_SCOPE); |
963 |
} |
|
964 |
||
17233 | 965 |
method.storeCompilerConstant(SCOPE); |
16147 | 966 |
} else { |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
967 |
// Since we don't have a scope, parameters didn't get assigned array indices by the FieldObjectCreator, so |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
968 |
// we need to assign them separately here. |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
969 |
int nextParam = 0; |
17233 | 970 |
if (isFunctionBody && function.isVarArg()) { |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
971 |
for (final IdentNode param : function.getParameters()) { |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
972 |
param.getSymbol().setFieldIndex(nextParam++); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
973 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
974 |
} |
17233 | 975 |
|
17518
2225a4f929c0
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
lagergren
parents:
17255
diff
changeset
|
976 |
initSymbols(block.getSymbols()); |
16147 | 977 |
} |
978 |
||
979 |
// Debugging: print symbols? @see --print-symbols flag |
|
17233 | 980 |
printSymbols(block, (isFunctionBody ? "Function " : "Block in ") + (function.getIdent() == null ? "<anonymous>" : function.getIdent().getName())); |
16147 | 981 |
} |
982 |
||
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
983 |
private void initArguments(final FunctionNode function) { |
17233 | 984 |
method.loadCompilerConstant(VARARGS); |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
985 |
if (function.needsCallee()) { |
17233 | 986 |
method.loadCompilerConstant(CALLEE); |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
987 |
} else { |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
988 |
// If function is strict mode, "arguments.callee" is not populated, so we don't necessarily need the |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
989 |
// caller. |
17233 | 990 |
assert function.isStrict(); |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
991 |
method.loadNull(); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
992 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
993 |
method.load(function.getParameters().size()); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
994 |
globalAllocateArguments(); |
17233 | 995 |
method.storeCompilerConstant(ARGUMENTS); |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
996 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
997 |
|
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
998 |
private void initParentScope() { |
17233 | 999 |
method.loadCompilerConstant(CALLEE); |
16147 | 1000 |
method.invoke(ScriptFunction.GET_SCOPE); |
17233 | 1001 |
method.storeCompilerConstant(SCOPE); |
16147 | 1002 |
} |
1003 |
||
1004 |
@Override |
|
17233 | 1005 |
public boolean enterFunctionNode(final FunctionNode functionNode) { |
1006 |
if (functionNode.isLazy()) { |
|
1007 |
// Must do it now; can't postpone it until leaveFunctionNode() |
|
1008 |
newFunctionObject(functionNode, functionNode); |
|
1009 |
return false; |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
1010 |
} |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
1011 |
|
17233 | 1012 |
LOG.info("=== BEGIN ", functionNode.getName()); |
1013 |
||
1014 |
assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1015 |
unit = lc.pushCompileUnit(functionNode.getCompileUnit()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1016 |
assert lc.hasCompileUnits(); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1017 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1018 |
method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode)); |
16147 | 1019 |
// Mark end for variable tables. |
1020 |
method.begin(); |
|
17233 | 1021 |
|
1022 |
return true; |
|
16147 | 1023 |
} |
1024 |
||
1025 |
@Override |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
1026 |
public Node leaveFunctionNode(final FunctionNode functionNode) { |
16147 | 1027 |
try { |
1028 |
method.end(); // wrap up this method |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1029 |
unit = lc.popCompileUnit(functionNode.getCompileUnit()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1030 |
method = lc.popMethodEmitter(method); |
17233 | 1031 |
LOG.info("=== END ", functionNode.getName()); |
1032 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1033 |
final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED); |
17233 | 1034 |
|
1035 |
newFunctionObject(newFunctionNode, functionNode); |
|
1036 |
return newFunctionNode; |
|
16147 | 1037 |
} catch (final Throwable t) { |
1038 |
Context.printStackTrace(t); |
|
1039 |
final VerifyError e = new VerifyError("Code generation bug in \"" + functionNode.getName() + "\": likely stack misaligned: " + t + " " + functionNode.getSource().getName()); |
|
1040 |
e.initCause(t); |
|
1041 |
throw e; |
|
1042 |
} |
|
1043 |
} |
|
1044 |
||
1045 |
@Override |
|
17233 | 1046 |
public boolean enterIdentNode(final IdentNode identNode) { |
1047 |
return false; |
|
16147 | 1048 |
} |
1049 |
||
1050 |
@Override |
|
17233 | 1051 |
public boolean enterIfNode(final IfNode ifNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1052 |
lineNumber(ifNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1053 |
|
16147 | 1054 |
final Node test = ifNode.getTest(); |
1055 |
final Block pass = ifNode.getPass(); |
|
1056 |
final Block fail = ifNode.getFail(); |
|
1057 |
||
1058 |
final Label failLabel = new Label("if_fail"); |
|
1059 |
final Label afterLabel = fail == null ? failLabel : new Label("if_done"); |
|
1060 |
||
1061 |
new BranchOptimizer(this, method).execute(test, failLabel, false); |
|
1062 |
||
1063 |
boolean passTerminal = false; |
|
1064 |
boolean failTerminal = false; |
|
1065 |
||
1066 |
pass.accept(this); |
|
1067 |
if (!pass.hasTerminalFlags()) { |
|
1068 |
method._goto(afterLabel); //don't fallthru to fail block |
|
1069 |
} else { |
|
1070 |
passTerminal = pass.isTerminal(); |
|
1071 |
} |
|
1072 |
||
1073 |
if (fail != null) { |
|
1074 |
method.label(failLabel); |
|
1075 |
fail.accept(this); |
|
1076 |
failTerminal = fail.isTerminal(); |
|
1077 |
} |
|
1078 |
||
1079 |
//if if terminates, put the after label there |
|
1080 |
if (!passTerminal || !failTerminal) { |
|
1081 |
method.label(afterLabel); |
|
1082 |
} |
|
1083 |
||
17233 | 1084 |
return false; |
16147 | 1085 |
} |
1086 |
||
1087 |
@Override |
|
17233 | 1088 |
public boolean enterIndexNode(final IndexNode indexNode) { |
16147 | 1089 |
load(indexNode); |
17233 | 1090 |
return false; |
16147 | 1091 |
} |
1092 |
||
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1093 |
private void lineNumber(final Statement statement) { |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1094 |
final int lineNumber = statement.getLineNumber(); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1095 |
if (lineNumber != lastLineNumber) { |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1096 |
method.lineNumber(statement.getLineNumber()); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1097 |
} |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1098 |
lastLineNumber = lineNumber; |
16147 | 1099 |
} |
1100 |
||
1101 |
/** |
|
1102 |
* Load a list of nodes as an array of a specific type |
|
1103 |
* The array will contain the visited nodes. |
|
1104 |
* |
|
1105 |
* @param arrayLiteralNode the array of contents |
|
1106 |
* @param arrayType the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT |
|
1107 |
* |
|
1108 |
* @return the method generator that was used |
|
1109 |
*/ |
|
1110 |
private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) { |
|
1111 |
assert arrayType == Type.INT_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY; |
|
1112 |
||
1113 |
final Node[] nodes = arrayLiteralNode.getValue(); |
|
1114 |
final Object presets = arrayLiteralNode.getPresets(); |
|
1115 |
final int[] postsets = arrayLiteralNode.getPostsets(); |
|
1116 |
final Class<?> type = arrayType.getTypeClass(); |
|
1117 |
final List<ArrayUnit> units = arrayLiteralNode.getUnits(); |
|
1118 |
||
1119 |
loadConstant(presets); |
|
1120 |
||
1121 |
final Type elementType = arrayType.getElementType(); |
|
1122 |
||
1123 |
if (units != null) { |
|
17233 | 1124 |
final MethodEmitter savedMethod = method; |
1125 |
||
1126 |
for (final ArrayUnit arrayUnit : units) { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1127 |
unit = lc.pushCompileUnit(arrayUnit.getCompileUnit()); |
17233 | 1128 |
|
1129 |
final String className = unit.getUnitClassName(); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1130 |
final String name = lc.getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName()); |
17233 | 1131 |
final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); |
1132 |
||
1133 |
final MethodEmitter me = unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1134 |
method = lc.pushMethodEmitter(me); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1135 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1136 |
method.setFunctionNode(lc.getCurrentFunction()); |
17233 | 1137 |
method.begin(); |
1138 |
||
1139 |
fixScopeSlot(); |
|
1140 |
||
1141 |
method.load(arrayType, SPLIT_ARRAY_ARG.slot()); |
|
1142 |
||
1143 |
for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) { |
|
1144 |
storeElement(nodes, elementType, postsets[i]); |
|
16147 | 1145 |
} |
17233 | 1146 |
|
1147 |
method._return(); |
|
1148 |
method.end(); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1149 |
method = lc.popMethodEmitter(me); |
17233 | 1150 |
|
1151 |
assert method == savedMethod; |
|
1152 |
method.loadCompilerConstant(THIS); |
|
1153 |
method.swap(); |
|
1154 |
method.loadCompilerConstant(CALLEE); |
|
1155 |
method.swap(); |
|
1156 |
method.loadCompilerConstant(SCOPE); |
|
1157 |
method.swap(); |
|
1158 |
method.invokestatic(className, name, signature); |
|
1159 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1160 |
unit = lc.popCompileUnit(unit); |
16147 | 1161 |
} |
1162 |
||
1163 |
return method; |
|
1164 |
} |
|
1165 |
||
1166 |
for (final int postset : postsets) { |
|
1167 |
storeElement(nodes, elementType, postset); |
|
1168 |
} |
|
1169 |
||
1170 |
return method; |
|
1171 |
} |
|
1172 |
||
1173 |
private void storeElement(final Node[] nodes, final Type elementType, final int index) { |
|
1174 |
method.dup(); |
|
1175 |
method.load(index); |
|
1176 |
||
1177 |
final Node element = nodes[index]; |
|
1178 |
||
1179 |
if (element == null) { |
|
1180 |
method.loadEmpty(elementType); |
|
1181 |
} else { |
|
1182 |
assert elementType.isEquivalentTo(element.getType()) : "array element type doesn't match array type"; |
|
1183 |
load(element); |
|
1184 |
} |
|
1185 |
||
1186 |
method.arraystore(); |
|
1187 |
} |
|
1188 |
||
1189 |
private MethodEmitter loadArgsArray(final List<Node> args) { |
|
1190 |
final Object[] array = new Object[args.size()]; |
|
1191 |
loadConstant(array); |
|
1192 |
||
1193 |
for (int i = 0; i < args.size(); i++) { |
|
1194 |
method.dup(); |
|
1195 |
method.load(i); |
|
1196 |
load(args.get(i)).convert(Type.OBJECT); //has to be upcast to object or we fail |
|
1197 |
method.arraystore(); |
|
1198 |
} |
|
1199 |
||
1200 |
return method; |
|
1201 |
} |
|
1202 |
||
1203 |
/** |
|
1204 |
* Load a constant from the constant array. This is only public to be callable from the objects |
|
1205 |
* subpackage. Do not call directly. |
|
1206 |
* |
|
1207 |
* @param string string to load |
|
1208 |
*/ |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1209 |
void loadConstant(final String string) { |
17233 | 1210 |
final String unitClassName = unit.getUnitClassName(); |
1211 |
final ClassEmitter classEmitter = unit.getClassEmitter(); |
|
16147 | 1212 |
final int index = compiler.getConstantData().add(string); |
1213 |
||
1214 |
method.load(index); |
|
17233 | 1215 |
method.invokestatic(unitClassName, GET_STRING.symbolName(), methodDescriptor(String.class, int.class)); |
16147 | 1216 |
classEmitter.needGetConstantMethod(String.class); |
1217 |
} |
|
1218 |
||
1219 |
/** |
|
1220 |
* Load a constant from the constant array. This is only public to be callable from the objects |
|
1221 |
* subpackage. Do not call directly. |
|
1222 |
* |
|
1223 |
* @param object object to load |
|
1224 |
*/ |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1225 |
void loadConstant(final Object object) { |
17233 | 1226 |
final String unitClassName = unit.getUnitClassName(); |
1227 |
final ClassEmitter classEmitter = unit.getClassEmitter(); |
|
16147 | 1228 |
final int index = compiler.getConstantData().add(object); |
1229 |
final Class<?> cls = object.getClass(); |
|
1230 |
||
1231 |
if (cls == PropertyMap.class) { |
|
1232 |
method.load(index); |
|
17233 | 1233 |
method.invokestatic(unitClassName, GET_MAP.symbolName(), methodDescriptor(PropertyMap.class, int.class)); |
16147 | 1234 |
classEmitter.needGetConstantMethod(PropertyMap.class); |
1235 |
} else if (cls.isArray()) { |
|
1236 |
method.load(index); |
|
1237 |
final String methodName = ClassEmitter.getArrayMethodName(cls); |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1238 |
method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class)); |
16147 | 1239 |
classEmitter.needGetConstantMethod(cls); |
1240 |
} else { |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
1241 |
method.loadConstants().load(index).arrayload(); |
16147 | 1242 |
if (cls != Object.class) { |
1243 |
method.checkcast(cls); |
|
1244 |
} |
|
1245 |
} |
|
1246 |
} |
|
1247 |
||
1248 |
// literal values |
|
1249 |
private MethodEmitter load(final LiteralNode<?> node) { |
|
1250 |
final Object value = node.getValue(); |
|
1251 |
||
1252 |
if (value == null) { |
|
1253 |
method.loadNull(); |
|
1254 |
} else if (value instanceof Undefined) { |
|
1255 |
method.loadUndefined(Type.OBJECT); |
|
1256 |
} else if (value instanceof String) { |
|
1257 |
final String string = (String)value; |
|
1258 |
||
1259 |
if (string.length() > (MethodEmitter.LARGE_STRING_THRESHOLD / 3)) { // 3 == max bytes per encoded char |
|
1260 |
loadConstant(string); |
|
1261 |
} else { |
|
1262 |
method.load(string); |
|
1263 |
} |
|
1264 |
} else if (value instanceof RegexToken) { |
|
1265 |
loadRegex((RegexToken)value); |
|
1266 |
} else if (value instanceof Boolean) { |
|
1267 |
method.load((Boolean)value); |
|
1268 |
} else if (value instanceof Integer) { |
|
1269 |
method.load((Integer)value); |
|
1270 |
} else if (value instanceof Long) { |
|
1271 |
method.load((Long)value); |
|
1272 |
} else if (value instanceof Double) { |
|
1273 |
method.load((Double)value); |
|
1274 |
} else if (node instanceof ArrayLiteralNode) { |
|
1275 |
final ArrayType type = (ArrayType)node.getType(); |
|
1276 |
loadArray((ArrayLiteralNode)node, type); |
|
1277 |
globalAllocateArray(type); |
|
1278 |
} else { |
|
1279 |
assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value; |
|
1280 |
} |
|
1281 |
||
1282 |
return method; |
|
1283 |
} |
|
1284 |
||
1285 |
private MethodEmitter loadRegexToken(final RegexToken value) { |
|
1286 |
method.load(value.getExpression()); |
|
1287 |
method.load(value.getOptions()); |
|
1288 |
return globalNewRegExp(); |
|
1289 |
} |
|
1290 |
||
1291 |
private MethodEmitter loadRegex(final RegexToken regexToken) { |
|
1292 |
if (regexFieldCount > MAX_REGEX_FIELDS) { |
|
1293 |
return loadRegexToken(regexToken); |
|
1294 |
} |
|
1295 |
// emit field |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1296 |
final String regexName = lc.getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName()); |
17233 | 1297 |
final ClassEmitter classEmitter = unit.getClassEmitter(); |
16147 | 1298 |
|
1299 |
classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class); |
|
1300 |
regexFieldCount++; |
|
1301 |
||
1302 |
// get field, if null create new regex, finally clone regex object |
|
17233 | 1303 |
method.getStatic(unit.getUnitClassName(), regexName, typeDescriptor(Object.class)); |
16147 | 1304 |
method.dup(); |
1305 |
final Label cachedLabel = new Label("cached"); |
|
1306 |
method.ifnonnull(cachedLabel); |
|
1307 |
||
1308 |
method.pop(); |
|
1309 |
loadRegexToken(regexToken); |
|
1310 |
method.dup(); |
|
17233 | 1311 |
method.putStatic(unit.getUnitClassName(), regexName, typeDescriptor(Object.class)); |
16147 | 1312 |
|
1313 |
method.label(cachedLabel); |
|
1314 |
globalRegExpCopy(); |
|
1315 |
||
1316 |
return method; |
|
1317 |
} |
|
1318 |
||
1319 |
@SuppressWarnings("rawtypes") |
|
1320 |
@Override |
|
17233 | 1321 |
public boolean enterLiteralNode(final LiteralNode literalNode) { |
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1322 |
assert literalNode.getSymbol() != null : literalNode + " has no symbol"; |
16147 | 1323 |
load(literalNode).store(literalNode.getSymbol()); |
17233 | 1324 |
return false; |
16147 | 1325 |
} |
1326 |
||
1327 |
@Override |
|
17233 | 1328 |
public boolean enterObjectNode(final ObjectNode objectNode) { |
17981
9b8e085aa1fe
8015955: ObjectNode.elements should be stronger typed
attila
parents:
17969
diff
changeset
|
1329 |
final List<PropertyNode> elements = objectNode.getElements(); |
16147 | 1330 |
|
1331 |
final List<String> keys = new ArrayList<>(); |
|
1332 |
final List<Symbol> symbols = new ArrayList<>(); |
|
1333 |
final List<Node> values = new ArrayList<>(); |
|
1334 |
||
1335 |
boolean hasGettersSetters = false; |
|
1336 |
||
17981
9b8e085aa1fe
8015955: ObjectNode.elements should be stronger typed
attila
parents:
17969
diff
changeset
|
1337 |
for (PropertyNode propertyNode: elements) { |
16147 | 1338 |
final Node value = propertyNode.getValue(); |
1339 |
final String key = propertyNode.getKeyName(); |
|
1340 |
final Symbol symbol = value == null ? null : propertyNode.getSymbol(); |
|
1341 |
||
1342 |
if (value == null) { |
|
1343 |
hasGettersSetters = true; |
|
1344 |
} |
|
1345 |
||
1346 |
keys.add(key); |
|
1347 |
symbols.add(symbol); |
|
1348 |
values.add(value); |
|
1349 |
} |
|
1350 |
||
1351 |
new FieldObjectCreator<Node>(this, keys, symbols, values) { |
|
1352 |
@Override |
|
1353 |
protected void loadValue(final Node node) { |
|
1354 |
load(node); |
|
1355 |
} |
|
1356 |
||
1357 |
/** |
|
1358 |
* Ensure that the properties start out as object types so that |
|
1359 |
* we can do putfield initializations instead of dynamicSetIndex |
|
1360 |
* which would be the case to determine initial property type |
|
1361 |
* otherwise. |
|
1362 |
* |
|
1363 |
* Use case, it's very expensive to do a million var x = {a:obj, b:obj} |
|
1364 |
* just to have to invalidate them immediately on initialization |
|
1365 |
* |
|
1366 |
* see NASHORN-594 |
|
1367 |
*/ |
|
1368 |
@Override |
|
1369 |
protected MapCreator newMapCreator(final Class<?> fieldObjectClass) { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1370 |
return new MapCreator(fieldObjectClass, keys, symbols) { |
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1371 |
@Override |
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1372 |
protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) { |
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1373 |
return super.getPropertyFlags(symbol, isVarArg) | Property.IS_ALWAYS_OBJECT; |
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1374 |
} |
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1375 |
}; |
16147 | 1376 |
} |
1377 |
||
1378 |
}.makeObject(method); |
|
1379 |
||
1380 |
method.dup(); |
|
1381 |
globalObjectPrototype(); |
|
1382 |
method.invoke(ScriptObject.SET_PROTO); |
|
1383 |
||
1384 |
if (!hasGettersSetters) { |
|
1385 |
method.store(objectNode.getSymbol()); |
|
17233 | 1386 |
return false; |
16147 | 1387 |
} |
1388 |
||
1389 |
for (final Node element : elements) { |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
1390 |
final PropertyNode propertyNode = (PropertyNode)element; |
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
1391 |
final Object key = propertyNode.getKey(); |
17233 | 1392 |
final FunctionNode getter = propertyNode.getGetter(); |
1393 |
final FunctionNode setter = propertyNode.getSetter(); |
|
16147 | 1394 |
|
1395 |
if (getter == null && setter == null) { |
|
1396 |
continue; |
|
1397 |
} |
|
1398 |
||
1399 |
method.dup().loadKey(key); |
|
1400 |
||
1401 |
if (getter == null) { |
|
1402 |
method.loadNull(); |
|
1403 |
} else { |
|
1404 |
getter.accept(this); |
|
1405 |
} |
|
1406 |
||
1407 |
if (setter == null) { |
|
1408 |
method.loadNull(); |
|
1409 |
} else { |
|
1410 |
setter.accept(this); |
|
1411 |
} |
|
1412 |
||
1413 |
method.invoke(ScriptObject.SET_USER_ACCESSORS); |
|
1414 |
} |
|
1415 |
||
1416 |
method.store(objectNode.getSymbol()); |
|
1417 |
||
17233 | 1418 |
return false; |
16147 | 1419 |
} |
1420 |
||
1421 |
@Override |
|
17233 | 1422 |
public boolean enterReturnNode(final ReturnNode returnNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1423 |
lineNumber(returnNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1424 |
|
17233 | 1425 |
method.registerReturn(); |
1426 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1427 |
final Type returnType = lc.getCurrentFunction().getReturnType(); |
16147 | 1428 |
|
1429 |
final Node expression = returnNode.getExpression(); |
|
1430 |
if (expression != null) { |
|
1431 |
load(expression); |
|
1432 |
} else { |
|
17233 | 1433 |
method.loadUndefined(returnType); |
16147 | 1434 |
} |
1435 |
||
17233 | 1436 |
method._return(returnType); |
1437 |
||
1438 |
return false; |
|
16147 | 1439 |
} |
1440 |
||
1441 |
private static boolean isNullLiteral(final Node node) { |
|
1442 |
return node instanceof LiteralNode<?> && ((LiteralNode<?>) node).isNull(); |
|
1443 |
} |
|
1444 |
||
1445 |
private boolean nullCheck(final RuntimeNode runtimeNode, final List<Node> args, final String signature) { |
|
1446 |
final Request request = runtimeNode.getRequest(); |
|
1447 |
||
1448 |
if (!Request.isEQ(request) && !Request.isNE(request)) { |
|
1449 |
return false; |
|
1450 |
} |
|
1451 |
||
1452 |
assert args.size() == 2 : "EQ or NE or TYPEOF need two args"; |
|
1453 |
||
1454 |
Node lhs = args.get(0); |
|
1455 |
Node rhs = args.get(1); |
|
1456 |
||
1457 |
if (isNullLiteral(lhs)) { |
|
1458 |
final Node tmp = lhs; |
|
1459 |
lhs = rhs; |
|
1460 |
rhs = tmp; |
|
1461 |
} |
|
1462 |
||
1463 |
if (isNullLiteral(rhs)) { |
|
1464 |
final Label trueLabel = new Label("trueLabel"); |
|
1465 |
final Label falseLabel = new Label("falseLabel"); |
|
1466 |
final Label endLabel = new Label("end"); |
|
1467 |
||
1468 |
load(lhs); |
|
1469 |
method.dup(); |
|
1470 |
if (Request.isEQ(request)) { |
|
1471 |
method.ifnull(trueLabel); |
|
1472 |
} else if (Request.isNE(request)) { |
|
1473 |
method.ifnonnull(trueLabel); |
|
1474 |
} else { |
|
1475 |
assert false : "Invalid request " + request; |
|
1476 |
} |
|
1477 |
||
1478 |
method.label(falseLabel); |
|
1479 |
load(rhs); |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1480 |
method.invokestatic(CompilerConstants.className(ScriptRuntime.class), request.toString(), signature); |
16147 | 1481 |
method._goto(endLabel); |
1482 |
||
1483 |
method.label(trueLabel); |
|
1484 |
// if NE (not strict) this can be "undefined != null" which is supposed to be false |
|
1485 |
if (request == Request.NE) { |
|
1486 |
method.loadUndefined(Type.OBJECT); |
|
1487 |
final Label isUndefined = new Label("isUndefined"); |
|
1488 |
final Label afterUndefinedCheck = new Label("afterUndefinedCheck"); |
|
1489 |
method.if_acmpeq(isUndefined); |
|
1490 |
// not undefined |
|
1491 |
method.load(true); |
|
1492 |
method._goto(afterUndefinedCheck); |
|
1493 |
method.label(isUndefined); |
|
1494 |
method.load(false); |
|
1495 |
method.label(afterUndefinedCheck); |
|
1496 |
} else { |
|
1497 |
method.pop(); |
|
1498 |
method.load(true); |
|
1499 |
} |
|
1500 |
method.label(endLabel); |
|
1501 |
method.convert(runtimeNode.getType()); |
|
1502 |
method.store(runtimeNode.getSymbol()); |
|
1503 |
||
1504 |
return true; |
|
1505 |
} |
|
1506 |
||
1507 |
return false; |
|
1508 |
} |
|
1509 |
||
1510 |
private boolean specializationCheck(final RuntimeNode.Request request, final Node node, final List<Node> args) { |
|
1511 |
if (!request.canSpecialize()) { |
|
1512 |
return false; |
|
1513 |
} |
|
1514 |
||
1515 |
assert args.size() == 2; |
|
1516 |
final Type returnType = node.getType(); |
|
17233 | 1517 |
|
1518 |
load(args.get(0)); |
|
1519 |
load(args.get(1)); |
|
16147 | 1520 |
|
1521 |
Request finalRequest = request; |
|
1522 |
||
17233 | 1523 |
//if the request is a comparison, i.e. one that can be reversed |
1524 |
//it keeps its semantic, but make sure that the object comes in |
|
1525 |
//last |
|
16147 | 1526 |
final Request reverse = Request.reverse(request); |
17233 | 1527 |
if (method.peekType().isObject() && reverse != null) { //rhs is object |
1528 |
if (!method.peekType(1).isObject()) { //lhs is not object |
|
1529 |
method.swap(); //prefer object as lhs |
|
16147 | 1530 |
finalRequest = reverse; |
1531 |
} |
|
1532 |
} |
|
1533 |
||
1534 |
method.dynamicRuntimeCall( |
|
1535 |
new SpecializedRuntimeNode( |
|
1536 |
finalRequest, |
|
1537 |
new Type[] { |
|
1538 |
method.peekType(1), |
|
1539 |
method.peekType() |
|
1540 |
}, |
|
1541 |
returnType).getInitialName(), |
|
1542 |
returnType, |
|
1543 |
finalRequest); |
|
1544 |
||
1545 |
method.convert(node.getType()); |
|
1546 |
method.store(node.getSymbol()); |
|
1547 |
||
1548 |
return true; |
|
1549 |
} |
|
1550 |
||
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
1551 |
private static boolean isReducible(final Request request) { |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
1552 |
return Request.isComparison(request) || request == Request.ADD; |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
1553 |
} |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
1554 |
|
16147 | 1555 |
@Override |
17233 | 1556 |
public boolean enterRuntimeNode(final RuntimeNode runtimeNode) { |
16147 | 1557 |
/* |
1558 |
* First check if this should be something other than a runtime node |
|
1559 |
* AccessSpecializer might have changed the type |
|
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1560 |
* |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1561 |
* TODO - remove this - Access Specializer will always know after Attr/Lower |
16147 | 1562 |
*/ |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
1563 |
if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) { |
16147 | 1564 |
final Node lhs = runtimeNode.getArgs().get(0); |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
1565 |
assert runtimeNode.getArgs().size() > 1 : runtimeNode + " must have two args"; |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
1566 |
final Node rhs = runtimeNode.getArgs().get(1); |
16147 | 1567 |
|
1568 |
final Type type = runtimeNode.getType(); |
|
1569 |
final Symbol symbol = runtimeNode.getSymbol(); |
|
1570 |
||
1571 |
switch (runtimeNode.getRequest()) { |
|
1572 |
case EQ: |
|
1573 |
case EQ_STRICT: |
|
1574 |
return enterCmp(lhs, rhs, Condition.EQ, type, symbol); |
|
1575 |
case NE: |
|
1576 |
case NE_STRICT: |
|
1577 |
return enterCmp(lhs, rhs, Condition.NE, type, symbol); |
|
1578 |
case LE: |
|
1579 |
return enterCmp(lhs, rhs, Condition.LE, type, symbol); |
|
1580 |
case LT: |
|
1581 |
return enterCmp(lhs, rhs, Condition.LT, type, symbol); |
|
1582 |
case GE: |
|
1583 |
return enterCmp(lhs, rhs, Condition.GE, type, symbol); |
|
1584 |
case GT: |
|
1585 |
return enterCmp(lhs, rhs, Condition.GT, type, symbol); |
|
1586 |
case ADD: |
|
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1587 |
Type widest = Type.widest(lhs.getType(), rhs.getType()); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1588 |
load(lhs); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1589 |
method.convert(widest); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1590 |
load(rhs); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1591 |
method.convert(widest); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1592 |
method.add(); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1593 |
method.convert(type); |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1594 |
method.store(symbol); |
17233 | 1595 |
return false; |
16147 | 1596 |
default: |
1597 |
// it's ok to send this one on with only primitive arguments, maybe INSTANCEOF(true, true) or similar |
|
1598 |
// assert false : runtimeNode + " has all primitive arguments. This is an inconsistent state"; |
|
1599 |
break; |
|
1600 |
} |
|
1601 |
} |
|
1602 |
||
1603 |
// Get the request arguments. |
|
1604 |
final List<Node> args = runtimeNode.getArgs(); |
|
1605 |
||
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
1606 |
if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) { |
17233 | 1607 |
return false; |
16147 | 1608 |
} |
1609 |
||
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
1610 |
if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) { |
17233 | 1611 |
return false; |
16147 | 1612 |
} |
1613 |
||
1614 |
for (final Node arg : runtimeNode.getArgs()) { |
|
1615 |
load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower |
|
1616 |
} |
|
1617 |
||
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1618 |
method.invokestatic( |
16147 | 1619 |
CompilerConstants.className(ScriptRuntime.class), |
1620 |
runtimeNode.getRequest().toString(), |
|
1621 |
new FunctionSignature( |
|
1622 |
false, |
|
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
1623 |
false, |
16147 | 1624 |
runtimeNode.getType(), |
1625 |
runtimeNode.getArgs().size()).toString()); |
|
1626 |
method.convert(runtimeNode.getType()); |
|
1627 |
method.store(runtimeNode.getSymbol()); |
|
1628 |
||
17233 | 1629 |
return false; |
16147 | 1630 |
} |
1631 |
||
1632 |
@Override |
|
17233 | 1633 |
public boolean enterSplitNode(final SplitNode splitNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1634 |
lineNumber(splitNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1635 |
|
16147 | 1636 |
final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); |
1637 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1638 |
final FunctionNode fn = lc.getCurrentFunction(); |
16147 | 1639 |
final String className = splitCompileUnit.getUnitClassName(); |
1640 |
final String name = splitNode.getName(); |
|
1641 |
||
17233 | 1642 |
final Class<?> rtype = fn.getReturnType().getTypeClass(); |
1643 |
final boolean needsArguments = fn.needsArguments(); |
|
1644 |
final Class<?>[] ptypes = needsArguments ? |
|
16225
81d58c2b9fcf
8006943: Fix order of function method arguments to be (callee, thisObject)
attila
parents:
16210
diff
changeset
|
1645 |
new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class, Object.class} : |
81d58c2b9fcf
8006943: Fix order of function method arguments to be (callee, thisObject)
attila
parents:
16210
diff
changeset
|
1646 |
new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class}; |
16147 | 1647 |
|
17233 | 1648 |
final MethodEmitter caller = method; |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1649 |
unit = lc.pushCompileUnit(splitCompileUnit); |
16147 | 1650 |
|
1651 |
final Call splitCall = staticCallNoLookup( |
|
1652 |
className, |
|
1653 |
name, |
|
1654 |
methodDescriptor(rtype, ptypes)); |
|
1655 |
||
17233 | 1656 |
final MethodEmitter splitEmitter = |
1657 |
splitCompileUnit.getClassEmitter().method( |
|
1658 |
splitNode, |
|
1659 |
name, |
|
1660 |
rtype, |
|
1661 |
ptypes); |
|
1662 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1663 |
method = lc.pushMethodEmitter(splitEmitter); |
16147 | 1664 |
method.setFunctionNode(fn); |
17233 | 1665 |
|
1666 |
if (fn.needsCallee()) { |
|
1667 |
caller.loadCompilerConstant(CALLEE); |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
1668 |
} else { |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
1669 |
caller.loadNull(); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
1670 |
} |
17233 | 1671 |
caller.loadCompilerConstant(THIS); |
1672 |
caller.loadCompilerConstant(SCOPE); |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
1673 |
if (needsArguments) { |
17233 | 1674 |
caller.loadCompilerConstant(ARGUMENTS); |
16147 | 1675 |
} |
1676 |
caller.invoke(splitCall); |
|
17233 | 1677 |
caller.storeCompilerConstant(RETURN); |
16147 | 1678 |
|
1679 |
method.begin(); |
|
1680 |
||
1681 |
method.loadUndefined(fn.getReturnType()); |
|
17233 | 1682 |
method.storeCompilerConstant(RETURN); |
16147 | 1683 |
|
1684 |
fixScopeSlot(); |
|
1685 |
||
17233 | 1686 |
return true; |
16147 | 1687 |
} |
1688 |
||
1689 |
private void fixScopeSlot() { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1690 |
if (lc.getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) { |
16147 | 1691 |
// TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method) |
1692 |
method.load(Type.typeFor(ScriptObject.class), SCOPE.slot()); |
|
17233 | 1693 |
method.storeCompilerConstant(SCOPE); |
16147 | 1694 |
} |
1695 |
} |
|
1696 |
||
1697 |
@Override |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
1698 |
public Node leaveSplitNode(final SplitNode splitNode) { |
17233 | 1699 |
assert method instanceof SplitMethodEmitter; |
1700 |
final boolean hasReturn = method.hasReturn(); |
|
1701 |
final List<Label> targets = method.getExternalTargets(); |
|
1702 |
||
16147 | 1703 |
try { |
1704 |
// Wrap up this method. |
|
17233 | 1705 |
|
1706 |
method.loadCompilerConstant(RETURN); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1707 |
method._return(lc.getCurrentFunction().getReturnType()); |
16147 | 1708 |
method.end(); |
17233 | 1709 |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1710 |
unit = lc.popCompileUnit(splitNode.getCompileUnit()); |
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1711 |
method = lc.popMethodEmitter(method); |
17233 | 1712 |
|
16147 | 1713 |
} catch (final Throwable t) { |
1714 |
Context.printStackTrace(t); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1715 |
final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + lc.getCurrentFunction().getSource().getName()); |
16147 | 1716 |
e.initCause(t); |
1717 |
throw e; |
|
1718 |
} |
|
1719 |
||
1720 |
// Handle return from split method if there was one. |
|
17233 | 1721 |
final MethodEmitter caller = method; |
1722 |
final int targetCount = targets.size(); |
|
1723 |
||
1724 |
//no external jump targets or return in switch node |
|
1725 |
if (!hasReturn && targets.isEmpty()) { |
|
1726 |
return splitNode; |
|
1727 |
} |
|
1728 |
||
1729 |
caller.loadCompilerConstant(SCOPE); |
|
1730 |
caller.checkcast(Scope.class); |
|
1731 |
caller.invoke(Scope.GET_SPLIT_STATE); |
|
1732 |
||
1733 |
final Label breakLabel = new Label("no_split_state"); |
|
1734 |
// Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue |
|
1735 |
||
1736 |
//the common case is that we don't need a switch |
|
1737 |
if (targetCount == 0) { |
|
1738 |
assert hasReturn; |
|
1739 |
caller.ifne(breakLabel); |
|
1740 |
//has to be zero |
|
1741 |
caller.label(new Label("split_return")); |
|
1742 |
method.loadCompilerConstant(RETURN); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1743 |
caller._return(lc.getCurrentFunction().getReturnType()); |
17233 | 1744 |
caller.label(breakLabel); |
1745 |
} else { |
|
1746 |
assert !targets.isEmpty(); |
|
1747 |
||
1748 |
final int low = hasReturn ? 0 : 1; |
|
1749 |
final int labelCount = targetCount + 1 - low; |
|
1750 |
final Label[] labels = new Label[labelCount]; |
|
16147 | 1751 |
|
1752 |
for (int i = 0; i < labelCount; i++) { |
|
17233 | 1753 |
labels[i] = new Label(i == 0 ? "split_return" : "split_" + targets.get(i - 1)); |
16147 | 1754 |
} |
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1755 |
caller.tableswitch(low, targetCount, breakLabel, labels); |
16147 | 1756 |
for (int i = low; i <= targetCount; i++) { |
1757 |
caller.label(labels[i - low]); |
|
1758 |
if (i == 0) { |
|
17233 | 1759 |
caller.loadCompilerConstant(RETURN); |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1760 |
caller._return(lc.getCurrentFunction().getReturnType()); |
16147 | 1761 |
} else { |
1762 |
// Clear split state. |
|
17233 | 1763 |
caller.loadCompilerConstant(SCOPE); |
16147 | 1764 |
caller.checkcast(Scope.class); |
1765 |
caller.load(-1); |
|
1766 |
caller.invoke(Scope.SET_SPLIT_STATE); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1767 |
caller.splitAwareGoto(lc, targets.get(i - 1)); |
16147 | 1768 |
} |
1769 |
} |
|
1770 |
caller.label(breakLabel); |
|
1771 |
} |
|
1772 |
||
1773 |
return splitNode; |
|
1774 |
} |
|
1775 |
||
1776 |
@Override |
|
17233 | 1777 |
public boolean enterSwitchNode(final SwitchNode switchNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1778 |
lineNumber(switchNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1779 |
|
16147 | 1780 |
final Node expression = switchNode.getExpression(); |
1781 |
final Symbol tag = switchNode.getTag(); |
|
1782 |
final boolean allInteger = tag.getSymbolType().isInteger(); |
|
1783 |
final List<CaseNode> cases = switchNode.getCases(); |
|
1784 |
final CaseNode defaultCase = switchNode.getDefaultCase(); |
|
1785 |
final Label breakLabel = switchNode.getBreakLabel(); |
|
1786 |
||
1787 |
Label defaultLabel = breakLabel; |
|
1788 |
boolean hasDefault = false; |
|
1789 |
||
1790 |
if (defaultCase != null) { |
|
1791 |
defaultLabel = defaultCase.getEntry(); |
|
1792 |
hasDefault = true; |
|
1793 |
} |
|
1794 |
||
1795 |
if (cases.isEmpty()) { |
|
1796 |
method.label(breakLabel); |
|
17233 | 1797 |
return false; |
16147 | 1798 |
} |
1799 |
||
1800 |
if (allInteger) { |
|
1801 |
// Tree for sorting values. |
|
1802 |
final TreeMap<Integer, Label> tree = new TreeMap<>(); |
|
1803 |
||
1804 |
// Build up sorted tree. |
|
1805 |
for (final CaseNode caseNode : cases) { |
|
1806 |
final Node test = caseNode.getTest(); |
|
1807 |
||
1808 |
if (test != null) { |
|
16235
cc200fdc3478
8008206: The allInteger case for SwitchNode generation in CodeGenerator assumes integer LITERALS only.
lagergren
parents:
16233
diff
changeset
|
1809 |
final Integer value = (Integer)((LiteralNode<?>)test).getValue(); |
16147 | 1810 |
final Label entry = caseNode.getEntry(); |
1811 |
||
1812 |
// Take first duplicate. |
|
1813 |
if (!(tree.containsKey(value))) { |
|
1814 |
tree.put(value, entry); |
|
1815 |
} |
|
1816 |
} |
|
1817 |
} |
|
1818 |
||
1819 |
// Copy values and labels to arrays. |
|
1820 |
final int size = tree.size(); |
|
1821 |
final Integer[] values = tree.keySet().toArray(new Integer[size]); |
|
1822 |
final Label[] labels = tree.values().toArray(new Label[size]); |
|
1823 |
||
1824 |
// Discern low, high and range. |
|
1825 |
final int lo = values[0]; |
|
1826 |
final int hi = values[size - 1]; |
|
1827 |
final int range = hi - lo + 1; |
|
1828 |
||
1829 |
// Find an unused value for default. |
|
1830 |
int deflt = Integer.MIN_VALUE; |
|
1831 |
for (final int value : values) { |
|
1832 |
if (deflt == value) { |
|
1833 |
deflt++; |
|
1834 |
} else if (deflt < value) { |
|
1835 |
break; |
|
1836 |
} |
|
1837 |
} |
|
1838 |
||
1839 |
// Load switch expression. |
|
1840 |
load(expression); |
|
1841 |
final Type type = expression.getType(); |
|
1842 |
||
1843 |
// If expression not int see if we can convert, if not use deflt to trigger default. |
|
1844 |
if (!type.isInteger()) { |
|
1845 |
method.load(deflt); |
|
1846 |
method.invoke(staticCallNoLookup(ScriptRuntime.class, "switchTagAsInt", int.class, type.getTypeClass(), int.class)); |
|
1847 |
} |
|
1848 |
||
1849 |
// If reasonable size and not too sparse (80%), use table otherwise use lookup. |
|
1850 |
if (range > 0 && range < 4096 && range < (size * 5 / 4)) { |
|
1851 |
final Label[] table = new Label[range]; |
|
1852 |
Arrays.fill(table, defaultLabel); |
|
1853 |
||
1854 |
for (int i = 0; i < size; i++) { |
|
1855 |
final int value = values[i]; |
|
1856 |
table[value - lo] = labels[i]; |
|
1857 |
} |
|
1858 |
||
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1859 |
method.tableswitch(lo, hi, defaultLabel, table); |
16147 | 1860 |
} else { |
1861 |
final int[] ints = new int[size]; |
|
1862 |
for (int i = 0; i < size; i++) { |
|
1863 |
ints[i] = values[i]; |
|
1864 |
} |
|
1865 |
||
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1866 |
method.lookupswitch(defaultLabel, ints, labels); |
16147 | 1867 |
} |
1868 |
} else { |
|
1869 |
load(expression); |
|
1870 |
||
1871 |
if (expression.getType().isInteger()) { |
|
1872 |
method.convert(Type.NUMBER).dup(); |
|
1873 |
method.store(tag); |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
1874 |
method.conditionalJump(Condition.NE, true, defaultLabel); |
16147 | 1875 |
} else { |
1876 |
method.store(tag); |
|
1877 |
} |
|
1878 |
||
1879 |
for (final CaseNode caseNode : cases) { |
|
1880 |
final Node test = caseNode.getTest(); |
|
1881 |
||
1882 |
if (test != null) { |
|
1883 |
method.load(tag); |
|
1884 |
load(test); |
|
1885 |
method.invoke(ScriptRuntime.EQ_STRICT); |
|
1886 |
method.ifne(caseNode.getEntry()); |
|
1887 |
} |
|
1888 |
} |
|
1889 |
||
1890 |
method._goto(hasDefault ? defaultLabel : breakLabel); |
|
1891 |
} |
|
1892 |
||
1893 |
for (final CaseNode caseNode : cases) { |
|
1894 |
method.label(caseNode.getEntry()); |
|
1895 |
caseNode.getBody().accept(this); |
|
1896 |
} |
|
1897 |
||
1898 |
if (!switchNode.isTerminal()) { |
|
1899 |
method.label(breakLabel); |
|
1900 |
} |
|
1901 |
||
17233 | 1902 |
return false; |
16147 | 1903 |
} |
1904 |
||
1905 |
@Override |
|
17233 | 1906 |
public boolean enterThrowNode(final ThrowNode throwNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1907 |
lineNumber(throwNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1908 |
|
17745
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1909 |
if (throwNode.isSyntheticRethrow()) { |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1910 |
//do not wrap whatever this is in an ecma exception, just rethrow it |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1911 |
load(throwNode.getExpression()); |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1912 |
method.athrow(); |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1913 |
return false; |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1914 |
} |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1915 |
|
16147 | 1916 |
method._new(ECMAException.class).dup(); |
1917 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1918 |
final Source source = lc.getCurrentFunction().getSource(); |
17523
cb4a7c901e0d
8013913: Removed Source field from all nodes except FunctionNode in order to save footprint
lagergren
parents:
17518
diff
changeset
|
1919 |
|
16147 | 1920 |
final Node expression = throwNode.getExpression(); |
1921 |
final int position = throwNode.position(); |
|
1922 |
final int line = source.getLine(position); |
|
1923 |
final int column = source.getColumn(position); |
|
1924 |
||
1925 |
load(expression); |
|
1926 |
assert expression.getType().isObject(); |
|
1927 |
||
1928 |
method.load(source.getName()); |
|
1929 |
method.load(line); |
|
1930 |
method.load(column); |
|
1931 |
method.invoke(ECMAException.THROW_INIT); |
|
1932 |
||
1933 |
method.athrow(); |
|
1934 |
||
17233 | 1935 |
return false; |
16147 | 1936 |
} |
1937 |
||
1938 |
@Override |
|
17233 | 1939 |
public boolean enterTryNode(final TryNode tryNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1940 |
lineNumber(tryNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
1941 |
|
16147 | 1942 |
final Block body = tryNode.getBody(); |
1943 |
final List<Block> catchBlocks = tryNode.getCatchBlocks(); |
|
1944 |
final Symbol symbol = tryNode.getException(); |
|
1945 |
final Label entry = new Label("try"); |
|
1946 |
final Label recovery = new Label("catch"); |
|
1947 |
final Label exit = tryNode.getExit(); |
|
1948 |
final Label skip = new Label("skip"); |
|
1949 |
||
1950 |
method.label(entry); |
|
1951 |
||
1952 |
body.accept(this); |
|
1953 |
||
1954 |
if (!body.hasTerminalFlags()) { |
|
1955 |
method._goto(skip); |
|
1956 |
} |
|
1957 |
||
1958 |
method.label(exit); |
|
1959 |
||
1960 |
method._catch(recovery); |
|
1961 |
method.store(symbol); |
|
1962 |
||
1963 |
for (int i = 0; i < catchBlocks.size(); i++) { |
|
1964 |
final Block catchBlock = catchBlocks.get(i); |
|
1965 |
||
17233 | 1966 |
//TODO this is very ugly - try not to call enter/leave methods directly |
1967 |
//better to use the implicit lexical context scoping given by the visitor's |
|
1968 |
//accept method. |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1969 |
lc.push(catchBlock); |
17233 | 1970 |
enterBlock(catchBlock); |
1971 |
||
1972 |
final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0); |
|
1973 |
final IdentNode exception = catchNode.getException(); |
|
1974 |
final Node exceptionCondition = catchNode.getExceptionCondition(); |
|
1975 |
final Block catchBody = catchNode.getBody(); |
|
1976 |
||
1977 |
new Store<IdentNode>(exception) { |
|
1978 |
@Override |
|
1979 |
protected void storeNonDiscard() { |
|
1980 |
return; |
|
16147 | 1981 |
} |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
1982 |
|
17233 | 1983 |
@Override |
1984 |
protected void evaluate() { |
|
17745
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1985 |
if (catchNode.isSyntheticRethrow()) { |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1986 |
method.load(symbol); |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1987 |
return; |
86e5a15b3b20
8014426: Original exception no longer thrown away when a finally rethrows
lagergren
parents:
17524
diff
changeset
|
1988 |
} |
17233 | 1989 |
/* |
1990 |
* If caught object is an instance of ECMAException, then |
|
1991 |
* bind obj.thrown to the script catch var. Or else bind the |
|
1992 |
* caught object itself to the script catch var. |
|
1993 |
*/ |
|
1994 |
final Label notEcmaException = new Label("no_ecma_exception"); |
|
1995 |
method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException); |
|
1996 |
method.checkcast(ECMAException.class); //TODO is this necessary? |
|
1997 |
method.getField(ECMAException.THROWN); |
|
1998 |
method.label(notEcmaException); |
|
1999 |
} |
|
2000 |
}.store(); |
|
2001 |
||
2002 |
final Label next; |
|
2003 |
||
2004 |
if (exceptionCondition != null) { |
|
2005 |
next = new Label("next"); |
|
2006 |
load(exceptionCondition).convert(Type.BOOLEAN).ifeq(next); |
|
2007 |
} else { |
|
2008 |
next = null; |
|
2009 |
} |
|
2010 |
||
2011 |
catchBody.accept(this); |
|
2012 |
||
2013 |
if (i + 1 != catchBlocks.size() && !catchBody.hasTerminalFlags()) { |
|
2014 |
method._goto(skip); |
|
2015 |
} |
|
2016 |
||
2017 |
if (next != null) { |
|
2018 |
if (i + 1 == catchBlocks.size()) { |
|
2019 |
// no next catch block - rethrow if condition failed |
|
2020 |
method._goto(skip); |
|
2021 |
method.label(next); |
|
2022 |
method.load(symbol).athrow(); |
|
16147 | 2023 |
} else { |
17233 | 2024 |
method.label(next); |
16147 | 2025 |
} |
2026 |
} |
|
17233 | 2027 |
|
2028 |
leaveBlock(catchBlock); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2029 |
lc.pop(catchBlock); |
16147 | 2030 |
} |
2031 |
||
2032 |
method.label(skip); |
|
2033 |
method._try(entry, exit, recovery, Throwable.class); |
|
2034 |
||
2035 |
// Finally body is always inlined elsewhere so it doesn't need to be emitted |
|
2036 |
||
17233 | 2037 |
return false; |
16147 | 2038 |
} |
2039 |
||
2040 |
@Override |
|
17233 | 2041 |
public boolean enterVarNode(final VarNode varNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2042 |
|
16147 | 2043 |
final Node init = varNode.getInit(); |
2044 |
||
17233 | 2045 |
if (init == null) { |
2046 |
return false; |
|
16147 | 2047 |
} |
2048 |
||
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2049 |
lineNumber(varNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2050 |
|
16147 | 2051 |
final Symbol varSymbol = varNode.getSymbol(); |
2052 |
assert varSymbol != null : "variable node " + varNode + " requires a symbol"; |
|
2053 |
||
2054 |
assert method != null; |
|
2055 |
||
2056 |
final boolean needsScope = varSymbol.isScope(); |
|
2057 |
if (needsScope) { |
|
17233 | 2058 |
method.loadCompilerConstant(SCOPE); |
16147 | 2059 |
} |
2060 |
load(init); |
|
2061 |
||
2062 |
if (needsScope) { |
|
2063 |
int flags = CALLSITE_SCOPE | getCallSiteFlags(); |
|
2064 |
final IdentNode identNode = varNode.getName(); |
|
2065 |
final Type type = identNode.getType(); |
|
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
2066 |
if (isFastScope(varSymbol)) { |
16147 | 2067 |
storeFastScopeVar(type, varSymbol, flags); |
2068 |
} else { |
|
2069 |
method.dynamicSet(type, identNode.getName(), flags); |
|
2070 |
} |
|
2071 |
} else { |
|
2072 |
assert varNode.getType() == varNode.getName().getType() : "varNode type=" + varNode.getType() + " nametype=" + varNode.getName().getType() + " inittype=" + init.getType(); |
|
2073 |
||
2074 |
method.convert(varNode.getType()); // aw: convert moved here |
|
2075 |
method.store(varSymbol); |
|
2076 |
} |
|
2077 |
||
17233 | 2078 |
return false; |
16147 | 2079 |
} |
2080 |
||
2081 |
@Override |
|
17233 | 2082 |
public boolean enterWhileNode(final WhileNode whileNode) { |
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2083 |
lineNumber(whileNode); |
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2084 |
|
16147 | 2085 |
final Node test = whileNode.getTest(); |
2086 |
final Block body = whileNode.getBody(); |
|
2087 |
final Label breakLabel = whileNode.getBreakLabel(); |
|
2088 |
final Label continueLabel = whileNode.getContinueLabel(); |
|
2089 |
final Label loopLabel = new Label("loop"); |
|
2090 |
||
17233 | 2091 |
if (!whileNode.isDoWhile()) { |
16147 | 2092 |
method._goto(continueLabel); |
2093 |
} |
|
2094 |
||
2095 |
method.label(loopLabel); |
|
2096 |
body.accept(this); |
|
2097 |
if (!whileNode.isTerminal()) { |
|
2098 |
method.label(continueLabel); |
|
2099 |
new BranchOptimizer(this, method).execute(test, loopLabel, true); |
|
2100 |
method.label(breakLabel); |
|
2101 |
} |
|
2102 |
||
17233 | 2103 |
return false; |
16147 | 2104 |
} |
2105 |
||
2106 |
private void closeWith() { |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2107 |
if (method.hasScope()) { |
17255 | 2108 |
method.loadCompilerConstant(SCOPE); |
2109 |
method.invoke(ScriptRuntime.CLOSE_WITH); |
|
2110 |
method.storeCompilerConstant(SCOPE); |
|
2111 |
} |
|
16147 | 2112 |
} |
2113 |
||
2114 |
@Override |
|
17233 | 2115 |
public boolean enterWithNode(final WithNode withNode) { |
16147 | 2116 |
final Node expression = withNode.getExpression(); |
2117 |
final Node body = withNode.getBody(); |
|
2118 |
||
17255 | 2119 |
// It is possible to have a "pathological" case where the with block does not reference *any* identifiers. It's |
2120 |
// pointless, but legal. In that case, if nothing else in the method forced the assignment of a slot to the |
|
2121 |
// scope object, its' possible that it won't have a slot assigned. In this case we'll only evaluate expression |
|
2122 |
// for its side effect and visit the body, and not bother opening and closing a WithObject. |
|
2123 |
final boolean hasScope = method.hasScope(); |
|
2124 |
||
2125 |
final Label tryLabel; |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2126 |
if (hasScope) { |
17255 | 2127 |
tryLabel = new Label("with_try"); |
2128 |
method.label(tryLabel); |
|
2129 |
method.loadCompilerConstant(SCOPE); |
|
2130 |
} else { |
|
2131 |
tryLabel = null; |
|
2132 |
} |
|
2133 |
||
16147 | 2134 |
load(expression); |
2135 |
assert expression.getType().isObject() : "with expression needs to be object: " + expression; |
|
2136 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2137 |
if (hasScope) { |
17255 | 2138 |
// Construct a WithObject if we have a scope |
2139 |
method.invoke(ScriptRuntime.OPEN_WITH); |
|
2140 |
method.storeCompilerConstant(SCOPE); |
|
2141 |
} else { |
|
2142 |
// We just loaded the expression for its side effect; discard it |
|
2143 |
method.pop(); |
|
2144 |
} |
|
2145 |
||
2146 |
||
2147 |
// Always process body |
|
16147 | 2148 |
body.accept(this); |
2149 |
||
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2150 |
if (hasScope) { |
17255 | 2151 |
// Ensure we always close the WithObject |
2152 |
final Label endLabel = new Label("with_end"); |
|
2153 |
final Label catchLabel = new Label("with_catch"); |
|
2154 |
final Label exitLabel = new Label("with_exit"); |
|
2155 |
||
2156 |
if (!body.isTerminal()) { |
|
2157 |
closeWith(); |
|
2158 |
method._goto(exitLabel); |
|
2159 |
} |
|
2160 |
||
2161 |
method.label(endLabel); |
|
2162 |
||
2163 |
method._catch(catchLabel); |
|
16147 | 2164 |
closeWith(); |
17255 | 2165 |
method.athrow(); |
2166 |
||
2167 |
method.label(exitLabel); |
|
2168 |
||
2169 |
method._try(tryLabel, endLabel, catchLabel); |
|
16147 | 2170 |
} |
17233 | 2171 |
return false; |
16147 | 2172 |
} |
2173 |
||
2174 |
@Override |
|
17233 | 2175 |
public boolean enterADD(final UnaryNode unaryNode) { |
16147 | 2176 |
load(unaryNode.rhs()); |
17766 | 2177 |
assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol(); |
16147 | 2178 |
method.store(unaryNode.getSymbol()); |
2179 |
||
17233 | 2180 |
return false; |
16147 | 2181 |
} |
2182 |
||
2183 |
@Override |
|
17233 | 2184 |
public boolean enterBIT_NOT(final UnaryNode unaryNode) { |
16147 | 2185 |
load(unaryNode.rhs()).convert(Type.INT).load(-1).xor().store(unaryNode.getSymbol()); |
17233 | 2186 |
return false; |
16147 | 2187 |
} |
2188 |
||
2189 |
// do this better with convert calls to method. TODO |
|
2190 |
@Override |
|
17233 | 2191 |
public boolean enterCONVERT(final UnaryNode unaryNode) { |
16147 | 2192 |
final Node rhs = unaryNode.rhs(); |
2193 |
final Type to = unaryNode.getType(); |
|
2194 |
||
2195 |
if (to.isObject() && rhs instanceof LiteralNode) { |
|
2196 |
final LiteralNode<?> literalNode = (LiteralNode<?>)rhs; |
|
2197 |
final Object value = literalNode.getValue(); |
|
2198 |
||
2199 |
if (value instanceof Number) { |
|
2200 |
assert !to.isArray() : "type hygiene - cannot convert number to array: (" + to.getTypeClass().getSimpleName() + ')' + value; |
|
2201 |
if (value instanceof Integer) { |
|
2202 |
method.load((Integer)value); |
|
2203 |
} else if (value instanceof Long) { |
|
2204 |
method.load((Long)value); |
|
2205 |
} else if (value instanceof Double) { |
|
2206 |
method.load((Double)value); |
|
2207 |
} else { |
|
2208 |
assert false; |
|
2209 |
} |
|
2210 |
method.convert(Type.OBJECT); |
|
2211 |
} else if (value instanceof Boolean) { |
|
17778 | 2212 |
method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class)); |
16147 | 2213 |
} else { |
2214 |
load(rhs); |
|
2215 |
method.convert(unaryNode.getType()); |
|
2216 |
} |
|
2217 |
} else { |
|
2218 |
load(rhs); |
|
2219 |
method.convert(unaryNode.getType()); |
|
2220 |
} |
|
2221 |
||
2222 |
method.store(unaryNode.getSymbol()); |
|
2223 |
||
17233 | 2224 |
return false; |
16147 | 2225 |
} |
2226 |
||
2227 |
@Override |
|
17233 | 2228 |
public boolean enterDECINC(final UnaryNode unaryNode) { |
16147 | 2229 |
final Node rhs = unaryNode.rhs(); |
2230 |
final Type type = unaryNode.getType(); |
|
2231 |
final TokenType tokenType = unaryNode.tokenType(); |
|
2232 |
final boolean isPostfix = tokenType == TokenType.DECPOSTFIX || tokenType == TokenType.INCPOSTFIX; |
|
2233 |
final boolean isIncrement = tokenType == TokenType.INCPREFIX || tokenType == TokenType.INCPOSTFIX; |
|
2234 |
||
2235 |
assert !type.isObject(); |
|
2236 |
||
2237 |
new SelfModifyingStore<UnaryNode>(unaryNode, rhs) { |
|
2238 |
||
2239 |
@Override |
|
2240 |
protected void evaluate() { |
|
2241 |
load(rhs, true); |
|
2242 |
||
2243 |
method.convert(type); |
|
2244 |
if (!isPostfix) { |
|
2245 |
if (type.isInteger()) { |
|
2246 |
method.load(isIncrement ? 1 : -1); |
|
2247 |
} else if (type.isLong()) { |
|
2248 |
method.load(isIncrement ? 1L : -1L); |
|
2249 |
} else { |
|
2250 |
method.load(isIncrement ? 1.0 : -1.0); |
|
2251 |
} |
|
2252 |
method.add(); |
|
2253 |
} |
|
2254 |
} |
|
2255 |
||
2256 |
@Override |
|
2257 |
protected void storeNonDiscard() { |
|
2258 |
super.storeNonDiscard(); |
|
2259 |
if (isPostfix) { |
|
2260 |
if (type.isInteger()) { |
|
2261 |
method.load(isIncrement ? 1 : -1); |
|
2262 |
} else if (type.isLong()) { |
|
2263 |
method.load(isIncrement ? 1L : 1L); |
|
2264 |
} else { |
|
2265 |
method.load(isIncrement ? 1.0 : -1.0); |
|
2266 |
} |
|
2267 |
method.add(); |
|
2268 |
} |
|
2269 |
} |
|
2270 |
}.store(); |
|
2271 |
||
17233 | 2272 |
return false; |
16147 | 2273 |
} |
2274 |
||
2275 |
@Override |
|
17233 | 2276 |
public boolean enterDISCARD(final UnaryNode unaryNode) { |
16147 | 2277 |
final Node rhs = unaryNode.rhs(); |
2278 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2279 |
lc.pushDiscard(rhs); |
16147 | 2280 |
load(rhs); |
2281 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2282 |
if (lc.getCurrentDiscard() == rhs) { |
17233 | 2283 |
assert !rhs.isAssignment(); |
16147 | 2284 |
method.pop(); |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2285 |
lc.popDiscard(); |
16147 | 2286 |
} |
17518
2225a4f929c0
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
lagergren
parents:
17255
diff
changeset
|
2287 |
|
17233 | 2288 |
return false; |
16147 | 2289 |
} |
2290 |
||
2291 |
@Override |
|
17233 | 2292 |
public boolean enterNEW(final UnaryNode unaryNode) { |
16147 | 2293 |
final CallNode callNode = (CallNode)unaryNode.rhs(); |
2294 |
final List<Node> args = callNode.getArgs(); |
|
2295 |
||
2296 |
// Load function reference. |
|
2297 |
load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error |
|
2298 |
||
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
2299 |
method.dynamicNew(1 + loadArgs(args), getCallSiteFlags()); |
16147 | 2300 |
method.store(unaryNode.getSymbol()); |
2301 |
||
17233 | 2302 |
return false; |
16147 | 2303 |
} |
2304 |
||
2305 |
@Override |
|
17233 | 2306 |
public boolean enterNOT(final UnaryNode unaryNode) { |
16147 | 2307 |
final Node rhs = unaryNode.rhs(); |
2308 |
||
2309 |
load(rhs); |
|
2310 |
||
2311 |
final Label trueLabel = new Label("true"); |
|
2312 |
final Label afterLabel = new Label("after"); |
|
2313 |
||
2314 |
method.convert(Type.BOOLEAN); |
|
2315 |
method.ifne(trueLabel); |
|
2316 |
method.load(true); |
|
2317 |
method._goto(afterLabel); |
|
2318 |
method.label(trueLabel); |
|
2319 |
method.load(false); |
|
2320 |
method.label(afterLabel); |
|
2321 |
method.store(unaryNode.getSymbol()); |
|
2322 |
||
17233 | 2323 |
return false; |
16147 | 2324 |
} |
2325 |
||
2326 |
@Override |
|
17233 | 2327 |
public boolean enterSUB(final UnaryNode unaryNode) { |
16147 | 2328 |
load(unaryNode.rhs()).neg().store(unaryNode.getSymbol()); |
2329 |
||
17233 | 2330 |
return false; |
16147 | 2331 |
} |
2332 |
||
2333 |
private Node enterNumericAdd(final Node lhs, final Node rhs, final Type type, final Symbol symbol) { |
|
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
2334 |
assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs); |
16147 | 2335 |
load(lhs); |
2336 |
load(rhs); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2337 |
method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack? |
16147 | 2338 |
method.store(symbol); |
2339 |
return null; |
|
2340 |
} |
|
2341 |
||
2342 |
@Override |
|
17233 | 2343 |
public boolean enterADD(final BinaryNode binaryNode) { |
16147 | 2344 |
final Node lhs = binaryNode.lhs(); |
2345 |
final Node rhs = binaryNode.rhs(); |
|
2346 |
||
2347 |
final Type type = binaryNode.getType(); |
|
2348 |
if (type.isNumeric()) { |
|
2349 |
enterNumericAdd(lhs, rhs, type, binaryNode.getSymbol()); |
|
2350 |
} else { |
|
2351 |
load(lhs).convert(Type.OBJECT); |
|
2352 |
load(rhs).convert(Type.OBJECT); |
|
2353 |
method.add(); |
|
2354 |
method.store(binaryNode.getSymbol()); |
|
2355 |
} |
|
2356 |
||
17233 | 2357 |
return false; |
16147 | 2358 |
} |
2359 |
||
17233 | 2360 |
private boolean enterAND_OR(final BinaryNode binaryNode) { |
16147 | 2361 |
final Node lhs = binaryNode.lhs(); |
2362 |
final Node rhs = binaryNode.rhs(); |
|
2363 |
||
2364 |
final Label skip = new Label("skip"); |
|
2365 |
||
2366 |
load(lhs).convert(Type.OBJECT).dup().convert(Type.BOOLEAN); |
|
2367 |
||
2368 |
if (binaryNode.tokenType() == TokenType.AND) { |
|
2369 |
method.ifeq(skip); |
|
2370 |
} else { |
|
2371 |
method.ifne(skip); |
|
2372 |
} |
|
2373 |
||
2374 |
method.pop(); |
|
2375 |
load(rhs).convert(Type.OBJECT); |
|
2376 |
method.label(skip); |
|
2377 |
method.store(binaryNode.getSymbol()); |
|
2378 |
||
17233 | 2379 |
return false; |
16147 | 2380 |
} |
2381 |
||
2382 |
@Override |
|
17233 | 2383 |
public boolean enterAND(final BinaryNode binaryNode) { |
16147 | 2384 |
return enterAND_OR(binaryNode); |
2385 |
} |
|
2386 |
||
2387 |
@Override |
|
17233 | 2388 |
public boolean enterASSIGN(final BinaryNode binaryNode) { |
16147 | 2389 |
final Node lhs = binaryNode.lhs(); |
2390 |
final Node rhs = binaryNode.rhs(); |
|
2391 |
||
2392 |
final Type lhsType = lhs.getType(); |
|
2393 |
final Type rhsType = rhs.getType(); |
|
2394 |
||
2395 |
if (!lhsType.isEquivalentTo(rhsType)) { |
|
2396 |
//this is OK if scoped, only locals are wrong |
|
2397 |
assert !(lhs instanceof IdentNode) || lhs.getSymbol().isScope() : new ASTWriter(binaryNode); |
|
2398 |
} |
|
2399 |
||
2400 |
new Store<BinaryNode>(binaryNode, lhs) { |
|
2401 |
@Override |
|
2402 |
protected void evaluate() { |
|
2403 |
load(rhs); |
|
2404 |
} |
|
2405 |
}.store(); |
|
2406 |
||
17233 | 2407 |
return false; |
16147 | 2408 |
} |
2409 |
||
2410 |
/** |
|
2411 |
* Helper class for assignment ops, e.g. *=, += and so on.. |
|
2412 |
*/ |
|
2413 |
private abstract class AssignOp extends SelfModifyingStore<BinaryNode> { |
|
2414 |
||
2415 |
/** The type of the resulting operation */ |
|
2416 |
private final Type opType; |
|
2417 |
||
2418 |
/** |
|
2419 |
* Constructor |
|
2420 |
* |
|
2421 |
* @param node the assign op node |
|
2422 |
*/ |
|
2423 |
AssignOp(final BinaryNode node) { |
|
2424 |
this(node.getType(), node); |
|
2425 |
} |
|
2426 |
||
2427 |
/** |
|
2428 |
* Constructor |
|
2429 |
* |
|
2430 |
* @param opType type of the computation - overriding the type of the node |
|
2431 |
* @param node the assign op node |
|
2432 |
*/ |
|
2433 |
AssignOp(final Type opType, final BinaryNode node) { |
|
2434 |
super(node, node.lhs()); |
|
2435 |
this.opType = opType; |
|
2436 |
} |
|
2437 |
||
2438 |
protected abstract void op(); |
|
2439 |
||
2440 |
@Override |
|
2441 |
protected void evaluate() { |
|
2442 |
load(assignNode.lhs(), true).convert(opType); |
|
2443 |
load(assignNode.rhs()).convert(opType); |
|
2444 |
op(); |
|
2445 |
method.convert(assignNode.getType()); |
|
2446 |
} |
|
2447 |
} |
|
2448 |
||
2449 |
@Override |
|
17233 | 2450 |
public boolean enterASSIGN_ADD(final BinaryNode binaryNode) { |
16147 | 2451 |
assert RuntimeNode.Request.ADD.canSpecialize(); |
17233 | 2452 |
final Type lhsType = binaryNode.lhs().getType(); |
2453 |
final Type rhsType = binaryNode.rhs().getType(); |
|
16147 | 2454 |
final boolean specialize = binaryNode.getType() == Type.OBJECT; |
2455 |
||
2456 |
new AssignOp(binaryNode) { |
|
2457 |
||
2458 |
@Override |
|
2459 |
protected void op() { |
|
17233 | 2460 |
if (specialize) { |
2461 |
method.dynamicRuntimeCall( |
|
2462 |
new SpecializedRuntimeNode( |
|
2463 |
Request.ADD, |
|
2464 |
new Type[] { |
|
2465 |
lhsType, |
|
2466 |
rhsType, |
|
2467 |
}, |
|
2468 |
Type.OBJECT).getInitialName(), |
|
2469 |
Type.OBJECT, |
|
2470 |
Request.ADD); |
|
2471 |
} else { |
|
2472 |
method.add(); |
|
2473 |
} |
|
16147 | 2474 |
} |
2475 |
||
2476 |
@Override |
|
2477 |
protected void evaluate() { |
|
2478 |
super.evaluate(); |
|
2479 |
} |
|
2480 |
}.store(); |
|
2481 |
||
17233 | 2482 |
return false; |
16147 | 2483 |
} |
2484 |
||
2485 |
@Override |
|
17233 | 2486 |
public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) { |
16147 | 2487 |
new AssignOp(Type.INT, binaryNode) { |
2488 |
@Override |
|
2489 |
protected void op() { |
|
2490 |
method.and(); |
|
2491 |
} |
|
2492 |
}.store(); |
|
2493 |
||
17233 | 2494 |
return false; |
16147 | 2495 |
} |
2496 |
||
2497 |
@Override |
|
17233 | 2498 |
public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) { |
16147 | 2499 |
new AssignOp(Type.INT, binaryNode) { |
2500 |
@Override |
|
2501 |
protected void op() { |
|
2502 |
method.or(); |
|
2503 |
} |
|
2504 |
}.store(); |
|
2505 |
||
17233 | 2506 |
return false; |
16147 | 2507 |
} |
2508 |
||
2509 |
@Override |
|
17233 | 2510 |
public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { |
16147 | 2511 |
new AssignOp(Type.INT, binaryNode) { |
2512 |
@Override |
|
2513 |
protected void op() { |
|
2514 |
method.xor(); |
|
2515 |
} |
|
2516 |
}.store(); |
|
2517 |
||
17233 | 2518 |
return false; |
16147 | 2519 |
} |
2520 |
||
2521 |
@Override |
|
17233 | 2522 |
public boolean enterASSIGN_DIV(final BinaryNode binaryNode) { |
16147 | 2523 |
new AssignOp(binaryNode) { |
2524 |
@Override |
|
2525 |
protected void op() { |
|
2526 |
method.div(); |
|
2527 |
} |
|
2528 |
}.store(); |
|
2529 |
||
17233 | 2530 |
return false; |
16147 | 2531 |
} |
2532 |
||
2533 |
@Override |
|
17233 | 2534 |
public boolean enterASSIGN_MOD(final BinaryNode binaryNode) { |
16147 | 2535 |
new AssignOp(binaryNode) { |
2536 |
@Override |
|
2537 |
protected void op() { |
|
2538 |
method.rem(); |
|
2539 |
} |
|
2540 |
}.store(); |
|
2541 |
||
17233 | 2542 |
return false; |
16147 | 2543 |
} |
2544 |
||
2545 |
@Override |
|
17233 | 2546 |
public boolean enterASSIGN_MUL(final BinaryNode binaryNode) { |
16147 | 2547 |
new AssignOp(binaryNode) { |
2548 |
@Override |
|
2549 |
protected void op() { |
|
2550 |
method.mul(); |
|
2551 |
} |
|
2552 |
}.store(); |
|
2553 |
||
17233 | 2554 |
return false; |
16147 | 2555 |
} |
2556 |
||
2557 |
@Override |
|
17233 | 2558 |
public boolean enterASSIGN_SAR(final BinaryNode binaryNode) { |
16147 | 2559 |
new AssignOp(Type.INT, binaryNode) { |
2560 |
@Override |
|
2561 |
protected void op() { |
|
2562 |
method.sar(); |
|
2563 |
} |
|
2564 |
}.store(); |
|
2565 |
||
17233 | 2566 |
return false; |
16147 | 2567 |
} |
2568 |
||
2569 |
@Override |
|
17233 | 2570 |
public boolean enterASSIGN_SHL(final BinaryNode binaryNode) { |
16147 | 2571 |
new AssignOp(Type.INT, binaryNode) { |
2572 |
@Override |
|
2573 |
protected void op() { |
|
2574 |
method.shl(); |
|
2575 |
} |
|
2576 |
}.store(); |
|
2577 |
||
17233 | 2578 |
return false; |
16147 | 2579 |
} |
2580 |
||
2581 |
@Override |
|
17233 | 2582 |
public boolean enterASSIGN_SHR(final BinaryNode binaryNode) { |
16147 | 2583 |
new AssignOp(Type.INT, binaryNode) { |
2584 |
@Override |
|
2585 |
protected void op() { |
|
2586 |
method.shr(); |
|
17241
c337fefb8c84
8012334: ToUint32, ToInt32, and ToUint16 don't conform to spec
hannesw
parents:
17239
diff
changeset
|
2587 |
method.convert(Type.LONG).load(JSType.MAX_UINT).and(); |
16147 | 2588 |
} |
2589 |
}.store(); |
|
2590 |
||
17233 | 2591 |
return false; |
16147 | 2592 |
} |
2593 |
||
2594 |
@Override |
|
17233 | 2595 |
public boolean enterASSIGN_SUB(final BinaryNode binaryNode) { |
16147 | 2596 |
new AssignOp(binaryNode) { |
2597 |
@Override |
|
2598 |
protected void op() { |
|
2599 |
method.sub(); |
|
2600 |
} |
|
2601 |
}.store(); |
|
2602 |
||
17233 | 2603 |
return false; |
16147 | 2604 |
} |
2605 |
||
2606 |
/** |
|
2607 |
* Helper class for binary arithmetic ops |
|
2608 |
*/ |
|
2609 |
private abstract class BinaryArith { |
|
2610 |
||
2611 |
protected abstract void op(); |
|
2612 |
||
2613 |
protected void evaluate(final BinaryNode node) { |
|
2614 |
load(node.lhs()); |
|
2615 |
load(node.rhs()); |
|
2616 |
op(); |
|
2617 |
method.store(node.getSymbol()); |
|
2618 |
} |
|
2619 |
} |
|
2620 |
||
2621 |
@Override |
|
17233 | 2622 |
public boolean enterBIT_AND(final BinaryNode binaryNode) { |
16147 | 2623 |
new BinaryArith() { |
2624 |
@Override |
|
2625 |
protected void op() { |
|
2626 |
method.and(); |
|
2627 |
} |
|
2628 |
}.evaluate(binaryNode); |
|
2629 |
||
17233 | 2630 |
return false; |
16147 | 2631 |
} |
2632 |
||
2633 |
@Override |
|
17233 | 2634 |
public boolean enterBIT_OR(final BinaryNode binaryNode) { |
16147 | 2635 |
new BinaryArith() { |
2636 |
@Override |
|
2637 |
protected void op() { |
|
2638 |
method.or(); |
|
2639 |
} |
|
2640 |
}.evaluate(binaryNode); |
|
2641 |
||
17233 | 2642 |
return false; |
16147 | 2643 |
} |
2644 |
||
2645 |
@Override |
|
17233 | 2646 |
public boolean enterBIT_XOR(final BinaryNode binaryNode) { |
16147 | 2647 |
new BinaryArith() { |
2648 |
@Override |
|
2649 |
protected void op() { |
|
2650 |
method.xor(); |
|
2651 |
} |
|
2652 |
}.evaluate(binaryNode); |
|
2653 |
||
17233 | 2654 |
return false; |
16147 | 2655 |
} |
2656 |
||
17233 | 2657 |
private boolean enterComma(final BinaryNode binaryNode) { |
16147 | 2658 |
final Node lhs = binaryNode.lhs(); |
2659 |
final Node rhs = binaryNode.rhs(); |
|
2660 |
||
2661 |
load(lhs); |
|
2662 |
load(rhs); |
|
2663 |
method.store(binaryNode.getSymbol()); |
|
2664 |
||
17233 | 2665 |
return false; |
16147 | 2666 |
} |
2667 |
||
2668 |
@Override |
|
17233 | 2669 |
public boolean enterCOMMARIGHT(final BinaryNode binaryNode) { |
16147 | 2670 |
return enterComma(binaryNode); |
2671 |
} |
|
2672 |
||
2673 |
@Override |
|
17233 | 2674 |
public boolean enterCOMMALEFT(final BinaryNode binaryNode) { |
16147 | 2675 |
return enterComma(binaryNode); |
2676 |
} |
|
2677 |
||
2678 |
@Override |
|
17233 | 2679 |
public boolean enterDIV(final BinaryNode binaryNode) { |
16147 | 2680 |
new BinaryArith() { |
2681 |
@Override |
|
2682 |
protected void op() { |
|
2683 |
method.div(); |
|
2684 |
} |
|
2685 |
}.evaluate(binaryNode); |
|
2686 |
||
17233 | 2687 |
return false; |
16147 | 2688 |
} |
2689 |
||
17233 | 2690 |
private boolean enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) { |
16147 | 2691 |
final Type lhsType = lhs.getType(); |
2692 |
final Type rhsType = rhs.getType(); |
|
2693 |
||
2694 |
final Type widest = Type.widest(lhsType, rhsType); |
|
2695 |
assert widest.isNumeric() || widest.isBoolean() : widest; |
|
2696 |
||
2697 |
load(lhs); |
|
2698 |
method.convert(widest); |
|
2699 |
load(rhs); |
|
2700 |
method.convert(widest); |
|
2701 |
||
2702 |
final Label trueLabel = new Label("trueLabel"); |
|
2703 |
final Label afterLabel = new Label("skip"); |
|
2704 |
||
2705 |
method.conditionalJump(cond, trueLabel); |
|
2706 |
||
2707 |
method.load(Boolean.FALSE); |
|
2708 |
method._goto(afterLabel); |
|
2709 |
method.label(trueLabel); |
|
2710 |
method.load(Boolean.TRUE); |
|
2711 |
method.label(afterLabel); |
|
2712 |
||
2713 |
method.convert(type); |
|
2714 |
method.store(symbol); |
|
2715 |
||
17233 | 2716 |
return false; |
16147 | 2717 |
} |
2718 |
||
17233 | 2719 |
private boolean enterCmp(final BinaryNode binaryNode, final Condition cond) { |
16147 | 2720 |
return enterCmp(binaryNode.lhs(), binaryNode.rhs(), cond, binaryNode.getType(), binaryNode.getSymbol()); |
2721 |
} |
|
2722 |
||
2723 |
@Override |
|
17233 | 2724 |
public boolean enterEQ(final BinaryNode binaryNode) { |
16147 | 2725 |
return enterCmp(binaryNode, Condition.EQ); |
2726 |
} |
|
2727 |
||
2728 |
@Override |
|
17233 | 2729 |
public boolean enterEQ_STRICT(final BinaryNode binaryNode) { |
16147 | 2730 |
return enterCmp(binaryNode, Condition.EQ); |
2731 |
} |
|
2732 |
||
2733 |
@Override |
|
17233 | 2734 |
public boolean enterGE(final BinaryNode binaryNode) { |
16147 | 2735 |
return enterCmp(binaryNode, Condition.GE); |
2736 |
} |
|
2737 |
||
2738 |
@Override |
|
17233 | 2739 |
public boolean enterGT(final BinaryNode binaryNode) { |
16147 | 2740 |
return enterCmp(binaryNode, Condition.GT); |
2741 |
} |
|
2742 |
||
2743 |
@Override |
|
17233 | 2744 |
public boolean enterLE(final BinaryNode binaryNode) { |
16147 | 2745 |
return enterCmp(binaryNode, Condition.LE); |
2746 |
} |
|
2747 |
||
2748 |
@Override |
|
17233 | 2749 |
public boolean enterLT(final BinaryNode binaryNode) { |
16147 | 2750 |
return enterCmp(binaryNode, Condition.LT); |
2751 |
} |
|
2752 |
||
2753 |
@Override |
|
17233 | 2754 |
public boolean enterMOD(final BinaryNode binaryNode) { |
16147 | 2755 |
new BinaryArith() { |
2756 |
@Override |
|
2757 |
protected void op() { |
|
2758 |
method.rem(); |
|
2759 |
} |
|
2760 |
}.evaluate(binaryNode); |
|
2761 |
||
17233 | 2762 |
return false; |
16147 | 2763 |
} |
2764 |
||
2765 |
@Override |
|
17233 | 2766 |
public boolean enterMUL(final BinaryNode binaryNode) { |
16147 | 2767 |
new BinaryArith() { |
2768 |
@Override |
|
2769 |
protected void op() { |
|
2770 |
method.mul(); |
|
2771 |
} |
|
2772 |
}.evaluate(binaryNode); |
|
2773 |
||
17233 | 2774 |
return false; |
16147 | 2775 |
} |
2776 |
||
2777 |
@Override |
|
17233 | 2778 |
public boolean enterNE(final BinaryNode binaryNode) { |
16147 | 2779 |
return enterCmp(binaryNode, Condition.NE); |
2780 |
} |
|
2781 |
||
2782 |
@Override |
|
17233 | 2783 |
public boolean enterNE_STRICT(final BinaryNode binaryNode) { |
16147 | 2784 |
return enterCmp(binaryNode, Condition.NE); |
2785 |
} |
|
2786 |
||
2787 |
@Override |
|
17233 | 2788 |
public boolean enterOR(final BinaryNode binaryNode) { |
16147 | 2789 |
return enterAND_OR(binaryNode); |
2790 |
} |
|
2791 |
||
2792 |
@Override |
|
17233 | 2793 |
public boolean enterSAR(final BinaryNode binaryNode) { |
16147 | 2794 |
new BinaryArith() { |
2795 |
@Override |
|
2796 |
protected void op() { |
|
2797 |
method.sar(); |
|
2798 |
} |
|
2799 |
}.evaluate(binaryNode); |
|
2800 |
||
17233 | 2801 |
return false; |
16147 | 2802 |
} |
2803 |
||
2804 |
@Override |
|
17233 | 2805 |
public boolean enterSHL(final BinaryNode binaryNode) { |
16147 | 2806 |
new BinaryArith() { |
2807 |
@Override |
|
2808 |
protected void op() { |
|
2809 |
method.shl(); |
|
2810 |
} |
|
2811 |
}.evaluate(binaryNode); |
|
2812 |
||
17233 | 2813 |
return false; |
16147 | 2814 |
} |
2815 |
||
2816 |
@Override |
|
17233 | 2817 |
public boolean enterSHR(final BinaryNode binaryNode) { |
16147 | 2818 |
new BinaryArith() { |
2819 |
@Override |
|
2820 |
protected void op() { |
|
2821 |
method.shr(); |
|
17241
c337fefb8c84
8012334: ToUint32, ToInt32, and ToUint16 don't conform to spec
hannesw
parents:
17239
diff
changeset
|
2822 |
method.convert(Type.LONG).load(JSType.MAX_UINT).and(); |
16147 | 2823 |
} |
2824 |
}.evaluate(binaryNode); |
|
2825 |
||
17233 | 2826 |
return false; |
16147 | 2827 |
} |
2828 |
||
2829 |
@Override |
|
17233 | 2830 |
public boolean enterSUB(final BinaryNode binaryNode) { |
16147 | 2831 |
new BinaryArith() { |
2832 |
@Override |
|
2833 |
protected void op() { |
|
2834 |
method.sub(); |
|
2835 |
} |
|
2836 |
}.evaluate(binaryNode); |
|
2837 |
||
17233 | 2838 |
return false; |
16147 | 2839 |
} |
2840 |
||
2841 |
@Override |
|
17233 | 2842 |
public boolean enterTernaryNode(final TernaryNode ternaryNode) { |
16147 | 2843 |
final Node lhs = ternaryNode.lhs(); |
2844 |
final Node rhs = ternaryNode.rhs(); |
|
2845 |
final Node third = ternaryNode.third(); |
|
2846 |
||
2847 |
final Symbol symbol = ternaryNode.getSymbol(); |
|
2848 |
final Label falseLabel = new Label("ternary_false"); |
|
2849 |
final Label exitLabel = new Label("ternary_exit"); |
|
2850 |
||
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
2851 |
Type widest = Type.widest(rhs.getType(), third.getType()); |
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
2852 |
if (rhs.getType().isArray() || third.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type |
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
2853 |
widest = Type.OBJECT; |
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
2854 |
} |
16147 | 2855 |
|
2856 |
load(lhs); |
|
2857 |
assert lhs.getType().isBoolean() : "lhs in ternary must be boolean"; |
|
2858 |
||
2859 |
// we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17 |
|
2860 |
// will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the |
|
2861 |
// symmetry for the temporary slot for this TernaryNode. This is evidence that we assign types and explicit conversions |
|
2862 |
// to early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to |
|
2863 |
// do this property. Then we never need any conversions in CodeGenerator |
|
2864 |
method.ifeq(falseLabel); |
|
2865 |
load(rhs); |
|
2866 |
method.convert(widest); |
|
2867 |
method._goto(exitLabel); |
|
2868 |
method.label(falseLabel); |
|
2869 |
load(third); |
|
2870 |
method.convert(widest); |
|
2871 |
method.label(exitLabel); |
|
2872 |
method.store(symbol); |
|
2873 |
||
17233 | 2874 |
return false; |
16147 | 2875 |
} |
2876 |
||
2877 |
/** |
|
2878 |
* Generate all shared scope calls generated during codegen. |
|
2879 |
*/ |
|
2880 |
protected void generateScopeCalls() { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2881 |
for (final SharedScopeCall scopeAccess : lc.getScopeCalls()) { |
16147 | 2882 |
scopeAccess.generateScopeCall(); |
2883 |
} |
|
2884 |
} |
|
2885 |
||
2886 |
/** |
|
2887 |
* Debug code used to print symbols |
|
2888 |
* |
|
2889 |
* @param block the block we are in |
|
2890 |
* @param ident identifier for block or function where applicable |
|
2891 |
*/ |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
2892 |
@SuppressWarnings("resource") |
16147 | 2893 |
private void printSymbols(final Block block, final String ident) { |
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
2894 |
if (!compiler.getEnv()._print_symbols) { |
16147 | 2895 |
return; |
2896 |
} |
|
2897 |
||
16262
75513555e603
8008731: Separate configuration environment (options, error/output writer etc.) from Context
sundar
parents:
16252
diff
changeset
|
2898 |
final PrintWriter out = compiler.getEnv().getErr(); |
16147 | 2899 |
out.println("[BLOCK in '" + ident + "']"); |
2900 |
if (!block.printSymbols(out)) { |
|
2901 |
out.println("<no symbols>"); |
|
2902 |
} |
|
2903 |
out.println(); |
|
2904 |
} |
|
2905 |
||
2906 |
||
2907 |
/** |
|
2908 |
* The difference between a store and a self modifying store is that |
|
2909 |
* the latter may load part of the target on the stack, e.g. the base |
|
2910 |
* of an AccessNode or the base and index of an IndexNode. These are used |
|
2911 |
* both as target and as an extra source. Previously it was problematic |
|
2912 |
* for self modifying stores if the target/lhs didn't belong to one |
|
2913 |
* of three trivial categories: IdentNode, AcessNodes, IndexNodes. In that |
|
2914 |
* case it was evaluated and tagged as "resolved", which meant at the second |
|
2915 |
* time the lhs of this store was read (e.g. in a = a (second) + b for a += b, |
|
2916 |
* it would be evaluated to a nop in the scope and cause stack underflow |
|
2917 |
* |
|
2918 |
* see NASHORN-703 |
|
2919 |
* |
|
2920 |
* @param <T> |
|
2921 |
*/ |
|
2922 |
private abstract class SelfModifyingStore<T extends Node> extends Store<T> { |
|
2923 |
protected SelfModifyingStore(final T assignNode, final Node target) { |
|
2924 |
super(assignNode, target); |
|
2925 |
} |
|
2926 |
||
2927 |
@Override |
|
2928 |
protected boolean isSelfModifying() { |
|
2929 |
return true; |
|
2930 |
} |
|
2931 |
} |
|
2932 |
||
2933 |
/** |
|
2934 |
* Helper class to generate stores |
|
2935 |
*/ |
|
2936 |
private abstract class Store<T extends Node> { |
|
2937 |
||
2938 |
/** An assignment node, e.g. x += y */ |
|
2939 |
protected final T assignNode; |
|
2940 |
||
2941 |
/** The target node to store to, e.g. x */ |
|
2942 |
private final Node target; |
|
2943 |
||
2944 |
/** How deep on the stack do the arguments go if this generates an indy call */ |
|
2945 |
private int depth; |
|
2946 |
||
2947 |
/** If we have too many arguments, we need temporary storage, this is stored in 'quick' */ |
|
2948 |
private Symbol quick; |
|
2949 |
||
2950 |
/** |
|
2951 |
* Constructor |
|
2952 |
* |
|
2953 |
* @param assignNode the node representing the whole assignment |
|
2954 |
* @param target the target node of the assignment (destination) |
|
2955 |
*/ |
|
2956 |
protected Store(final T assignNode, final Node target) { |
|
2957 |
this.assignNode = assignNode; |
|
2958 |
this.target = target; |
|
2959 |
} |
|
2960 |
||
2961 |
/** |
|
2962 |
* Constructor |
|
2963 |
* |
|
2964 |
* @param assignNode the node representing the whole assignment |
|
2965 |
*/ |
|
2966 |
protected Store(final T assignNode) { |
|
2967 |
this(assignNode, assignNode); |
|
2968 |
} |
|
2969 |
||
2970 |
/** |
|
2971 |
* Is this a self modifying store operation, e.g. *= or ++ |
|
2972 |
* @return true if self modifying store |
|
2973 |
*/ |
|
2974 |
protected boolean isSelfModifying() { |
|
2975 |
return false; |
|
2976 |
} |
|
2977 |
||
2978 |
private void prologue() { |
|
2979 |
final Symbol targetSymbol = target.getSymbol(); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2980 |
final Symbol scopeSymbol = lc.getCurrentFunction().compilerConstant(SCOPE); |
16147 | 2981 |
|
2982 |
/** |
|
2983 |
* This loads the parts of the target, e.g base and index. they are kept |
|
2984 |
* on the stack throughout the store and used at the end to execute it |
|
2985 |
*/ |
|
2986 |
||
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
2987 |
target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
16147 | 2988 |
@Override |
17233 | 2989 |
public boolean enterIdentNode(final IdentNode node) { |
16147 | 2990 |
if (targetSymbol.isScope()) { |
2991 |
method.load(scopeSymbol); |
|
2992 |
depth++; |
|
2993 |
} |
|
17233 | 2994 |
return false; |
16147 | 2995 |
} |
2996 |
||
2997 |
private void enterBaseNode() { |
|
2998 |
assert target instanceof BaseNode : "error - base node " + target + " must be instanceof BaseNode"; |
|
2999 |
final BaseNode baseNode = (BaseNode)target; |
|
3000 |
final Node base = baseNode.getBase(); |
|
3001 |
||
3002 |
load(base); |
|
3003 |
method.convert(Type.OBJECT); |
|
3004 |
depth += Type.OBJECT.getSlots(); |
|
3005 |
||
3006 |
if (isSelfModifying()) { |
|
3007 |
method.dup(); |
|
3008 |
} |
|
3009 |
} |
|
3010 |
||
3011 |
@Override |
|
17233 | 3012 |
public boolean enterAccessNode(final AccessNode node) { |
16147 | 3013 |
enterBaseNode(); |
17233 | 3014 |
return false; |
16147 | 3015 |
} |
3016 |
||
3017 |
@Override |
|
17233 | 3018 |
public boolean enterIndexNode(final IndexNode node) { |
16147 | 3019 |
enterBaseNode(); |
3020 |
||
3021 |
final Node index = node.getIndex(); |
|
3022 |
// could be boolean here as well |
|
3023 |
load(index); |
|
3024 |
if (!index.getType().isNumeric()) { |
|
3025 |
method.convert(Type.OBJECT); |
|
3026 |
} |
|
3027 |
depth += index.getType().getSlots(); |
|
3028 |
||
3029 |
if (isSelfModifying()) { |
|
3030 |
//convert "base base index" to "base index base index" |
|
3031 |
method.dup(1); |
|
3032 |
} |
|
3033 |
||
17233 | 3034 |
return false; |
16147 | 3035 |
} |
3036 |
||
3037 |
}); |
|
3038 |
} |
|
3039 |
||
3040 |
private Symbol quickSymbol(final Type type) { |
|
17233 | 3041 |
return quickSymbol(type, QUICK_PREFIX.symbolName()); |
16147 | 3042 |
} |
3043 |
||
3044 |
/** |
|
3045 |
* Quick symbol generates an extra local variable, always using the same |
|
3046 |
* slot, one that is available after the end of the frame. |
|
3047 |
* |
|
3048 |
* @param type the type of the symbol |
|
3049 |
* @param prefix the prefix for the variable name for the symbol |
|
3050 |
* |
|
3051 |
* @return the quick symbol |
|
3052 |
*/ |
|
3053 |
private Symbol quickSymbol(final Type type, final String prefix) { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
3054 |
final String name = lc.getCurrentFunction().uniqueName(prefix); |
17233 | 3055 |
final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL); |
16147 | 3056 |
|
3057 |
symbol.setType(type); |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
3058 |
|
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
3059 |
symbol.setSlot(lc.quickSlot(symbol)); |
16147 | 3060 |
|
3061 |
return symbol; |
|
3062 |
} |
|
3063 |
||
3064 |
// store the result that "lives on" after the op, e.g. "i" in i++ postfix. |
|
3065 |
protected void storeNonDiscard() { |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
3066 |
if (lc.getCurrentDiscard() == assignNode) { |
17233 | 3067 |
assert assignNode.isAssignment(); |
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
3068 |
lc.popDiscard(); |
16147 | 3069 |
return; |
3070 |
} |
|
3071 |
||
3072 |
final Symbol symbol = assignNode.getSymbol(); |
|
3073 |
if (symbol.hasSlot()) { |
|
3074 |
method.dup().store(symbol); |
|
3075 |
return; |
|
3076 |
} |
|
3077 |
||
3078 |
if (method.dup(depth) == null) { |
|
3079 |
method.dup(); |
|
3080 |
this.quick = quickSymbol(method.peekType()); |
|
3081 |
method.store(quick); |
|
3082 |
} |
|
3083 |
} |
|
3084 |
||
3085 |
private void epilogue() { |
|
3086 |
/** |
|
3087 |
* Take the original target args from the stack and use them |
|
3088 |
* together with the value to be stored to emit the store code |
|
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
3089 |
* |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
3090 |
* The case that targetSymbol is in scope (!hasSlot) and we actually |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
3091 |
* need to do a conversion on non-equivalent types exists, but is |
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
3092 |
* very rare. See for example test/script/basic/access-specializer.js |
16147 | 3093 |
*/ |
16201
889ddb179cdf
8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
lagergren
parents:
16190
diff
changeset
|
3094 |
method.convert(target.getType()); |
16147 | 3095 |
|
17769
14ea7feaf658
8012522: Clean up lexical contexts - split out stack based functionality in CodeGenerator and generify NodeVisitors based on their LexicalContext type to avoid casts
lagergren
parents:
17766
diff
changeset
|
3096 |
target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
16147 | 3097 |
@Override |
17233 | 3098 |
protected boolean enterDefault(Node node) { |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3099 |
throw new AssertionError("Unexpected node " + node + " in store epilogue"); |
16210
8ad1381b69d0
8007215: Varargs broken for the case of passing more than the arg limit arguments.
lagergren
parents:
16209
diff
changeset
|
3100 |
} |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3101 |
|
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3102 |
@Override |
17233 | 3103 |
public boolean enterUnaryNode(final UnaryNode node) { |
3104 |
if (node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) { |
|
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3105 |
method.convert(node.rhs().getType()); |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3106 |
} |
17233 | 3107 |
return true; |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3108 |
} |
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3109 |
|
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3110 |
@Override |
17233 | 3111 |
public boolean enterIdentNode(final IdentNode node) { |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3112 |
final Symbol symbol = node.getSymbol(); |
16226
0e4f37e6cc40
8007915: Nashorn IR, codegen, parser packages and Context instance should be inaccessible to user code
sundar
parents:
16225
diff
changeset
|
3113 |
assert symbol != null; |
16147 | 3114 |
if (symbol.isScope()) { |
16530
201d682e75f4
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
attila
parents:
16525
diff
changeset
|
3115 |
if (isFastScope(symbol)) { |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3116 |
storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags()); |
16147 | 3117 |
} else { |
16206
83069fa0935b
8006529: Methods always get callee - it should be conditional
attila
parents:
16201
diff
changeset
|
3118 |
method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); |
16147 | 3119 |
} |
3120 |
} else { |
|
16209
18e55b352d56
8007460: var assignment to a parameter in a varargs method causes compilation error
attila
parents:
16206
diff
changeset
|
3121 |
method.store(symbol); |
16147 | 3122 |
} |
17233 | 3123 |
return false; |
16147 | 3124 |
|
3125 |
} |
|
3126 |
||
3127 |
@Override |
|
17233 | 3128 |
public boolean enterAccessNode(final AccessNode node) { |
16147 | 3129 |
method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags()); |
17233 | 3130 |
return false; |
16147 | 3131 |
} |
3132 |
||
3133 |
@Override |
|
17233 | 3134 |
public boolean enterIndexNode(final IndexNode node) { |
16147 | 3135 |
method.dynamicSetIndex(getCallSiteFlags()); |
17233 | 3136 |
return false; |
16147 | 3137 |
} |
3138 |
}); |
|
3139 |
||
3140 |
||
3141 |
// whatever is on the stack now is the final answer |
|
3142 |
} |
|
3143 |
||
3144 |
protected abstract void evaluate(); |
|
3145 |
||
3146 |
void store() { |
|
3147 |
prologue(); |
|
3148 |
evaluate(); // leaves an operation of whatever the operationType was on the stack |
|
3149 |
storeNonDiscard(); |
|
3150 |
epilogue(); |
|
3151 |
if (quick != null) { |
|
3152 |
method.load(quick); |
|
3153 |
} |
|
3154 |
} |
|
3155 |
} |
|
3156 |
||
17233 | 3157 |
private void newFunctionObject(final FunctionNode functionNode, final FunctionNode originalFunctionNode) { |
3158 |
assert lc.peek() == functionNode; |
|
3159 |
// We don't emit a ScriptFunction on stack for: |
|
3160 |
// 1. the outermost compiled function (as there's no code being generated in its outer context that'd need it |
|
3161 |
// as a callee), and |
|
3162 |
// 2. for functions that are immediately called upon definition and they don't need a callee, e.g. (function(){})(). |
|
3163 |
// Such immediately-called functions are invoked using INVOKESTATIC (see enterFunctionNode() of the embedded |
|
3164 |
// visitor of enterCallNode() for details), and if they don't need a callee, they don't have it on their |
|
3165 |
// static method's parameter list. |
|
17524
703643aeb0d6
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
lagergren
parents:
17523
diff
changeset
|
3166 |
if (lc.getOutermostFunction() == functionNode || |
17233 | 3167 |
(!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) { |
3168 |
return; |
|
3169 |
} |
|
3170 |
||
16525
1409942e618e
8009982: Lazy execution bugfix. Added lazy sunspider unit test. Added mandreel to compile-octane test. Fixed warnings
lagergren
parents:
16523
diff
changeset
|
3171 |
final boolean isLazy = functionNode.isLazy(); |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3172 |
|
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3173 |
new ObjectCreator(this, new ArrayList<String>(), new ArrayList<Symbol>(), false, false) { |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3174 |
@Override |
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16268
diff
changeset
|
3175 |
protected void makeObject(final MethodEmitter m) { |
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16268
diff
changeset
|
3176 |
final String className = SCRIPTFUNCTION_IMPL_OBJECT; |
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16268
diff
changeset
|
3177 |
|
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16268
diff
changeset
|
3178 |
m._new(className).dup(); |
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16268
diff
changeset
|
3179 |
loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap())); |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3180 |
|
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3181 |
if (isLazy || functionNode.needsParentScope()) { |
17233 | 3182 |
m.loadCompilerConstant(SCOPE); |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3183 |
} else { |
16523
af8b30edebce
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
lagergren
parents:
16268
diff
changeset
|
3184 |
m.loadNull(); |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3185 |
} |
16525
1409942e618e
8009982: Lazy execution bugfix. Added lazy sunspider unit test. Added mandreel to compile-octane test. Fixed warnings
lagergren
parents:
16523
diff
changeset
|
3186 |
m.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class)); |
16233
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3187 |
} |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3188 |
}.makeObject(method); |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3189 |
} |
95d3e01c04c3
8008199: Lazy compilation and trampoline implementation
lagergren
parents:
16226
diff
changeset
|
3190 |
|
16147 | 3191 |
/* |
3192 |
* Globals are special. We cannot refer to any Global (or NativeObject) class by .class, as they are different |
|
3193 |
* for different contexts. As far as I can tell, the only NativeObject that we need to deal with like this |
|
3194 |
* is from the code pipeline is Global |
|
3195 |
*/ |
|
3196 |
private MethodEmitter globalInstance() { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3197 |
return method.invokestatic(GLOBAL_OBJECT, "instance", "()L" + GLOBAL_OBJECT + ';'); |
16147 | 3198 |
} |
3199 |
||
3200 |
private MethodEmitter globalObjectPrototype() { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3201 |
return method.invokestatic(GLOBAL_OBJECT, "objectPrototype", methodDescriptor(ScriptObject.class)); |
16147 | 3202 |
} |
3203 |
||
3204 |
private MethodEmitter globalAllocateArguments() { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3205 |
return method.invokestatic(GLOBAL_OBJECT, "allocateArguments", methodDescriptor(ScriptObject.class, Object[].class, Object.class, int.class)); |
16147 | 3206 |
} |
3207 |
||
3208 |
private MethodEmitter globalNewRegExp() { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3209 |
return method.invokestatic(GLOBAL_OBJECT, "newRegExp", methodDescriptor(Object.class, String.class, String.class)); |
16147 | 3210 |
} |
3211 |
||
3212 |
private MethodEmitter globalRegExpCopy() { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3213 |
return method.invokestatic(GLOBAL_OBJECT, "regExpCopy", methodDescriptor(Object.class, Object.class)); |
16147 | 3214 |
} |
3215 |
||
3216 |
private MethodEmitter globalAllocateArray(final ArrayType type) { |
|
3217 |
//make sure the native array is treated as an array type |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3218 |
return method.invokestatic(GLOBAL_OBJECT, "allocate", "(" + type.getDescriptor() + ")Ljdk/nashorn/internal/objects/NativeArray;"); |
16147 | 3219 |
} |
3220 |
||
3221 |
private MethodEmitter globalIsEval() { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3222 |
return method.invokestatic(GLOBAL_OBJECT, "isEval", methodDescriptor(boolean.class, Object.class)); |
16147 | 3223 |
} |
3224 |
||
3225 |
private MethodEmitter globalDirectEval() { |
|
16240
e1468b33e201
8008239: Unpublicized parts of the code generator package that were only package internal.
lagergren
parents:
16235
diff
changeset
|
3226 |
return method.invokestatic(GLOBAL_OBJECT, "directEval", |
16147 | 3227 |
methodDescriptor(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class)); |
3228 |
} |
|
3229 |
} |