OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:collection'; | 5 import 'dart:collection'; |
6 | 6 |
7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
8 | 8 |
9 import '../closure.dart'; | 9 import '../closure.dart'; |
10 import '../common.dart'; | 10 import '../common.dart'; |
11 import '../common/codegen.dart' show | 11 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
12 CodegenRegistry, | 12 import '../common/names.dart' show Identifiers, Selectors; |
13 CodegenWorkItem; | 13 import '../common/tasks.dart' show CompilerTask; |
14 import '../common/names.dart' show | 14 import '../compiler.dart' show Compiler; |
15 Identifiers, | |
16 Selectors; | |
17 import '../common/tasks.dart' show | |
18 CompilerTask; | |
19 import '../compiler.dart' show | |
20 Compiler; | |
21 import '../constants/constant_system.dart'; | 15 import '../constants/constant_system.dart'; |
22 import '../constants/expressions.dart'; | 16 import '../constants/expressions.dart'; |
23 import '../constants/values.dart'; | 17 import '../constants/values.dart'; |
24 import '../core_types.dart' show | 18 import '../core_types.dart' show CoreClasses; |
25 CoreClasses; | |
26 import '../dart_types.dart'; | 19 import '../dart_types.dart'; |
27 import '../diagnostics/messages.dart' show | 20 import '../diagnostics/messages.dart' show Message, MessageTemplate; |
28 Message, | |
29 MessageTemplate; | |
30 import '../elements/elements.dart'; | 21 import '../elements/elements.dart'; |
31 import '../elements/modelx.dart' show | 22 import '../elements/modelx.dart' |
32 ConstructorBodyElementX, | 23 show ConstructorBodyElementX, ElementX, VariableElementX; |
33 ElementX, | |
34 VariableElementX; | |
35 import '../io/source_information.dart'; | 24 import '../io/source_information.dart'; |
36 import '../js/js.dart' as js; | 25 import '../js/js.dart' as js; |
37 import '../js_backend/backend_helpers.dart' show | 26 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
38 BackendHelpers; | |
39 import '../js_backend/js_backend.dart'; | 27 import '../js_backend/js_backend.dart'; |
40 import '../js_emitter/js_emitter.dart' show | 28 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
41 CodeEmitterTask, | |
42 NativeEmitter; | |
43 import '../native/native.dart' as native; | 29 import '../native/native.dart' as native; |
44 import '../resolution/operators.dart'; | 30 import '../resolution/operators.dart'; |
45 import '../resolution/semantic_visitor.dart'; | 31 import '../resolution/semantic_visitor.dart'; |
46 import '../resolution/tree_elements.dart' show | 32 import '../resolution/tree_elements.dart' show TreeElements; |
47 TreeElements; | |
48 import '../tree/tree.dart' as ast; | 33 import '../tree/tree.dart' as ast; |
49 import '../types/types.dart'; | 34 import '../types/types.dart'; |
50 import '../universe/call_structure.dart' show | 35 import '../universe/call_structure.dart' show CallStructure; |
51 CallStructure; | 36 import '../universe/selector.dart' show Selector; |
52 import '../universe/selector.dart' show | 37 import '../universe/side_effects.dart' show SideEffects; |
53 Selector; | 38 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse; |
54 import '../universe/side_effects.dart' show | |
55 SideEffects; | |
56 import '../universe/use.dart' show | |
57 DynamicUse, | |
58 StaticUse, | |
59 TypeUse; | |
60 import '../util/util.dart'; | 39 import '../util/util.dart'; |
61 import '../world.dart' show | 40 import '../world.dart' show ClassWorld, World; |
62 ClassWorld, | |
63 World; | |
64 import '../dump_info.dart' show InfoReporter; | 41 import '../dump_info.dart' show InfoReporter; |
65 | 42 |
66 import 'nodes.dart'; | 43 import 'nodes.dart'; |
67 import 'codegen.dart'; | 44 import 'codegen.dart'; |
68 import 'optimize.dart'; | 45 import 'optimize.dart'; |
69 import 'types.dart'; | 46 import 'types.dart'; |
70 | 47 |
71 class SsaFunctionCompiler implements FunctionCompiler { | 48 class SsaFunctionCompiler implements FunctionCompiler { |
72 final SsaCodeGeneratorTask generator; | 49 final SsaCodeGeneratorTask generator; |
73 final SsaBuilderTask builder; | 50 final SsaBuilderTask builder; |
74 final SsaOptimizerTask optimizer; | 51 final SsaOptimizerTask optimizer; |
75 final JavaScriptBackend backend; | 52 final JavaScriptBackend backend; |
76 | 53 |
77 SsaFunctionCompiler(JavaScriptBackend backend, | 54 SsaFunctionCompiler(JavaScriptBackend backend, |
78 SourceInformationStrategy sourceInformationFactory) | 55 SourceInformationStrategy sourceInformationFactory) |
79 : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory), | 56 : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory), |
80 builder = new SsaBuilderTask(backend, sourceInformationFactory), | 57 builder = new SsaBuilderTask(backend, sourceInformationFactory), |
81 optimizer = new SsaOptimizerTask(backend), | 58 optimizer = new SsaOptimizerTask(backend), |
82 backend = backend; | 59 backend = backend; |
83 | 60 |
84 /// Generates JavaScript code for `work.element`. | 61 /// Generates JavaScript code for `work.element`. |
85 /// Using the ssa builder, optimizer and codegenerator. | 62 /// Using the ssa builder, optimizer and codegenerator. |
86 js.Fun compile(CodegenWorkItem work) { | 63 js.Fun compile(CodegenWorkItem work) { |
87 HGraph graph = builder.build(work); | 64 HGraph graph = builder.build(work); |
88 optimizer.optimize(work, graph); | 65 optimizer.optimize(work, graph); |
(...skipping 24 matching lines...) Expand all Loading... |
113 } | 90 } |
114 | 91 |
115 class SsaBuilderTask extends CompilerTask { | 92 class SsaBuilderTask extends CompilerTask { |
116 final CodeEmitterTask emitter; | 93 final CodeEmitterTask emitter; |
117 final JavaScriptBackend backend; | 94 final JavaScriptBackend backend; |
118 final SourceInformationStrategy sourceInformationFactory; | 95 final SourceInformationStrategy sourceInformationFactory; |
119 | 96 |
120 String get name => 'SSA builder'; | 97 String get name => 'SSA builder'; |
121 | 98 |
122 SsaBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) | 99 SsaBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) |
123 : emitter = backend.emitter, | 100 : emitter = backend.emitter, |
124 backend = backend, | 101 backend = backend, |
125 super(backend.compiler); | 102 super(backend.compiler); |
126 | 103 |
127 DiagnosticReporter get reporter => compiler.reporter; | 104 DiagnosticReporter get reporter => compiler.reporter; |
128 | 105 |
129 HGraph build(CodegenWorkItem work) { | 106 HGraph build(CodegenWorkItem work) { |
130 return measure(() { | 107 return measure(() { |
131 Element element = work.element.implementation; | 108 Element element = work.element.implementation; |
132 return reporter.withCurrentElement(element, () { | 109 return reporter.withCurrentElement(element, () { |
133 SsaBuilder builder = | 110 SsaBuilder builder = new SsaBuilder( |
134 new SsaBuilder(work.element.implementation, | 111 work.element.implementation, |
135 work.resolutionTree, work.compilationContext, work.registry, | 112 work.resolutionTree, |
136 backend, emitter.nativeEmitter, | 113 work.compilationContext, |
137 sourceInformationFactory); | 114 work.registry, |
| 115 backend, |
| 116 emitter.nativeEmitter, |
| 117 sourceInformationFactory); |
138 HGraph graph = builder.build(); | 118 HGraph graph = builder.build(); |
139 | 119 |
140 // Default arguments are handled elsewhere, but we must ensure | 120 // Default arguments are handled elsewhere, but we must ensure |
141 // that the default values are computed during codegen. | 121 // that the default values are computed during codegen. |
142 if (!identical(element.kind, ElementKind.FIELD)) { | 122 if (!identical(element.kind, ElementKind.FIELD)) { |
143 FunctionElement function = element; | 123 FunctionElement function = element; |
144 FunctionSignature signature = function.functionSignature; | 124 FunctionSignature signature = function.functionSignature; |
145 signature.forEachOptionalParameter((ParameterElement parameter) { | 125 signature.forEachOptionalParameter((ParameterElement parameter) { |
146 // This ensures the default value will be computed. | 126 // This ensures the default value will be computed. |
147 ConstantValue constant = | 127 ConstantValue constant = |
148 backend.constants.getConstantValueForVariable(parameter); | 128 backend.constants.getConstantValueForVariable(parameter); |
149 work.registry.registerCompileTimeConstant(constant); | 129 work.registry.registerCompileTimeConstant(constant); |
150 }); | 130 }); |
151 } | 131 } |
152 if (compiler.tracer.isEnabled) { | 132 if (compiler.tracer.isEnabled) { |
153 String name; | 133 String name; |
154 if (element.isClassMember) { | 134 if (element.isClassMember) { |
155 String className = element.enclosingClass.name; | 135 String className = element.enclosingClass.name; |
156 String memberName = element.name; | 136 String memberName = element.name; |
157 name = "$className.$memberName"; | 137 name = "$className.$memberName"; |
158 if (element.isGenerativeConstructorBody) { | 138 if (element.isGenerativeConstructorBody) { |
159 name = "$name (body)"; | 139 name = "$name (body)"; |
160 } | 140 } |
161 } else { | 141 } else { |
162 name = "${element.name}"; | 142 name = "${element.name}"; |
163 } | 143 } |
164 compiler.tracer.traceCompilation( | 144 compiler.tracer.traceCompilation(name, work.compilationContext); |
165 name, work.compilationContext); | |
166 compiler.tracer.traceGraph('builder', graph); | 145 compiler.tracer.traceGraph('builder', graph); |
167 } | 146 } |
168 return graph; | 147 return graph; |
169 }); | 148 }); |
170 }); | 149 }); |
171 } | 150 } |
172 | |
173 } | 151 } |
174 | 152 |
175 /** | 153 /** |
176 * Keeps track of locals (including parameters and phis) when building. The | 154 * Keeps track of locals (including parameters and phis) when building. The |
177 * 'this' reference is treated as parameter and hence handled by this class, | 155 * 'this' reference is treated as parameter and hence handled by this class, |
178 * too. | 156 * too. |
179 */ | 157 */ |
180 class LocalsHandler { | 158 class LocalsHandler { |
181 /** | 159 /** |
182 * The values of locals that can be directly accessed (without redirections | 160 * The values of locals that can be directly accessed (without redirections |
183 * to boxes or closure-fields). | 161 * to boxes or closure-fields). |
184 * | 162 * |
185 * [directLocals] is iterated, so it is "insertion ordered" to make the | 163 * [directLocals] is iterated, so it is "insertion ordered" to make the |
186 * iteration order a function only of insertions and not a function of | 164 * iteration order a function only of insertions and not a function of |
187 * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements | 165 * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements |
188 * don't have source locations for [Elements.compareByPosition]. | 166 * don't have source locations for [Elements.compareByPosition]. |
189 */ | 167 */ |
190 Map<Local, HInstruction> directLocals = | 168 Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>(); |
191 new Map<Local, HInstruction>(); | |
192 Map<Local, CapturedVariable> redirectionMapping = | 169 Map<Local, CapturedVariable> redirectionMapping = |
193 new Map<Local, CapturedVariable>(); | 170 new Map<Local, CapturedVariable>(); |
194 SsaBuilder builder; | 171 SsaBuilder builder; |
195 ClosureClassMap closureData; | 172 ClosureClassMap closureData; |
196 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = | 173 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = |
197 new Map<TypeVariableType, TypeVariableLocal>(); | 174 new Map<TypeVariableType, TypeVariableLocal>(); |
198 final ExecutableElement executableContext; | 175 final ExecutableElement executableContext; |
199 | 176 |
200 /// The class that defines the current type environment or null if no type | 177 /// The class that defines the current type environment or null if no type |
201 /// variables are in scope. | 178 /// variables are in scope. |
(...skipping 14 matching lines...) Expand all Loading... |
216 /// | 193 /// |
217 /// [instanceType] is not used if it contains type variables, since these | 194 /// [instanceType] is not used if it contains type variables, since these |
218 /// might not be in scope or from the current instance. | 195 /// might not be in scope or from the current instance. |
219 /// | 196 /// |
220 final InterfaceType instanceType; | 197 final InterfaceType instanceType; |
221 | 198 |
222 SourceInformationBuilder get sourceInformationBuilder { | 199 SourceInformationBuilder get sourceInformationBuilder { |
223 return builder.sourceInformationBuilder; | 200 return builder.sourceInformationBuilder; |
224 } | 201 } |
225 | 202 |
226 LocalsHandler(this.builder, this.executableContext, | 203 LocalsHandler( |
227 InterfaceType instanceType) | 204 this.builder, this.executableContext, InterfaceType instanceType) |
228 : this.instanceType = | 205 : this.instanceType = instanceType == null || |
229 instanceType == null || instanceType.containsTypeVariables | 206 instanceType.containsTypeVariables ? null : instanceType; |
230 ? null : instanceType; | |
231 | 207 |
232 /// Substituted type variables occurring in [type] into the context of | 208 /// Substituted type variables occurring in [type] into the context of |
233 /// [contextClass]. | 209 /// [contextClass]. |
234 DartType substInContext(DartType type) { | 210 DartType substInContext(DartType type) { |
235 if (contextClass != null) { | 211 if (contextClass != null) { |
236 ClassElement typeContext = Types.getClassContext(type); | 212 ClassElement typeContext = Types.getClassContext(type); |
237 if (typeContext != null) { | 213 if (typeContext != null) { |
238 type = type.substByContext( | 214 type = type.substByContext(contextClass.asInstanceOf(typeContext)); |
239 contextClass.asInstanceOf(typeContext)); | |
240 } | 215 } |
241 } | 216 } |
242 if (instanceType != null) { | 217 if (instanceType != null) { |
243 type = type.substByContext(instanceType); | 218 type = type.substByContext(instanceType); |
244 } | 219 } |
245 return type; | 220 return type; |
246 } | 221 } |
247 | 222 |
248 get typesTask => builder.compiler.typesTask; | 223 get typesTask => builder.compiler.typesTask; |
249 | 224 |
(...skipping 18 matching lines...) Expand all Loading... |
268 assert(redirectionMapping[from] == null); | 243 assert(redirectionMapping[from] == null); |
269 redirectionMapping[from] = to; | 244 redirectionMapping[from] = to; |
270 assert(isStoredInClosureField(from) || isBoxed(from)); | 245 assert(isStoredInClosureField(from) || isBoxed(from)); |
271 } | 246 } |
272 | 247 |
273 HInstruction createBox() { | 248 HInstruction createBox() { |
274 // TODO(floitsch): Clean up this hack. Should we create a box-object by | 249 // TODO(floitsch): Clean up this hack. Should we create a box-object by |
275 // just creating an empty object literal? | 250 // just creating an empty object literal? |
276 JavaScriptBackend backend = builder.backend; | 251 JavaScriptBackend backend = builder.backend; |
277 HInstruction box = new HForeignCode( | 252 HInstruction box = new HForeignCode( |
278 js.js.parseForeignJS('{}'), | 253 js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[], |
279 backend.nonNullType, | |
280 <HInstruction>[], | |
281 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); | 254 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); |
282 builder.add(box); | 255 builder.add(box); |
283 return box; | 256 return box; |
284 } | 257 } |
285 | 258 |
286 /** | 259 /** |
287 * If the scope (function or loop) [node] has captured variables then this | 260 * If the scope (function or loop) [node] has captured variables then this |
288 * method creates a box and sets up the redirections. | 261 * method creates a box and sets up the redirections. |
289 */ | 262 */ |
290 void enterScope(ast.Node node, Element element) { | 263 void enterScope(ast.Node node, Element element) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 } else { | 297 } else { |
325 redirectElement(from, to); | 298 redirectElement(from, to); |
326 } | 299 } |
327 }); | 300 }); |
328 } | 301 } |
329 | 302 |
330 /** | 303 /** |
331 * Replaces the current box with a new box and copies over the given list | 304 * Replaces the current box with a new box and copies over the given list |
332 * of elements from the old box into the new box. | 305 * of elements from the old box into the new box. |
333 */ | 306 */ |
334 void updateCaptureBox(BoxLocal boxElement, | 307 void updateCaptureBox( |
335 List<LocalVariableElement> toBeCopiedElements) { | 308 BoxLocal boxElement, List<LocalVariableElement> toBeCopiedElements) { |
336 // Create a new box and copy over the values from the old box into the | 309 // Create a new box and copy over the values from the old box into the |
337 // new one. | 310 // new one. |
338 HInstruction oldBox = readLocal(boxElement); | 311 HInstruction oldBox = readLocal(boxElement); |
339 HInstruction newBox = createBox(); | 312 HInstruction newBox = createBox(); |
340 for (LocalVariableElement boxedVariable in toBeCopiedElements) { | 313 for (LocalVariableElement boxedVariable in toBeCopiedElements) { |
341 // [readLocal] uses the [boxElement] to find its box. By replacing it | 314 // [readLocal] uses the [boxElement] to find its box. By replacing it |
342 // behind its back we can still get to the old values. | 315 // behind its back we can still get to the old values. |
343 updateLocal(boxElement, oldBox); | 316 updateLocal(boxElement, oldBox); |
344 HInstruction oldValue = readLocal(boxedVariable); | 317 HInstruction oldValue = readLocal(boxedVariable); |
345 updateLocal(boxElement, newBox); | 318 updateLocal(boxElement, newBox); |
346 updateLocal(boxedVariable, oldValue); | 319 updateLocal(boxedVariable, oldValue); |
347 } | 320 } |
348 updateLocal(boxElement, newBox); | 321 updateLocal(boxElement, newBox); |
349 } | 322 } |
350 | 323 |
351 /** | 324 /** |
352 * Documentation wanted -- johnniwinther | 325 * Documentation wanted -- johnniwinther |
353 * | 326 * |
354 * Invariant: [function] must be an implementation element. | 327 * Invariant: [function] must be an implementation element. |
355 */ | 328 */ |
356 void startFunction(Element element, ast.Node node) { | 329 void startFunction(Element element, ast.Node node) { |
357 assert(invariant(element, element.isImplementation)); | 330 assert(invariant(element, element.isImplementation)); |
358 Compiler compiler = builder.compiler; | 331 Compiler compiler = builder.compiler; |
359 closureData = compiler.closureToClassMapper.computeClosureToClassMapping( | 332 closureData = compiler.closureToClassMapper |
360 element, node, builder.elements); | 333 .computeClosureToClassMapping(element, node, builder.elements); |
361 | 334 |
362 if (element is FunctionElement) { | 335 if (element is FunctionElement) { |
363 FunctionElement functionElement = element; | 336 FunctionElement functionElement = element; |
364 FunctionSignature params = functionElement.functionSignature; | 337 FunctionSignature params = functionElement.functionSignature; |
365 ClosureScope scopeData = closureData.capturingScopes[node]; | 338 ClosureScope scopeData = closureData.capturingScopes[node]; |
366 params.orderedForEachParameter((ParameterElement parameterElement) { | 339 params.orderedForEachParameter((ParameterElement parameterElement) { |
367 if (element.isGenerativeConstructorBody) { | 340 if (element.isGenerativeConstructorBody) { |
368 if (scopeData != null && | 341 if (scopeData != null && |
369 scopeData.isCapturedVariable(parameterElement)) { | 342 scopeData.isCapturedVariable(parameterElement)) { |
370 // The parameter will be a field in the box passed as the | 343 // The parameter will be a field in the box passed as the |
371 // last parameter. So no need to have it. | 344 // last parameter. So no need to have it. |
372 return; | 345 return; |
373 } | 346 } |
374 } | 347 } |
375 HInstruction parameter = builder.addParameter( | 348 HInstruction parameter = builder.addParameter(parameterElement, |
376 parameterElement, | |
377 TypeMaskFactory.inferredTypeForElement(parameterElement, compiler)); | 349 TypeMaskFactory.inferredTypeForElement(parameterElement, compiler)); |
378 builder.parameters[parameterElement] = parameter; | 350 builder.parameters[parameterElement] = parameter; |
379 directLocals[parameterElement] = parameter; | 351 directLocals[parameterElement] = parameter; |
380 }); | 352 }); |
381 } | 353 } |
382 | 354 |
383 enterScope(node, element); | 355 enterScope(node, element); |
384 | 356 |
385 // If the freeVariableMapping is not empty, then this function was a | 357 // If the freeVariableMapping is not empty, then this function was a |
386 // nested closure that captures variables. Redirect the captured | 358 // nested closure that captures variables. Redirect the captured |
387 // variables to fields in the closure. | 359 // variables to fields in the closure. |
388 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 360 closureData.forEachFreeVariable((Local from, CapturedVariable to) { |
389 redirectElement(from, to); | 361 redirectElement(from, to); |
390 }); | 362 }); |
391 JavaScriptBackend backend = compiler.backend; | 363 JavaScriptBackend backend = compiler.backend; |
392 if (closureData.isClosure) { | 364 if (closureData.isClosure) { |
393 // Inside closure redirect references to itself to [:this:]. | 365 // Inside closure redirect references to itself to [:this:]. |
394 HThis thisInstruction = new HThis(closureData.thisLocal, | 366 HThis thisInstruction = |
395 backend.nonNullType); | 367 new HThis(closureData.thisLocal, backend.nonNullType); |
396 builder.graph.thisInstruction = thisInstruction; | 368 builder.graph.thisInstruction = thisInstruction; |
397 builder.graph.entry.addAtEntry(thisInstruction); | 369 builder.graph.entry.addAtEntry(thisInstruction); |
398 updateLocal(closureData.closureElement, thisInstruction); | 370 updateLocal(closureData.closureElement, thisInstruction); |
399 } else if (element.isInstanceMember) { | 371 } else if (element.isInstanceMember) { |
400 // Once closures have been mapped to classes their instance members might | 372 // Once closures have been mapped to classes their instance members might |
401 // not have any thisElement if the closure was created inside a static | 373 // not have any thisElement if the closure was created inside a static |
402 // context. | 374 // context. |
403 HThis thisInstruction = new HThis( | 375 HThis thisInstruction = |
404 closureData.thisLocal, builder.getTypeOfThis()); | 376 new HThis(closureData.thisLocal, builder.getTypeOfThis()); |
405 builder.graph.thisInstruction = thisInstruction; | 377 builder.graph.thisInstruction = thisInstruction; |
406 builder.graph.entry.addAtEntry(thisInstruction); | 378 builder.graph.entry.addAtEntry(thisInstruction); |
407 directLocals[closureData.thisLocal] = thisInstruction; | 379 directLocals[closureData.thisLocal] = thisInstruction; |
408 } | 380 } |
409 | 381 |
410 // If this method is an intercepted method, add the extra | 382 // If this method is an intercepted method, add the extra |
411 // parameter to it, that is the actual receiver for intercepted | 383 // parameter to it, that is the actual receiver for intercepted |
412 // classes, or the same as [:this:] for non-intercepted classes. | 384 // classes, or the same as [:this:] for non-intercepted classes. |
413 ClassElement cls = element.enclosingClass; | 385 ClassElement cls = element.enclosingClass; |
414 | 386 |
415 // When the class extends a native class, the instance is pre-constructed | 387 // When the class extends a native class, the instance is pre-constructed |
416 // and passed to the generative constructor factory function as a parameter. | 388 // and passed to the generative constructor factory function as a parameter. |
417 // Instead of allocating and initializing the object, the constructor | 389 // Instead of allocating and initializing the object, the constructor |
418 // 'upgrades' the native subclass object by initializing the Dart fields. | 390 // 'upgrades' the native subclass object by initializing the Dart fields. |
419 bool isNativeUpgradeFactory = element.isGenerativeConstructor | 391 bool isNativeUpgradeFactory = |
420 && backend.isNativeOrExtendsNative(cls); | 392 element.isGenerativeConstructor && backend.isNativeOrExtendsNative(cls); |
421 if (backend.isInterceptedMethod(element)) { | 393 if (backend.isInterceptedMethod(element)) { |
422 bool isInterceptorClass = backend.isInterceptorClass(cls.declaration); | 394 bool isInterceptorClass = backend.isInterceptorClass(cls.declaration); |
423 String name = isInterceptorClass ? 'receiver' : '_'; | 395 String name = isInterceptorClass ? 'receiver' : '_'; |
424 SyntheticLocal parameter = new SyntheticLocal(name, executableContext); | 396 SyntheticLocal parameter = new SyntheticLocal(name, executableContext); |
425 HParameterValue value = | 397 HParameterValue value = |
426 new HParameterValue(parameter, builder.getTypeOfThis()); | 398 new HParameterValue(parameter, builder.getTypeOfThis()); |
427 builder.graph.explicitReceiverParameter = value; | 399 builder.graph.explicitReceiverParameter = value; |
428 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); | 400 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); |
429 if (builder.lastAddedParameter == null) { | 401 if (builder.lastAddedParameter == null) { |
430 // If this is the first parameter inserted, make sure it stays first. | 402 // If this is the first parameter inserted, make sure it stays first. |
(...skipping 15 matching lines...) Expand all Loading... |
446 builder.graph.entry.addAtEntry(value); | 418 builder.graph.entry.addAtEntry(value); |
447 } | 419 } |
448 } | 420 } |
449 | 421 |
450 /** | 422 /** |
451 * Returns true if the local can be accessed directly. Boxed variables or | 423 * Returns true if the local can be accessed directly. Boxed variables or |
452 * captured variables that are stored in the closure-field return [:false:]. | 424 * captured variables that are stored in the closure-field return [:false:]. |
453 */ | 425 */ |
454 bool isAccessedDirectly(Local local) { | 426 bool isAccessedDirectly(Local local) { |
455 assert(local != null); | 427 assert(local != null); |
456 return !redirectionMapping.containsKey(local) | 428 return !redirectionMapping.containsKey(local) && |
457 && !closureData.variablesUsedInTryOrGenerator.contains(local); | 429 !closureData.variablesUsedInTryOrGenerator.contains(local); |
458 } | 430 } |
459 | 431 |
460 bool isStoredInClosureField(Local local) { | 432 bool isStoredInClosureField(Local local) { |
461 assert(local != null); | 433 assert(local != null); |
462 if (isAccessedDirectly(local)) return false; | 434 if (isAccessedDirectly(local)) return false; |
463 CapturedVariable redirectTarget = redirectionMapping[local]; | 435 CapturedVariable redirectTarget = redirectionMapping[local]; |
464 if (redirectTarget == null) return false; | 436 if (redirectTarget == null) return false; |
465 return redirectTarget is ClosureFieldElement; | 437 return redirectTarget is ClosureFieldElement; |
466 } | 438 } |
467 | 439 |
468 bool isBoxed(Local local) { | 440 bool isBoxed(Local local) { |
469 if (isAccessedDirectly(local)) return false; | 441 if (isAccessedDirectly(local)) return false; |
470 if (isStoredInClosureField(local)) return false; | 442 if (isStoredInClosureField(local)) return false; |
471 return redirectionMapping.containsKey(local); | 443 return redirectionMapping.containsKey(local); |
472 } | 444 } |
473 | 445 |
474 bool isUsedInTryOrGenerator(Local local) { | 446 bool isUsedInTryOrGenerator(Local local) { |
475 return closureData.variablesUsedInTryOrGenerator.contains(local); | 447 return closureData.variablesUsedInTryOrGenerator.contains(local); |
476 } | 448 } |
477 | 449 |
478 /** | 450 /** |
479 * Returns an [HInstruction] for the given element. If the element is | 451 * Returns an [HInstruction] for the given element. If the element is |
480 * boxed or stored in a closure then the method generates code to retrieve | 452 * boxed or stored in a closure then the method generates code to retrieve |
481 * the value. | 453 * the value. |
482 */ | 454 */ |
483 HInstruction readLocal(Local local, | 455 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
484 {SourceInformation sourceInformation}) { | |
485 if (isAccessedDirectly(local)) { | 456 if (isAccessedDirectly(local)) { |
486 if (directLocals[local] == null) { | 457 if (directLocals[local] == null) { |
487 if (local is TypeVariableElement) { | 458 if (local is TypeVariableElement) { |
488 builder.reporter.internalError(builder.compiler.currentElement, | 459 builder.reporter.internalError(builder.compiler.currentElement, |
489 "Runtime type information not available for $local."); | 460 "Runtime type information not available for $local."); |
490 } else { | 461 } else { |
491 builder.reporter.internalError(local, | 462 builder.reporter.internalError(local, "Cannot find value $local."); |
492 "Cannot find value $local."); | |
493 } | 463 } |
494 } | 464 } |
495 HInstruction value = directLocals[local]; | 465 HInstruction value = directLocals[local]; |
496 if (sourceInformation != null) { | 466 if (sourceInformation != null) { |
497 value = new HRef(value, sourceInformation); | 467 value = new HRef(value, sourceInformation); |
498 builder.add(value); | 468 builder.add(value); |
499 } | 469 } |
500 return value; | 470 return value; |
501 } else if (isStoredInClosureField(local)) { | 471 } else if (isStoredInClosureField(local)) { |
502 ClosureFieldElement redirect = redirectionMapping[local]; | 472 ClosureFieldElement redirect = redirectionMapping[local]; |
(...skipping 27 matching lines...) Expand all Loading... |
530 } | 500 } |
531 | 501 |
532 HInstruction readThis() { | 502 HInstruction readThis() { |
533 HInstruction res = readLocal(closureData.thisLocal); | 503 HInstruction res = readLocal(closureData.thisLocal); |
534 if (res.instructionType == null) { | 504 if (res.instructionType == null) { |
535 res.instructionType = builder.getTypeOfThis(); | 505 res.instructionType = builder.getTypeOfThis(); |
536 } | 506 } |
537 return res; | 507 return res; |
538 } | 508 } |
539 | 509 |
540 HLocalValue getLocal(Local local, | 510 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { |
541 {SourceInformation sourceInformation}) { | |
542 // If the element is a parameter, we already have a | 511 // If the element is a parameter, we already have a |
543 // HParameterValue for it. We cannot create another one because | 512 // HParameterValue for it. We cannot create another one because |
544 // it could then have another name than the real parameter. And | 513 // it could then have another name than the real parameter. And |
545 // the other one would not know it is just a copy of the real | 514 // the other one would not know it is just a copy of the real |
546 // parameter. | 515 // parameter. |
547 if (local is ParameterElement) return builder.parameters[local]; | 516 if (local is ParameterElement) return builder.parameters[local]; |
548 | 517 |
549 return builder.activationVariables.putIfAbsent(local, () { | 518 return builder.activationVariables.putIfAbsent(local, () { |
550 JavaScriptBackend backend = builder.backend; | 519 JavaScriptBackend backend = builder.backend; |
551 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) | 520 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) |
552 ..sourceInformation = sourceInformation; | 521 ..sourceInformation = sourceInformation; |
553 builder.graph.entry.addAtExit(localValue); | 522 builder.graph.entry.addAtExit(localValue); |
554 return localValue; | 523 return localValue; |
555 }); | 524 }); |
556 } | 525 } |
557 | 526 |
558 Local getTypeVariableAsLocal(TypeVariableType type) { | 527 Local getTypeVariableAsLocal(TypeVariableType type) { |
559 return typeVariableLocals.putIfAbsent(type, () { | 528 return typeVariableLocals.putIfAbsent(type, () { |
560 return new TypeVariableLocal(type, executableContext); | 529 return new TypeVariableLocal(type, executableContext); |
561 }); | 530 }); |
562 } | 531 } |
563 | 532 |
564 /** | 533 /** |
565 * Sets the [element] to [value]. If the element is boxed or stored in a | 534 * Sets the [element] to [value]. If the element is boxed or stored in a |
566 * closure then the method generates code to set the value. | 535 * closure then the method generates code to set the value. |
567 */ | 536 */ |
568 void updateLocal(Local local, HInstruction value, | 537 void updateLocal(Local local, HInstruction value, |
569 {SourceInformation sourceInformation}) { | 538 {SourceInformation sourceInformation}) { |
570 if (value is HRef) { | 539 if (value is HRef) { |
571 HRef ref = value; | 540 HRef ref = value; |
572 value = ref.value; | 541 value = ref.value; |
573 } | 542 } |
574 assert(!isStoredInClosureField(local)); | 543 assert(!isStoredInClosureField(local)); |
575 if (isAccessedDirectly(local)) { | 544 if (isAccessedDirectly(local)) { |
576 directLocals[local] = value; | 545 directLocals[local] = value; |
577 } else if (isBoxed(local)) { | 546 } else if (isBoxed(local)) { |
578 BoxFieldElement redirect = redirectionMapping[local]; | 547 BoxFieldElement redirect = redirectionMapping[local]; |
579 // The box itself could be captured, or be local. A local variable that | 548 // The box itself could be captured, or be local. A local variable that |
580 // is captured will be boxed, but the box itself will be a local. | 549 // is captured will be boxed, but the box itself will be a local. |
581 // Inside the closure the box is stored in a closure-field and cannot | 550 // Inside the closure the box is stored in a closure-field and cannot |
582 // be accessed directly. | 551 // be accessed directly. |
583 HInstruction box = readLocal(redirect.box); | 552 HInstruction box = readLocal(redirect.box); |
584 builder.add(new HFieldSet(redirect, box, value) | 553 builder.add(new HFieldSet(redirect, box, value) |
585 ..sourceInformation = sourceInformation); | 554 ..sourceInformation = sourceInformation); |
586 } else { | 555 } else { |
587 assert(isUsedInTryOrGenerator(local)); | 556 assert(isUsedInTryOrGenerator(local)); |
588 HLocalValue localValue = getLocal(local); | 557 HLocalValue localValue = getLocal(local); |
589 builder.add(new HLocalSet(local, localValue, value) | 558 builder.add(new HLocalSet(local, localValue, value) |
590 ..sourceInformation = sourceInformation); | 559 ..sourceInformation = sourceInformation); |
591 } | 560 } |
592 } | 561 } |
593 | 562 |
594 /** | 563 /** |
595 * This function, startLoop, must be called before visiting any children of | 564 * This function, startLoop, must be called before visiting any children of |
596 * the loop. In particular it needs to be called before executing the | 565 * the loop. In particular it needs to be called before executing the |
597 * initializers. | 566 * initializers. |
598 * | 567 * |
599 * The [LocalsHandler] will make the boxes and updates at the right moment. | 568 * The [LocalsHandler] will make the boxes and updates at the right moment. |
600 * The builder just needs to call [enterLoopBody] and [enterLoopUpdates] | 569 * The builder just needs to call [enterLoopBody] and [enterLoopUpdates] |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 * Create phis at the loop entry for local variables (ready for the values | 622 * Create phis at the loop entry for local variables (ready for the values |
654 * from the back edge). Populate the phis with the current values. | 623 * from the back edge). Populate the phis with the current values. |
655 */ | 624 */ |
656 void beginLoopHeader(HBasicBlock loopEntry) { | 625 void beginLoopHeader(HBasicBlock loopEntry) { |
657 // Create a copy because we modify the map while iterating over it. | 626 // Create a copy because we modify the map while iterating over it. |
658 Map<Local, HInstruction> savedDirectLocals = | 627 Map<Local, HInstruction> savedDirectLocals = |
659 new Map<Local, HInstruction>.from(directLocals); | 628 new Map<Local, HInstruction>.from(directLocals); |
660 | 629 |
661 JavaScriptBackend backend = builder.backend; | 630 JavaScriptBackend backend = builder.backend; |
662 // Create phis for all elements in the definitions environment. | 631 // Create phis for all elements in the definitions environment. |
663 savedDirectLocals.forEach((Local local, | 632 savedDirectLocals.forEach((Local local, HInstruction instruction) { |
664 HInstruction instruction) { | |
665 if (isAccessedDirectly(local)) { | 633 if (isAccessedDirectly(local)) { |
666 // We know 'this' cannot be modified. | 634 // We know 'this' cannot be modified. |
667 if (local != closureData.thisLocal) { | 635 if (local != closureData.thisLocal) { |
668 HPhi phi = new HPhi.singleInput( | 636 HPhi phi = |
669 local, instruction, backend.dynamicType); | 637 new HPhi.singleInput(local, instruction, backend.dynamicType); |
670 loopEntry.addPhi(phi); | 638 loopEntry.addPhi(phi); |
671 directLocals[local] = phi; | 639 directLocals[local] = phi; |
672 } else { | 640 } else { |
673 directLocals[local] = instruction; | 641 directLocals[local] = instruction; |
674 } | 642 } |
675 } | 643 } |
676 }); | 644 }); |
677 } | 645 } |
678 | 646 |
679 void enterLoopBody(ast.Node node) { | 647 void enterLoopBody(ast.Node node) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 * there is a conflict. | 687 * there is a conflict. |
720 * If a phi node is necessary, it will use this handler's instruction as the | 688 * If a phi node is necessary, it will use this handler's instruction as the |
721 * first input, and the otherLocals instruction as the second. | 689 * first input, and the otherLocals instruction as the second. |
722 */ | 690 */ |
723 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 691 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
724 // If an element is in one map but not the other we can safely | 692 // If an element is in one map but not the other we can safely |
725 // ignore it. It means that a variable was declared in the | 693 // ignore it. It means that a variable was declared in the |
726 // block. Since variable declarations are scoped the declared | 694 // block. Since variable declarations are scoped the declared |
727 // variable cannot be alive outside the block. Note: this is only | 695 // variable cannot be alive outside the block. Note: this is only |
728 // true for nodes where we do joins. | 696 // true for nodes where we do joins. |
729 Map<Local, HInstruction> joinedLocals = | 697 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
730 new Map<Local, HInstruction>(); | |
731 JavaScriptBackend backend = builder.backend; | 698 JavaScriptBackend backend = builder.backend; |
732 otherLocals.directLocals.forEach((Local local, | 699 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { |
733 HInstruction instruction) { | |
734 // We know 'this' cannot be modified. | 700 // We know 'this' cannot be modified. |
735 if (local == closureData.thisLocal) { | 701 if (local == closureData.thisLocal) { |
736 assert(directLocals[local] == instruction); | 702 assert(directLocals[local] == instruction); |
737 joinedLocals[local] = instruction; | 703 joinedLocals[local] = instruction; |
738 } else { | 704 } else { |
739 HInstruction mine = directLocals[local]; | 705 HInstruction mine = directLocals[local]; |
740 if (mine == null) return; | 706 if (mine == null) return; |
741 if (identical(instruction, mine)) { | 707 if (identical(instruction, mine)) { |
742 joinedLocals[local] = instruction; | 708 joinedLocals[local] = instruction; |
743 } else { | 709 } else { |
744 HInstruction phi = new HPhi.manyInputs( | 710 HInstruction phi = new HPhi.manyInputs( |
745 local, <HInstruction>[mine, instruction], backend.dynamicType); | 711 local, <HInstruction>[mine, instruction], backend.dynamicType); |
746 joinBlock.addPhi(phi); | 712 joinBlock.addPhi(phi); |
747 joinedLocals[local] = phi; | 713 joinedLocals[local] = phi; |
748 } | 714 } |
749 } | 715 } |
750 }); | 716 }); |
751 directLocals = joinedLocals; | 717 directLocals = joinedLocals; |
752 } | 718 } |
753 | 719 |
754 /** | 720 /** |
755 * When control flow merges, this method can be used to merge several | 721 * When control flow merges, this method can be used to merge several |
756 * localsHandlers into a new one using phis. The new localsHandler is | 722 * localsHandlers into a new one using phis. The new localsHandler is |
757 * returned. Unless it is also in the list, the current localsHandler is not | 723 * returned. Unless it is also in the list, the current localsHandler is not |
758 * used for its values, only for its declared variables. This is a way to | 724 * used for its values, only for its declared variables. This is a way to |
759 * exclude local values from the result when they are no longer in scope. | 725 * exclude local values from the result when they are no longer in scope. |
760 */ | 726 */ |
761 LocalsHandler mergeMultiple(List<LocalsHandler> localsHandlers, | 727 LocalsHandler mergeMultiple( |
762 HBasicBlock joinBlock) { | 728 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { |
763 assert(localsHandlers.length > 0); | 729 assert(localsHandlers.length > 0); |
764 if (localsHandlers.length == 1) return localsHandlers[0]; | 730 if (localsHandlers.length == 1) return localsHandlers[0]; |
765 Map<Local, HInstruction> joinedLocals = | 731 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
766 new Map<Local, HInstruction>(); | |
767 HInstruction thisValue = null; | 732 HInstruction thisValue = null; |
768 JavaScriptBackend backend = builder.backend; | 733 JavaScriptBackend backend = builder.backend; |
769 directLocals.forEach((Local local, HInstruction instruction) { | 734 directLocals.forEach((Local local, HInstruction instruction) { |
770 if (local != closureData.thisLocal) { | 735 if (local != closureData.thisLocal) { |
771 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); | 736 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); |
772 joinedLocals[local] = phi; | 737 joinedLocals[local] = phi; |
773 joinBlock.addPhi(phi); | 738 joinBlock.addPhi(phi); |
774 } else { | 739 } else { |
775 // We know that "this" never changes, if it's there. | 740 // We know that "this" never changes, if it's there. |
776 // Save it for later. While merging, there is no phi for "this", | 741 // Save it for later. While merging, there is no phi for "this", |
777 // so we don't have to special case it in the merge loop. | 742 // so we don't have to special case it in the merge loop. |
778 thisValue = instruction; | 743 thisValue = instruction; |
779 } | 744 } |
780 }); | 745 }); |
781 for (LocalsHandler handler in localsHandlers) { | 746 for (LocalsHandler handler in localsHandlers) { |
782 handler.directLocals.forEach((Local local, | 747 handler.directLocals.forEach((Local local, HInstruction instruction) { |
783 HInstruction instruction) { | |
784 HPhi phi = joinedLocals[local]; | 748 HPhi phi = joinedLocals[local]; |
785 if (phi != null) { | 749 if (phi != null) { |
786 phi.addInput(instruction); | 750 phi.addInput(instruction); |
787 } | 751 } |
788 }); | 752 }); |
789 } | 753 } |
790 if (thisValue != null) { | 754 if (thisValue != null) { |
791 // If there was a "this" for the scope, add it to the new locals. | 755 // If there was a "this" for the scope, add it to the new locals. |
792 joinedLocals[closureData.thisLocal] = thisValue; | 756 joinedLocals[closureData.thisLocal] = thisValue; |
793 } | 757 } |
794 | 758 |
795 // Remove locals that are not in all handlers. | 759 // Remove locals that are not in all handlers. |
796 directLocals = new Map<Local, HInstruction>(); | 760 directLocals = new Map<Local, HInstruction>(); |
797 joinedLocals.forEach((Local local, | 761 joinedLocals.forEach((Local local, HInstruction instruction) { |
798 HInstruction instruction) { | 762 if (local != closureData.thisLocal && |
799 if (local != closureData.thisLocal | 763 instruction.inputs.length != localsHandlers.length) { |
800 && instruction.inputs.length != localsHandlers.length) { | |
801 joinBlock.removePhi(instruction); | 764 joinBlock.removePhi(instruction); |
802 } else { | 765 } else { |
803 directLocals[local] = instruction; | 766 directLocals[local] = instruction; |
804 } | 767 } |
805 }); | 768 }); |
806 return this; | 769 return this; |
807 } | 770 } |
808 } | 771 } |
809 | 772 |
810 | |
811 // Represents a single break/continue instruction. | 773 // Represents a single break/continue instruction. |
812 class JumpHandlerEntry { | 774 class JumpHandlerEntry { |
813 final HJump jumpInstruction; | 775 final HJump jumpInstruction; |
814 final LocalsHandler locals; | 776 final LocalsHandler locals; |
815 bool isBreak() => jumpInstruction is HBreak; | 777 bool isBreak() => jumpInstruction is HBreak; |
816 bool isContinue() => jumpInstruction is HContinue; | 778 bool isContinue() => jumpInstruction is HContinue; |
817 JumpHandlerEntry(this.jumpInstruction, this.locals); | 779 JumpHandlerEntry(this.jumpInstruction, this.locals); |
818 } | 780 } |
819 | 781 |
820 | |
821 abstract class JumpHandler { | 782 abstract class JumpHandler { |
822 factory JumpHandler(SsaBuilder builder, JumpTarget target) { | 783 factory JumpHandler(SsaBuilder builder, JumpTarget target) { |
823 return new TargetJumpHandler(builder, target); | 784 return new TargetJumpHandler(builder, target); |
824 } | 785 } |
825 void generateBreak([LabelDefinition label]); | 786 void generateBreak([LabelDefinition label]); |
826 void generateContinue([LabelDefinition label]); | 787 void generateContinue([LabelDefinition label]); |
827 void forEachBreak(void action(HBreak instruction, LocalsHandler locals)); | 788 void forEachBreak(void action(HBreak instruction, LocalsHandler locals)); |
828 void forEachContinue(void action(HContinue instruction, | 789 void forEachContinue( |
829 LocalsHandler locals)); | 790 void action(HContinue instruction, LocalsHandler locals)); |
830 bool hasAnyContinue(); | 791 bool hasAnyContinue(); |
831 bool hasAnyBreak(); | 792 bool hasAnyBreak(); |
832 void close(); | 793 void close(); |
833 final JumpTarget target; | 794 final JumpTarget target; |
834 List<LabelDefinition> labels(); | 795 List<LabelDefinition> labels(); |
835 } | 796 } |
836 | 797 |
837 // Insert break handler used to avoid null checks when a target isn't | 798 // Insert break handler used to avoid null checks when a target isn't |
838 // used as the target of a break, and therefore doesn't need a break | 799 // used as the target of a break, and therefore doesn't need a break |
839 // handler associated with it. | 800 // handler associated with it. |
840 class NullJumpHandler implements JumpHandler { | 801 class NullJumpHandler implements JumpHandler { |
841 final DiagnosticReporter reporter; | 802 final DiagnosticReporter reporter; |
842 | 803 |
843 NullJumpHandler(this.reporter); | 804 NullJumpHandler(this.reporter); |
844 | 805 |
845 void generateBreak([LabelDefinition label]) { | 806 void generateBreak([LabelDefinition label]) { |
846 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 807 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
847 'NullJumpHandler.generateBreak should not be called.'); | 808 'NullJumpHandler.generateBreak should not be called.'); |
848 } | 809 } |
849 | 810 |
850 void generateContinue([LabelDefinition label]) { | 811 void generateContinue([LabelDefinition label]) { |
851 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 812 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
852 'NullJumpHandler.generateContinue should not be called.'); | 813 'NullJumpHandler.generateContinue should not be called.'); |
853 } | 814 } |
854 | 815 |
855 void forEachBreak(Function ignored) { } | 816 void forEachBreak(Function ignored) {} |
856 void forEachContinue(Function ignored) { } | 817 void forEachContinue(Function ignored) {} |
857 void close() { } | 818 void close() {} |
858 bool hasAnyContinue() => false; | 819 bool hasAnyContinue() => false; |
859 bool hasAnyBreak() => false; | 820 bool hasAnyBreak() => false; |
860 | 821 |
861 List<LabelDefinition> labels() => const <LabelDefinition>[]; | 822 List<LabelDefinition> labels() => const <LabelDefinition>[]; |
862 JumpTarget get target => null; | 823 JumpTarget get target => null; |
863 } | 824 } |
864 | 825 |
865 // Records breaks until a target block is available. | 826 // Records breaks until a target block is available. |
866 // Breaks are always forward jumps. | 827 // Breaks are always forward jumps. |
867 // Continues in loops are implemented as breaks of the body. | 828 // Continues in loops are implemented as breaks of the body. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 } | 907 } |
947 } | 908 } |
948 | 909 |
949 /// Special [JumpHandler] implementation used to handle continue statements | 910 /// Special [JumpHandler] implementation used to handle continue statements |
950 /// targeting switch cases. | 911 /// targeting switch cases. |
951 class SwitchCaseJumpHandler extends TargetJumpHandler { | 912 class SwitchCaseJumpHandler extends TargetJumpHandler { |
952 /// Map from switch case targets to indices used to encode the flow of the | 913 /// Map from switch case targets to indices used to encode the flow of the |
953 /// switch case loop. | 914 /// switch case loop. |
954 final Map<JumpTarget, int> targetIndexMap = new Map<JumpTarget, int>(); | 915 final Map<JumpTarget, int> targetIndexMap = new Map<JumpTarget, int>(); |
955 | 916 |
956 SwitchCaseJumpHandler(SsaBuilder builder, | 917 SwitchCaseJumpHandler( |
957 JumpTarget target, | 918 SsaBuilder builder, JumpTarget target, ast.SwitchStatement node) |
958 ast.SwitchStatement node) | |
959 : super(builder, target) { | 919 : super(builder, target) { |
960 // The switch case indices must match those computed in | 920 // The switch case indices must match those computed in |
961 // [SsaFromAstMixin.buildSwitchCaseConstants]. | 921 // [SsaFromAstMixin.buildSwitchCaseConstants]. |
962 // Switch indices are 1-based so we can bypass the synthetic loop when no | 922 // Switch indices are 1-based so we can bypass the synthetic loop when no |
963 // cases match simply by branching on the index (which defaults to null). | 923 // cases match simply by branching on the index (which defaults to null). |
964 int switchIndex = 1; | 924 int switchIndex = 1; |
965 for (ast.SwitchCase switchCase in node.cases) { | 925 for (ast.SwitchCase switchCase in node.cases) { |
966 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 926 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
967 ast.Node label = labelOrCase.asLabel(); | 927 ast.Node label = labelOrCase.asLabel(); |
968 if (label != null) { | 928 if (label != null) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1000 return label != null && targetIndexMap.containsKey(label.target); | 960 return label != null && targetIndexMap.containsKey(label.target); |
1001 } | 961 } |
1002 | 962 |
1003 void generateContinue([LabelDefinition label]) { | 963 void generateContinue([LabelDefinition label]) { |
1004 if (isContinueToSwitchCase(label)) { | 964 if (isContinueToSwitchCase(label)) { |
1005 // Creates the special instructions 'label = i; continue l;' used in | 965 // Creates the special instructions 'label = i; continue l;' used in |
1006 // switch statements with continue statements. See | 966 // switch statements with continue statements. See |
1007 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. | 967 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. |
1008 | 968 |
1009 assert(label != null); | 969 assert(label != null); |
1010 HInstruction value = builder.graph.addConstantInt( | 970 HInstruction value = builder.graph |
1011 targetIndexMap[label.target], | 971 .addConstantInt(targetIndexMap[label.target], builder.compiler); |
1012 builder.compiler); | |
1013 builder.localsHandler.updateLocal(target, value); | 972 builder.localsHandler.updateLocal(target, value); |
1014 | 973 |
1015 assert(label.target.labels.contains(label)); | 974 assert(label.target.labels.contains(label)); |
1016 HInstruction continueInstruction = new HContinue(target); | 975 HInstruction continueInstruction = new HContinue(target); |
1017 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | 976 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); |
1018 builder.close(continueInstruction); | 977 builder.close(continueInstruction); |
1019 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); | 978 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); |
1020 } else { | 979 } else { |
1021 super.generateContinue(label); | 980 super.generateContinue(label); |
1022 } | 981 } |
1023 } | 982 } |
1024 | 983 |
1025 void close() { | 984 void close() { |
1026 // The mapping from TargetElement to JumpHandler is no longer needed. | 985 // The mapping from TargetElement to JumpHandler is no longer needed. |
1027 for (JumpTarget target in targetIndexMap.keys) { | 986 for (JumpTarget target in targetIndexMap.keys) { |
1028 builder.jumpTargets.remove(target); | 987 builder.jumpTargets.remove(target); |
1029 } | 988 } |
1030 super.close(); | 989 super.close(); |
1031 } | 990 } |
1032 } | 991 } |
1033 | 992 |
1034 /** | 993 /** |
1035 * This class builds SSA nodes for functions represented in AST. | 994 * This class builds SSA nodes for functions represented in AST. |
1036 */ | 995 */ |
1037 class SsaBuilder extends ast.Visitor | 996 class SsaBuilder extends ast.Visitor |
1038 with BaseImplementationOfCompoundsMixin, | 997 with |
1039 BaseImplementationOfSetIfNullsMixin, | 998 BaseImplementationOfCompoundsMixin, |
1040 BaseImplementationOfSuperIndexSetIfNullMixin, | 999 BaseImplementationOfSetIfNullsMixin, |
1041 SemanticSendResolvedMixin, | 1000 BaseImplementationOfSuperIndexSetIfNullMixin, |
1042 NewBulkMixin, | 1001 SemanticSendResolvedMixin, |
1043 ErrorBulkMixin | 1002 NewBulkMixin, |
| 1003 ErrorBulkMixin |
1044 implements SemanticSendVisitor { | 1004 implements SemanticSendVisitor { |
1045 | |
1046 /// The element for which this SSA builder is being used. | 1005 /// The element for which this SSA builder is being used. |
1047 final Element target; | 1006 final Element target; |
1048 | 1007 |
1049 /// Reference to resolved elements in [target]'s AST. | 1008 /// Reference to resolved elements in [target]'s AST. |
1050 TreeElements elements; | 1009 TreeElements elements; |
1051 | 1010 |
1052 /// Used to report information about inlining (which occurs while building the | 1011 /// Used to report information about inlining (which occurs while building the |
1053 /// SSA graph), when dump-info is enabled. | 1012 /// SSA graph), when dump-info is enabled. |
1054 final InfoReporter infoReporter; | 1013 final InfoReporter infoReporter; |
1055 | 1014 |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 Map<ParameterElement, HInstruction> parameters = | 1098 Map<ParameterElement, HInstruction> parameters = |
1140 <ParameterElement, HInstruction>{}; | 1099 <ParameterElement, HInstruction>{}; |
1141 | 1100 |
1142 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; | 1101 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; |
1143 | 1102 |
1144 /** | 1103 /** |
1145 * Variables stored in the current activation. These variables are | 1104 * Variables stored in the current activation. These variables are |
1146 * being updated in try/catch blocks, and should be | 1105 * being updated in try/catch blocks, and should be |
1147 * accessed indirectly through [HLocalGet] and [HLocalSet]. | 1106 * accessed indirectly through [HLocalGet] and [HLocalSet]. |
1148 */ | 1107 */ |
1149 Map<Local, HLocalValue> activationVariables = | 1108 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; |
1150 <Local, HLocalValue>{}; | |
1151 | 1109 |
1152 // We build the Ssa graph by simulating a stack machine. | 1110 // We build the Ssa graph by simulating a stack machine. |
1153 List<HInstruction> stack = <HInstruction>[]; | 1111 List<HInstruction> stack = <HInstruction>[]; |
1154 | 1112 |
1155 /// Returns `true` if the current element is an `async` function. | 1113 /// Returns `true` if the current element is an `async` function. |
1156 bool get isBuildingAsyncFunction { | 1114 bool get isBuildingAsyncFunction { |
1157 Element element = sourceElement; | 1115 Element element = sourceElement; |
1158 return (element is FunctionElement && | 1116 return (element is FunctionElement && |
1159 element.asyncMarker == AsyncMarker.ASYNC); | 1117 element.asyncMarker == AsyncMarker.ASYNC); |
1160 } | 1118 } |
1161 | 1119 |
1162 // TODO(sigmund): make most args optional | 1120 // TODO(sigmund): make most args optional |
1163 SsaBuilder(this.target, this.elements, this.context, this.registry, | 1121 SsaBuilder( |
1164 JavaScriptBackend backend, this.nativeEmitter, | 1122 this.target, |
| 1123 this.elements, |
| 1124 this.context, |
| 1125 this.registry, |
| 1126 JavaScriptBackend backend, |
| 1127 this.nativeEmitter, |
1165 SourceInformationStrategy sourceInformationFactory) | 1128 SourceInformationStrategy sourceInformationFactory) |
1166 : this.compiler = backend.compiler, | 1129 : this.compiler = backend.compiler, |
1167 this.infoReporter = backend.compiler.dumpInfoTask, | 1130 this.infoReporter = backend.compiler.dumpInfoTask, |
1168 this.backend = backend, | 1131 this.backend = backend, |
1169 this.constantSystem = backend.constantSystem, | 1132 this.constantSystem = backend.constantSystem, |
1170 this.rti = backend.rti { | 1133 this.rti = backend.rti { |
1171 assert(target.isImplementation); | 1134 assert(target.isImplementation); |
1172 graph.element = target; | 1135 graph.element = target; |
1173 localsHandler = new LocalsHandler(this, target, null); | 1136 localsHandler = new LocalsHandler(this, target, null); |
1174 sourceElementStack.add(target); | 1137 sourceElementStack.add(target); |
1175 sourceInformationBuilder = sourceInformationFactory.createBuilderForContext( | 1138 sourceInformationBuilder = |
1176 target); | 1139 sourceInformationFactory.createBuilderForContext(target); |
1177 graph.sourceInformation = | 1140 graph.sourceInformation = |
1178 sourceInformationBuilder.buildVariableDeclaration(); | 1141 sourceInformationBuilder.buildVariableDeclaration(); |
1179 } | 1142 } |
1180 | 1143 |
1181 BackendHelpers get helpers => backend.helpers; | 1144 BackendHelpers get helpers => backend.helpers; |
1182 | 1145 |
1183 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder; | 1146 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder; |
1184 | 1147 |
1185 DiagnosticReporter get reporter => compiler.reporter; | 1148 DiagnosticReporter get reporter => compiler.reporter; |
1186 | 1149 |
(...skipping 12 matching lines...) Expand all Loading... |
1199 node.accept(this); | 1162 node.accept(this); |
1200 } | 1163 } |
1201 | 1164 |
1202 /// Returns the current source element. | 1165 /// Returns the current source element. |
1203 /// | 1166 /// |
1204 /// The returned element is a declaration element. | 1167 /// The returned element is a declaration element. |
1205 // TODO(johnniwinther): Check that all usages of sourceElement agree on | 1168 // TODO(johnniwinther): Check that all usages of sourceElement agree on |
1206 // implementation/declaration distinction. | 1169 // implementation/declaration distinction. |
1207 Element get sourceElement => sourceElementStack.last; | 1170 Element get sourceElement => sourceElementStack.last; |
1208 | 1171 |
1209 bool get _checkOrTrustTypes => compiler.options.enableTypeAssertions || | 1172 bool get _checkOrTrustTypes => |
| 1173 compiler.options.enableTypeAssertions || |
1210 compiler.options.trustTypeAnnotations; | 1174 compiler.options.trustTypeAnnotations; |
1211 | 1175 |
1212 /// Build the graph for [target]. | 1176 /// Build the graph for [target]. |
1213 HGraph build() { | 1177 HGraph build() { |
1214 assert(invariant(target, target.isImplementation)); | 1178 assert(invariant(target, target.isImplementation)); |
1215 HInstruction.idCounter = 0; | 1179 HInstruction.idCounter = 0; |
1216 // TODO(sigmund): remove `result` and return graph directly, need to ensure | 1180 // TODO(sigmund): remove `result` and return graph directly, need to ensure |
1217 // that it can never be null (see result in buildFactory for instance). | 1181 // that it can never be null (see result in buildFactory for instance). |
1218 var result; | 1182 var result; |
1219 if (target.isGenerativeConstructor) { | 1183 if (target.isGenerativeConstructor) { |
1220 result = buildFactory(target); | 1184 result = buildFactory(target); |
1221 } else if (target.isGenerativeConstructorBody || | 1185 } else if (target.isGenerativeConstructorBody || |
1222 target.isFactoryConstructor || | 1186 target.isFactoryConstructor || |
1223 target.isFunction || | 1187 target.isFunction || |
1224 target.isGetter || | 1188 target.isGetter || |
1225 target.isSetter) { | 1189 target.isSetter) { |
1226 result = buildMethod(target); | 1190 result = buildMethod(target); |
1227 } else if (target.isField) { | 1191 } else if (target.isField) { |
1228 if (target.isInstanceMember) { | 1192 if (target.isInstanceMember) { |
1229 assert(compiler.options.enableTypeAssertions); | 1193 assert(compiler.options.enableTypeAssertions); |
1230 result = buildCheckedSetter(target); | 1194 result = buildCheckedSetter(target); |
1231 } else { | 1195 } else { |
1232 result = buildLazyInitializer(target); | 1196 result = buildLazyInitializer(target); |
1233 } | 1197 } |
1234 } else { | 1198 } else { |
1235 reporter.internalError(target, 'Unexpected element kind $target.'); | 1199 reporter.internalError(target, 'Unexpected element kind $target.'); |
1236 } | 1200 } |
1237 assert(result.isValid()); | 1201 assert(result.isValid()); |
1238 return result; | 1202 return result; |
1239 } | 1203 } |
1240 | 1204 |
1241 | |
1242 HBasicBlock addNewBlock() { | 1205 HBasicBlock addNewBlock() { |
1243 HBasicBlock block = graph.addNewBlock(); | 1206 HBasicBlock block = graph.addNewBlock(); |
1244 // If adding a new block during building of an expression, it is due to | 1207 // If adding a new block during building of an expression, it is due to |
1245 // conditional expressions or short-circuit logical operators. | 1208 // conditional expressions or short-circuit logical operators. |
1246 return block; | 1209 return block; |
1247 } | 1210 } |
1248 | 1211 |
1249 void open(HBasicBlock block) { | 1212 void open(HBasicBlock block) { |
1250 block.open(); | 1213 block.open(); |
1251 current = block; | 1214 current = block; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1302 FunctionElement function, | 1265 FunctionElement function, |
1303 Selector selector, | 1266 Selector selector, |
1304 List<HInstruction> providedArguments, | 1267 List<HInstruction> providedArguments, |
1305 ast.Node currentNode) { | 1268 ast.Node currentNode) { |
1306 assert(invariant(function, function.isImplementation)); | 1269 assert(invariant(function, function.isImplementation)); |
1307 assert(providedArguments != null); | 1270 assert(providedArguments != null); |
1308 | 1271 |
1309 bool isInstanceMember = function.isInstanceMember; | 1272 bool isInstanceMember = function.isInstanceMember; |
1310 // For static calls, [providedArguments] is complete, default arguments | 1273 // For static calls, [providedArguments] is complete, default arguments |
1311 // have been included if necessary, see [makeStaticArgumentList]. | 1274 // have been included if necessary, see [makeStaticArgumentList]. |
1312 if (!isInstanceMember | 1275 if (!isInstanceMember || |
1313 || currentNode == null // In erroneous code, currentNode can be null. | 1276 currentNode == null // In erroneous code, currentNode can be null. |
1314 || providedArgumentsKnownToBeComplete(currentNode) | 1277 || |
1315 || function.isGenerativeConstructorBody | 1278 providedArgumentsKnownToBeComplete(currentNode) || |
1316 || selector.isGetter) { | 1279 function.isGenerativeConstructorBody || |
| 1280 selector.isGetter) { |
1317 // For these cases, the provided argument list is known to be complete. | 1281 // For these cases, the provided argument list is known to be complete. |
1318 return providedArguments; | 1282 return providedArguments; |
1319 } else { | 1283 } else { |
1320 return completeDynamicSendArgumentsList( | 1284 return completeDynamicSendArgumentsList( |
1321 selector, function, providedArguments); | 1285 selector, function, providedArguments); |
1322 } | 1286 } |
1323 } | 1287 } |
1324 | 1288 |
1325 /** | 1289 /** |
1326 * Returns a complete argument list for a dynamic call of [function]. The | 1290 * Returns a complete argument list for a dynamic call of [function]. The |
1327 * initial argument list [providedArguments], created by | 1291 * initial argument list [providedArguments], created by |
1328 * [addDynamicSendArgumentsToList], does not include values for default | 1292 * [addDynamicSendArgumentsToList], does not include values for default |
1329 * arguments used in the call. The reason is that the target function (which | 1293 * arguments used in the call. The reason is that the target function (which |
1330 * defines the defaults) is not known. | 1294 * defines the defaults) is not known. |
1331 * | 1295 * |
1332 * However, inlining can only be performed when the target function can be | 1296 * However, inlining can only be performed when the target function can be |
1333 * resolved statically. The defaults can therefore be included at this point. | 1297 * resolved statically. The defaults can therefore be included at this point. |
1334 * | 1298 * |
1335 * The [providedArguments] list contains first all positional arguments, then | 1299 * The [providedArguments] list contains first all positional arguments, then |
1336 * the provided named arguments (the named arguments that are defined in the | 1300 * the provided named arguments (the named arguments that are defined in the |
1337 * [selector]) in a specific order (see [addDynamicSendArgumentsToList]). | 1301 * [selector]) in a specific order (see [addDynamicSendArgumentsToList]). |
1338 */ | 1302 */ |
1339 List<HInstruction> completeDynamicSendArgumentsList( | 1303 List<HInstruction> completeDynamicSendArgumentsList(Selector selector, |
1340 Selector selector, | 1304 FunctionElement function, List<HInstruction> providedArguments) { |
1341 FunctionElement function, | |
1342 List<HInstruction> providedArguments) { | |
1343 assert(selector.applies(function, compiler.world)); | 1305 assert(selector.applies(function, compiler.world)); |
1344 FunctionSignature signature = function.functionSignature; | 1306 FunctionSignature signature = function.functionSignature; |
1345 List<HInstruction> compiledArguments = new List<HInstruction>( | 1307 List<HInstruction> compiledArguments = new List<HInstruction>( |
1346 signature.parameterCount + 1); // Plus one for receiver. | 1308 signature.parameterCount + 1); // Plus one for receiver. |
1347 | 1309 |
1348 compiledArguments[0] = providedArguments[0]; // Receiver. | 1310 compiledArguments[0] = providedArguments[0]; // Receiver. |
1349 int index = 1; | 1311 int index = 1; |
1350 for (; index <= signature.requiredParameterCount; index++) { | 1312 for (; index <= signature.requiredParameterCount; index++) { |
1351 compiledArguments[index] = providedArguments[index]; | 1313 compiledArguments[index] = providedArguments[index]; |
1352 } | 1314 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1389 index++; | 1351 index++; |
1390 }); | 1352 }); |
1391 } | 1353 } |
1392 return compiledArguments; | 1354 return compiledArguments; |
1393 } | 1355 } |
1394 | 1356 |
1395 /** | 1357 /** |
1396 * Try to inline [element] within the currect context of the builder. The | 1358 * Try to inline [element] within the currect context of the builder. The |
1397 * insertion point is the state of the builder. | 1359 * insertion point is the state of the builder. |
1398 */ | 1360 */ |
1399 bool tryInlineMethod(Element element, | 1361 bool tryInlineMethod(Element element, Selector selector, TypeMask mask, |
1400 Selector selector, | 1362 List<HInstruction> providedArguments, ast.Node currentNode, |
1401 TypeMask mask, | 1363 {InterfaceType instanceType}) { |
1402 List<HInstruction> providedArguments, | |
1403 ast.Node currentNode, | |
1404 {InterfaceType instanceType}) { | |
1405 // TODO(johnniwinther): Register this on the [registry]. Currently the | 1364 // TODO(johnniwinther): Register this on the [registry]. Currently the |
1406 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be | 1365 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be |
1407 // enqueued. | 1366 // enqueued. |
1408 backend.registerStaticUse(element, compiler.enqueuer.codegen); | 1367 backend.registerStaticUse(element, compiler.enqueuer.codegen); |
1409 | 1368 |
1410 if (backend.isJsInterop(element) && !element.isFactoryConstructor) { | 1369 if (backend.isJsInterop(element) && !element.isFactoryConstructor) { |
1411 // We only inline factory JavaScript interop constructors. | 1370 // We only inline factory JavaScript interop constructors. |
1412 return false; | 1371 return false; |
1413 } | 1372 } |
1414 | 1373 |
(...skipping 10 matching lines...) Expand all Loading... |
1425 bool cachedCanBeInlined = | 1384 bool cachedCanBeInlined = |
1426 backend.inlineCache.canInline(function, insideLoop: insideLoop); | 1385 backend.inlineCache.canInline(function, insideLoop: insideLoop); |
1427 if (cachedCanBeInlined == false) return false; | 1386 if (cachedCanBeInlined == false) return false; |
1428 | 1387 |
1429 bool meetsHardConstraints() { | 1388 bool meetsHardConstraints() { |
1430 if (compiler.options.disableInlining) return false; | 1389 if (compiler.options.disableInlining) return false; |
1431 | 1390 |
1432 assert(invariant( | 1391 assert(invariant( |
1433 currentNode != null ? currentNode : element, | 1392 currentNode != null ? currentNode : element, |
1434 selector != null || | 1393 selector != null || |
1435 Elements.isStaticOrTopLevel(element) || | 1394 Elements.isStaticOrTopLevel(element) || |
1436 element.isGenerativeConstructorBody, | 1395 element.isGenerativeConstructorBody, |
1437 message: "Missing selector for inlining of $element.")); | 1396 message: "Missing selector for inlining of $element.")); |
1438 if (selector != null) { | 1397 if (selector != null) { |
1439 if (!selector.applies(function, compiler.world)) return false; | 1398 if (!selector.applies(function, compiler.world)) return false; |
1440 if (mask != null && !mask.canHit(function, selector, compiler.world)) { | 1399 if (mask != null && !mask.canHit(function, selector, compiler.world)) { |
1441 return false; | 1400 return false; |
1442 } | 1401 } |
1443 } | 1402 } |
1444 | 1403 |
1445 if (backend.isJsInterop(element)) return false; | 1404 if (backend.isJsInterop(element)) return false; |
1446 | 1405 |
1447 // Don't inline operator== methods if the parameter can be null. | 1406 // Don't inline operator== methods if the parameter can be null. |
1448 if (element.name == '==') { | 1407 if (element.name == '==') { |
1449 if (element.enclosingClass != coreClasses.objectClass | 1408 if (element.enclosingClass != coreClasses.objectClass && |
1450 && providedArguments[1].canBeNull()) { | 1409 providedArguments[1].canBeNull()) { |
1451 return false; | 1410 return false; |
1452 } | 1411 } |
1453 } | 1412 } |
1454 | 1413 |
1455 // Generative constructors of native classes should not be called directly | 1414 // Generative constructors of native classes should not be called directly |
1456 // and have an extra argument that causes problems with inlining. | 1415 // and have an extra argument that causes problems with inlining. |
1457 if (element.isGenerativeConstructor | 1416 if (element.isGenerativeConstructor && |
1458 && backend.isNativeOrExtendsNative(element.enclosingClass)) { | 1417 backend.isNativeOrExtendsNative(element.enclosingClass)) { |
1459 return false; | 1418 return false; |
1460 } | 1419 } |
1461 | 1420 |
1462 // A generative constructor body is not seen by global analysis, | 1421 // A generative constructor body is not seen by global analysis, |
1463 // so we should not query for its type. | 1422 // so we should not query for its type. |
1464 if (!element.isGenerativeConstructorBody) { | 1423 if (!element.isGenerativeConstructorBody) { |
1465 // Don't inline if the return type was inferred to be non-null empty. | 1424 // Don't inline if the return type was inferred to be non-null empty. |
1466 // This means that the function always throws an exception. | 1425 // This means that the function always throws an exception. |
1467 TypeMask returnType = | 1426 TypeMask returnType = |
1468 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); | 1427 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1517 | 1476 |
1518 // Do not inline code that is rarely executed unless it reduces size. | 1477 // Do not inline code that is rarely executed unless it reduces size. |
1519 if (inExpressionOfThrow || inLazyInitializerExpression) { | 1478 if (inExpressionOfThrow || inLazyInitializerExpression) { |
1520 return reductiveHeuristic(); | 1479 return reductiveHeuristic(); |
1521 } | 1480 } |
1522 | 1481 |
1523 if (cachedCanBeInlined == true) { | 1482 if (cachedCanBeInlined == true) { |
1524 // We may have forced the inlining of some methods. Therefore check | 1483 // We may have forced the inlining of some methods. Therefore check |
1525 // if we can inline this method regardless of size. | 1484 // if we can inline this method regardless of size. |
1526 assert(InlineWeeder.canBeInlined(function, -1, false, | 1485 assert(InlineWeeder.canBeInlined(function, -1, false, |
1527 allowLoops: true, | 1486 allowLoops: true, |
1528 enableUserAssertions: compiler.options.enableUserAssertions)); | 1487 enableUserAssertions: compiler.options.enableUserAssertions)); |
1529 return true; | 1488 return true; |
1530 } | 1489 } |
1531 | 1490 |
1532 int numParameters = function.functionSignature.parameterCount; | 1491 int numParameters = function.functionSignature.parameterCount; |
1533 int maxInliningNodes; | 1492 int maxInliningNodes; |
1534 bool useMaxInliningNodes = true; | 1493 bool useMaxInliningNodes = true; |
1535 if (insideLoop) { | 1494 if (insideLoop) { |
1536 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + | 1495 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + |
1537 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; | 1496 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; |
1538 } else { | 1497 } else { |
(...skipping 21 matching lines...) Expand all Loading... |
1560 | 1519 |
1561 void doInlining() { | 1520 void doInlining() { |
1562 // Add an explicit null check on the receiver before doing the | 1521 // Add an explicit null check on the receiver before doing the |
1563 // inlining. We use [element] to get the same name in the | 1522 // inlining. We use [element] to get the same name in the |
1564 // NoSuchMethodError message as if we had called it. | 1523 // NoSuchMethodError message as if we had called it. |
1565 if (element.isInstanceMember && | 1524 if (element.isInstanceMember && |
1566 !element.isGenerativeConstructorBody && | 1525 !element.isGenerativeConstructorBody && |
1567 (mask == null || mask.isNullable)) { | 1526 (mask == null || mask.isNullable)) { |
1568 addWithPosition( | 1527 addWithPosition( |
1569 new HFieldGet(null, providedArguments[0], backend.dynamicType, | 1528 new HFieldGet(null, providedArguments[0], backend.dynamicType, |
1570 isAssignable: false), | 1529 isAssignable: false), |
1571 currentNode); | 1530 currentNode); |
1572 } | 1531 } |
1573 List<HInstruction> compiledArguments = completeSendArgumentsList( | 1532 List<HInstruction> compiledArguments = completeSendArgumentsList( |
1574 function, selector, providedArguments, currentNode); | 1533 function, selector, providedArguments, currentNode); |
1575 enterInlinedMethod( | 1534 enterInlinedMethod(function, currentNode, compiledArguments, |
1576 function, currentNode, compiledArguments, instanceType: instanceType); | 1535 instanceType: instanceType); |
1577 inlinedFrom(function, () { | 1536 inlinedFrom(function, () { |
1578 if (!isReachable) { | 1537 if (!isReachable) { |
1579 emitReturn(graph.addConstantNull(compiler), null); | 1538 emitReturn(graph.addConstantNull(compiler), null); |
1580 } else { | 1539 } else { |
1581 doInline(function); | 1540 doInline(function); |
1582 } | 1541 } |
1583 }); | 1542 }); |
1584 leaveInlinedMethod(); | 1543 leaveInlinedMethod(); |
1585 } | 1544 } |
1586 | 1545 |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1721 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement); | 1680 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement); |
1722 ast.FunctionExpression function = functionElement.node; | 1681 ast.FunctionExpression function = functionElement.node; |
1723 assert(function != null); | 1682 assert(function != null); |
1724 assert(elements.getFunctionDefinition(function) != null); | 1683 assert(elements.getFunctionDefinition(function) != null); |
1725 openFunction(functionElement, function); | 1684 openFunction(functionElement, function); |
1726 String name = functionElement.name; | 1685 String name = functionElement.name; |
1727 if (backend.isJsInterop(functionElement)) { | 1686 if (backend.isJsInterop(functionElement)) { |
1728 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), | 1687 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), |
1729 sourceInformationBuilder.buildGeneric(function))); | 1688 sourceInformationBuilder.buildGeneric(function))); |
1730 var value = pop(); | 1689 var value = pop(); |
1731 closeAndGotoExit(new HReturn(value, | 1690 closeAndGotoExit(new HReturn( |
1732 sourceInformationBuilder.buildReturn(functionElement.node))); | 1691 value, sourceInformationBuilder.buildReturn(functionElement.node))); |
1733 return closeFunction(); | 1692 return closeFunction(); |
1734 } | 1693 } |
1735 assert(invariant(functionElement, !function.modifiers.isExternal)); | 1694 assert(invariant(functionElement, !function.modifiers.isExternal)); |
1736 | 1695 |
1737 // If [functionElement] is `operator==` we explicitely add a null check at | 1696 // If [functionElement] is `operator==` we explicitely add a null check at |
1738 // the beginning of the method. This is to avoid having call sites do the | 1697 // the beginning of the method. This is to avoid having call sites do the |
1739 // null check. | 1698 // null check. |
1740 if (name == '==') { | 1699 if (name == '==') { |
1741 if (!backend.operatorEqHandlesNullArgument(functionElement)) { | 1700 if (!backend.operatorEqHandlesNullArgument(functionElement)) { |
1742 handleIf( | 1701 handleIf(function, visitCondition: () { |
1743 function, | 1702 HParameterValue parameter = parameters.values.first; |
1744 visitCondition: () { | 1703 push(new HIdentity(parameter, graph.addConstantNull(compiler), null, |
1745 HParameterValue parameter = parameters.values.first; | 1704 backend.boolType)); |
1746 push(new HIdentity( | 1705 }, visitThen: () { |
1747 parameter, graph.addConstantNull(compiler), null, | 1706 closeAndGotoExit(new HReturn(graph.addConstantBool(false, compiler), |
1748 backend.boolType)); | 1707 sourceInformationBuilder.buildImplicitReturn(functionElement))); |
1749 }, | 1708 }, |
1750 visitThen: () { | |
1751 closeAndGotoExit(new HReturn( | |
1752 graph.addConstantBool(false, compiler), | |
1753 sourceInformationBuilder | |
1754 .buildImplicitReturn(functionElement))); | |
1755 }, | |
1756 visitElse: null, | 1709 visitElse: null, |
1757 sourceInformation: sourceInformationBuilder.buildIf(function.body)); | 1710 sourceInformation: sourceInformationBuilder.buildIf(function.body)); |
1758 } | 1711 } |
1759 } | 1712 } |
1760 if (const bool.fromEnvironment('unreachable-throw') == true) { | 1713 if (const bool.fromEnvironment('unreachable-throw') == true) { |
1761 var emptyParameters = parameters.values | 1714 var emptyParameters = |
1762 .where((p) => p.instructionType.isEmpty); | 1715 parameters.values.where((p) => p.instructionType.isEmpty); |
1763 if (emptyParameters.length > 0) { | 1716 if (emptyParameters.length > 0) { |
1764 addComment('${emptyParameters} inferred as [empty]'); | 1717 addComment('${emptyParameters} inferred as [empty]'); |
1765 pushInvokeStatic(function.body, helpers.assertUnreachableMethod, []); | 1718 pushInvokeStatic(function.body, helpers.assertUnreachableMethod, []); |
1766 pop(); | 1719 pop(); |
1767 return closeFunction(); | 1720 return closeFunction(); |
1768 } | 1721 } |
1769 } | 1722 } |
1770 function.body.accept(this); | 1723 function.body.accept(this); |
1771 return closeFunction(); | 1724 return closeFunction(); |
1772 } | 1725 } |
1773 | 1726 |
1774 /// Adds a JavaScript comment to the output. The comment will be omitted in | 1727 /// Adds a JavaScript comment to the output. The comment will be omitted in |
1775 /// minified mode. Each line in [text] is preceded with `//` and indented. | 1728 /// minified mode. Each line in [text] is preceded with `//` and indented. |
1776 /// Use sparingly. In order for the comment to be retained it is modeled as | 1729 /// Use sparingly. In order for the comment to be retained it is modeled as |
1777 /// having side effects which will inhibit code motion. | 1730 /// having side effects which will inhibit code motion. |
1778 // TODO(sra): Figure out how to keep comment anchored without effects. | 1731 // TODO(sra): Figure out how to keep comment anchored without effects. |
1779 void addComment(String text) { | 1732 void addComment(String text) { |
1780 add(new HForeignCode( | 1733 add(new HForeignCode(js.js.statementTemplateYielding(new js.Comment(text)), |
1781 js.js.statementTemplateYielding(new js.Comment(text)), | 1734 backend.dynamicType, <HInstruction>[], |
1782 backend.dynamicType, | |
1783 <HInstruction>[], | |
1784 isStatement: true)); | 1735 isStatement: true)); |
1785 } | 1736 } |
1786 | 1737 |
1787 HGraph buildCheckedSetter(VariableElement field) { | 1738 HGraph buildCheckedSetter(VariableElement field) { |
1788 openFunction(field, field.node); | 1739 openFunction(field, field.node); |
1789 HInstruction thisInstruction = localsHandler.readThis(); | 1740 HInstruction thisInstruction = localsHandler.readThis(); |
1790 // Use dynamic type because the type computed by the inferrer is | 1741 // Use dynamic type because the type computed by the inferrer is |
1791 // narrowed to the type annotation. | 1742 // narrowed to the type annotation. |
1792 HInstruction parameter = new HParameterValue(field, backend.dynamicType); | 1743 HInstruction parameter = new HParameterValue(field, backend.dynamicType); |
1793 // Add the parameter as the last instruction of the entry block. | 1744 // Add the parameter as the last instruction of the entry block. |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1871 | 1822 |
1872 /** | 1823 /** |
1873 * This method sets up the local state of the builder for inlining [function]. | 1824 * This method sets up the local state of the builder for inlining [function]. |
1874 * The arguments of the function are inserted into the [localsHandler]. | 1825 * The arguments of the function are inserted into the [localsHandler]. |
1875 * | 1826 * |
1876 * When inlining a function, [:return:] statements are not emitted as | 1827 * When inlining a function, [:return:] statements are not emitted as |
1877 * [HReturn] instructions. Instead, the value of a synthetic element is | 1828 * [HReturn] instructions. Instead, the value of a synthetic element is |
1878 * updated in the [localsHandler]. This function creates such an element and | 1829 * updated in the [localsHandler]. This function creates such an element and |
1879 * stores it in the [returnLocal] field. | 1830 * stores it in the [returnLocal] field. |
1880 */ | 1831 */ |
1881 void setupStateForInlining(FunctionElement function, | 1832 void setupStateForInlining( |
1882 List<HInstruction> compiledArguments, | 1833 FunctionElement function, List<HInstruction> compiledArguments, |
1883 {InterfaceType instanceType}) { | 1834 {InterfaceType instanceType}) { |
1884 localsHandler = new LocalsHandler(this, function, instanceType); | 1835 localsHandler = new LocalsHandler(this, function, instanceType); |
1885 localsHandler.closureData = | 1836 localsHandler.closureData = compiler.closureToClassMapper |
1886 compiler.closureToClassMapper.computeClosureToClassMapping( | 1837 .computeClosureToClassMapping(function, function.node, elements); |
1887 function, function.node, elements); | |
1888 returnLocal = new SyntheticLocal("result", function); | 1838 returnLocal = new SyntheticLocal("result", function); |
1889 localsHandler.updateLocal(returnLocal, | 1839 localsHandler.updateLocal(returnLocal, graph.addConstantNull(compiler)); |
1890 graph.addConstantNull(compiler)); | |
1891 | 1840 |
1892 inTryStatement = false; // TODO(lry): why? Document. | 1841 inTryStatement = false; // TODO(lry): why? Document. |
1893 | 1842 |
1894 int argumentIndex = 0; | 1843 int argumentIndex = 0; |
1895 if (function.isInstanceMember) { | 1844 if (function.isInstanceMember) { |
1896 localsHandler.updateLocal(localsHandler.closureData.thisLocal, | 1845 localsHandler.updateLocal(localsHandler.closureData.thisLocal, |
1897 compiledArguments[argumentIndex++]); | 1846 compiledArguments[argumentIndex++]); |
1898 } | 1847 } |
1899 | 1848 |
1900 FunctionSignature signature = function.functionSignature; | 1849 FunctionSignature signature = function.functionSignature; |
1901 signature.orderedForEachParameter((ParameterElement parameter) { | 1850 signature.orderedForEachParameter((ParameterElement parameter) { |
1902 HInstruction argument = compiledArguments[argumentIndex++]; | 1851 HInstruction argument = compiledArguments[argumentIndex++]; |
1903 localsHandler.updateLocal(parameter, argument); | 1852 localsHandler.updateLocal(parameter, argument); |
1904 }); | 1853 }); |
1905 | 1854 |
1906 ClassElement enclosing = function.enclosingClass; | 1855 ClassElement enclosing = function.enclosingClass; |
1907 if ((function.isConstructor || function.isGenerativeConstructorBody) | 1856 if ((function.isConstructor || function.isGenerativeConstructorBody) && |
1908 && backend.classNeedsRti(enclosing)) { | 1857 backend.classNeedsRti(enclosing)) { |
1909 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { | 1858 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { |
1910 HInstruction argument = compiledArguments[argumentIndex++]; | 1859 HInstruction argument = compiledArguments[argumentIndex++]; |
1911 localsHandler.updateLocal( | 1860 localsHandler.updateLocal( |
1912 localsHandler.getTypeVariableAsLocal(typeVariable), argument); | 1861 localsHandler.getTypeVariableAsLocal(typeVariable), argument); |
1913 }); | 1862 }); |
1914 } | 1863 } |
1915 assert(argumentIndex == compiledArguments.length); | 1864 assert(argumentIndex == compiledArguments.length); |
1916 | 1865 |
1917 elements = function.resolvedAst.elements; | 1866 elements = function.resolvedAst.elements; |
1918 assert(elements != null); | 1867 assert(elements != null); |
(...skipping 21 matching lines...) Expand all Loading... |
1940 potentiallyCheckInlinedParameterTypes(function); | 1889 potentiallyCheckInlinedParameterTypes(function); |
1941 | 1890 |
1942 if (function.isGenerativeConstructor) { | 1891 if (function.isGenerativeConstructor) { |
1943 buildFactory(function); | 1892 buildFactory(function); |
1944 } else { | 1893 } else { |
1945 ast.FunctionExpression functionNode = function.node; | 1894 ast.FunctionExpression functionNode = function.node; |
1946 functionNode.body.accept(this); | 1895 functionNode.body.accept(this); |
1947 } | 1896 } |
1948 } | 1897 } |
1949 | 1898 |
1950 | |
1951 addInlinedInstantiation(DartType type) { | 1899 addInlinedInstantiation(DartType type) { |
1952 if (type != null) { | 1900 if (type != null) { |
1953 currentInlinedInstantiations.add(type); | 1901 currentInlinedInstantiations.add(type); |
1954 } | 1902 } |
1955 } | 1903 } |
1956 | 1904 |
1957 removeInlinedInstantiation(DartType type) { | 1905 removeInlinedInstantiation(DartType type) { |
1958 if (type != null) { | 1906 if (type != null) { |
1959 currentInlinedInstantiations.removeLast(); | 1907 currentInlinedInstantiations.removeLast(); |
1960 } | 1908 } |
(...skipping 21 matching lines...) Expand all Loading... |
1982 HInstruction argument = localsHandler.readLocal(parameter); | 1930 HInstruction argument = localsHandler.readLocal(parameter); |
1983 potentiallyCheckOrTrustType(argument, parameter.type); | 1931 potentiallyCheckOrTrustType(argument, parameter.type); |
1984 }); | 1932 }); |
1985 } | 1933 } |
1986 | 1934 |
1987 /** | 1935 /** |
1988 * Documentation wanted -- johnniwinther | 1936 * Documentation wanted -- johnniwinther |
1989 * | 1937 * |
1990 * Invariant: [constructors] must contain only implementation elements. | 1938 * Invariant: [constructors] must contain only implementation elements. |
1991 */ | 1939 */ |
1992 void inlineSuperOrRedirect(ConstructorElement callee, | 1940 void inlineSuperOrRedirect( |
1993 List<HInstruction> compiledArguments, | 1941 ConstructorElement callee, |
1994 List<FunctionElement> constructors, | 1942 List<HInstruction> compiledArguments, |
1995 Map<Element, HInstruction> fieldValues, | 1943 List<FunctionElement> constructors, |
1996 FunctionElement caller) { | 1944 Map<Element, HInstruction> fieldValues, |
| 1945 FunctionElement caller) { |
1997 callee = callee.implementation; | 1946 callee = callee.implementation; |
1998 reporter.withCurrentElement(callee, () { | 1947 reporter.withCurrentElement(callee, () { |
1999 constructors.add(callee); | 1948 constructors.add(callee); |
2000 ClassElement enclosingClass = callee.enclosingClass; | 1949 ClassElement enclosingClass = callee.enclosingClass; |
2001 if (backend.classNeedsRti(enclosingClass)) { | 1950 if (backend.classNeedsRti(enclosingClass)) { |
2002 // If [enclosingClass] needs RTI, we have to give a value to its | 1951 // If [enclosingClass] needs RTI, we have to give a value to its |
2003 // type parameters. | 1952 // type parameters. |
2004 ClassElement currentClass = caller.enclosingClass; | 1953 ClassElement currentClass = caller.enclosingClass; |
2005 // For a super constructor call, the type is the supertype of | 1954 // For a super constructor call, the type is the supertype of |
2006 // [currentClass]. For a redirecting constructor, the type is | 1955 // [currentClass]. For a redirecting constructor, the type is |
(...skipping 21 matching lines...) Expand all Loading... |
2028 localsHandler.getTypeVariableAsLocal(variable), | 1977 localsHandler.getTypeVariableAsLocal(variable), |
2029 graph.addConstantNull(compiler)); | 1978 graph.addConstantNull(compiler)); |
2030 } | 1979 } |
2031 } | 1980 } |
2032 } | 1981 } |
2033 | 1982 |
2034 // For redirecting constructors, the fields will be initialized later | 1983 // For redirecting constructors, the fields will be initialized later |
2035 // by the effective target. | 1984 // by the effective target. |
2036 if (!callee.isRedirectingGenerative) { | 1985 if (!callee.isRedirectingGenerative) { |
2037 inlinedFrom(callee, () { | 1986 inlinedFrom(callee, () { |
2038 buildFieldInitializers(callee.enclosingClass.implementation, | 1987 buildFieldInitializers( |
2039 fieldValues); | 1988 callee.enclosingClass.implementation, fieldValues); |
2040 }); | 1989 }); |
2041 } | 1990 } |
2042 | 1991 |
2043 int index = 0; | 1992 int index = 0; |
2044 FunctionSignature params = callee.functionSignature; | 1993 FunctionSignature params = callee.functionSignature; |
2045 params.orderedForEachParameter((ParameterElement parameter) { | 1994 params.orderedForEachParameter((ParameterElement parameter) { |
2046 HInstruction argument = compiledArguments[index++]; | 1995 HInstruction argument = compiledArguments[index++]; |
2047 // Because we are inlining the initializer, we must update | 1996 // Because we are inlining the initializer, we must update |
2048 // what was given as parameter. This will be used in case | 1997 // what was given as parameter. This will be used in case |
2049 // there is a parameter check expression in the initializer. | 1998 // there is a parameter check expression in the initializer. |
2050 parameters[parameter] = argument; | 1999 parameters[parameter] = argument; |
2051 localsHandler.updateLocal(parameter, argument); | 2000 localsHandler.updateLocal(parameter, argument); |
2052 // Don't forget to update the field, if the parameter is of the | 2001 // Don't forget to update the field, if the parameter is of the |
2053 // form [:this.x:]. | 2002 // form [:this.x:]. |
2054 if (parameter.isInitializingFormal) { | 2003 if (parameter.isInitializingFormal) { |
2055 InitializingFormalElement fieldParameterElement = parameter; | 2004 InitializingFormalElement fieldParameterElement = parameter; |
2056 fieldValues[fieldParameterElement.fieldElement] = argument; | 2005 fieldValues[fieldParameterElement.fieldElement] = argument; |
2057 } | 2006 } |
2058 }); | 2007 }); |
2059 | 2008 |
2060 // Build the initializers in the context of the new constructor. | 2009 // Build the initializers in the context of the new constructor. |
2061 TreeElements oldElements = elements; | 2010 TreeElements oldElements = elements; |
2062 ResolvedAst resolvedAst = callee.resolvedAst; | 2011 ResolvedAst resolvedAst = callee.resolvedAst; |
2063 elements = resolvedAst.elements; | 2012 elements = resolvedAst.elements; |
2064 ClosureClassMap oldClosureData = localsHandler.closureData; | 2013 ClosureClassMap oldClosureData = localsHandler.closureData; |
2065 ast.Node node = resolvedAst.node; | 2014 ast.Node node = resolvedAst.node; |
2066 ClosureClassMap newClosureData = | 2015 ClosureClassMap newClosureData = compiler.closureToClassMapper |
2067 compiler.closureToClassMapper.computeClosureToClassMapping( | 2016 .computeClosureToClassMapping(callee, node, elements); |
2068 callee, node, elements); | |
2069 localsHandler.closureData = newClosureData; | 2017 localsHandler.closureData = newClosureData; |
2070 localsHandler.enterScope(node, callee); | 2018 localsHandler.enterScope(node, callee); |
2071 buildInitializers(callee, constructors, fieldValues); | 2019 buildInitializers(callee, constructors, fieldValues); |
2072 localsHandler.closureData = oldClosureData; | 2020 localsHandler.closureData = oldClosureData; |
2073 elements = oldElements; | 2021 elements = oldElements; |
2074 }); | 2022 }); |
2075 } | 2023 } |
2076 | 2024 |
2077 /** | 2025 /** |
2078 * Run through the initializers and inline all field initializers. Recursively | 2026 * Run through the initializers and inline all field initializers. Recursively |
2079 * inlines super initializers. | 2027 * inlines super initializers. |
2080 * | 2028 * |
2081 * The constructors of the inlined initializers is added to [constructors] | 2029 * The constructors of the inlined initializers is added to [constructors] |
2082 * with sub constructors having a lower index than super constructors. | 2030 * with sub constructors having a lower index than super constructors. |
2083 * | 2031 * |
2084 * Invariant: The [constructor] and elements in [constructors] must all be | 2032 * Invariant: The [constructor] and elements in [constructors] must all be |
2085 * implementation elements. | 2033 * implementation elements. |
2086 */ | 2034 */ |
2087 void buildInitializers(ConstructorElement constructor, | 2035 void buildInitializers( |
2088 List<FunctionElement> constructors, | 2036 ConstructorElement constructor, |
2089 Map<Element, HInstruction> fieldValues) { | 2037 List<FunctionElement> constructors, |
| 2038 Map<Element, HInstruction> fieldValues) { |
2090 assert(invariant(constructor, constructor.isImplementation)); | 2039 assert(invariant(constructor, constructor.isImplementation)); |
2091 if (constructor.isSynthesized) { | 2040 if (constructor.isSynthesized) { |
2092 List<HInstruction> arguments = <HInstruction>[]; | 2041 List<HInstruction> arguments = <HInstruction>[]; |
2093 HInstruction compileArgument(ParameterElement parameter) { | 2042 HInstruction compileArgument(ParameterElement parameter) { |
2094 return localsHandler.readLocal(parameter); | 2043 return localsHandler.readLocal(parameter); |
2095 } | 2044 } |
2096 | 2045 |
2097 Element target = constructor.definingConstructor.implementation; | 2046 Element target = constructor.definingConstructor.implementation; |
2098 bool match = !target.isMalformed && | 2047 bool match = !target.isMalformed && |
2099 CallStructure.addForwardingElementArgumentsToList( | 2048 CallStructure.addForwardingElementArgumentsToList( |
2100 constructor, | 2049 constructor, |
2101 arguments, | 2050 arguments, |
2102 target, | 2051 target, |
2103 compileArgument, | 2052 compileArgument, |
2104 handleConstantForOptionalParameter); | 2053 handleConstantForOptionalParameter); |
2105 if (!match) { | 2054 if (!match) { |
2106 if (compiler.elementHasCompileTimeError(constructor)) { | 2055 if (compiler.elementHasCompileTimeError(constructor)) { |
2107 return; | 2056 return; |
2108 } | 2057 } |
2109 // If this fails, the selector we constructed for the call to a | 2058 // If this fails, the selector we constructed for the call to a |
2110 // forwarding constructor in a mixin application did not match the | 2059 // forwarding constructor in a mixin application did not match the |
2111 // constructor (which, for example, may happen when the libraries are | 2060 // constructor (which, for example, may happen when the libraries are |
2112 // not compatible for private names, see issue 20394). | 2061 // not compatible for private names, see issue 20394). |
2113 reporter.internalError(constructor, | 2062 reporter.internalError( |
2114 'forwarding constructor call does not match'); | 2063 constructor, 'forwarding constructor call does not match'); |
2115 } | 2064 } |
2116 inlineSuperOrRedirect( | 2065 inlineSuperOrRedirect( |
2117 target, | 2066 target, arguments, constructors, fieldValues, constructor); |
2118 arguments, | |
2119 constructors, | |
2120 fieldValues, | |
2121 constructor); | |
2122 return; | 2067 return; |
2123 } | 2068 } |
2124 ast.FunctionExpression functionNode = constructor.node; | 2069 ast.FunctionExpression functionNode = constructor.node; |
2125 | 2070 |
2126 bool foundSuperOrRedirect = false; | 2071 bool foundSuperOrRedirect = false; |
2127 if (functionNode.initializers != null) { | 2072 if (functionNode.initializers != null) { |
2128 Link<ast.Node> initializers = functionNode.initializers.nodes; | 2073 Link<ast.Node> initializers = functionNode.initializers.nodes; |
2129 for (Link<ast.Node> link = initializers; !link.isEmpty; link = link.tail)
{ | 2074 for (Link<ast.Node> link = initializers; |
| 2075 !link.isEmpty; |
| 2076 link = link.tail) { |
2130 assert(link.head is ast.Send); | 2077 assert(link.head is ast.Send); |
2131 if (link.head is !ast.SendSet) { | 2078 if (link.head is! ast.SendSet) { |
2132 // A super initializer or constructor redirection. | 2079 // A super initializer or constructor redirection. |
2133 foundSuperOrRedirect = true; | 2080 foundSuperOrRedirect = true; |
2134 ast.Send call = link.head; | 2081 ast.Send call = link.head; |
2135 assert(ast.Initializers.isSuperConstructorCall(call) || | 2082 assert(ast.Initializers.isSuperConstructorCall(call) || |
2136 ast.Initializers.isConstructorRedirect(call)); | 2083 ast.Initializers.isConstructorRedirect(call)); |
2137 FunctionElement target = elements[call].implementation; | 2084 FunctionElement target = elements[call].implementation; |
2138 CallStructure callStructure = | 2085 CallStructure callStructure = |
2139 elements.getSelector(call).callStructure; | 2086 elements.getSelector(call).callStructure; |
2140 Link<ast.Node> arguments = call.arguments; | 2087 Link<ast.Node> arguments = call.arguments; |
2141 List<HInstruction> compiledArguments; | 2088 List<HInstruction> compiledArguments; |
2142 inlinedFrom(constructor, () { | 2089 inlinedFrom(constructor, () { |
2143 compiledArguments = | 2090 compiledArguments = |
2144 makeStaticArgumentList(callStructure, arguments, target); | 2091 makeStaticArgumentList(callStructure, arguments, target); |
2145 }); | 2092 }); |
2146 inlineSuperOrRedirect(target, | 2093 inlineSuperOrRedirect(target, compiledArguments, constructors, |
2147 compiledArguments, | 2094 fieldValues, constructor); |
2148 constructors, | |
2149 fieldValues, | |
2150 constructor); | |
2151 } else { | 2095 } else { |
2152 // A field initializer. | 2096 // A field initializer. |
2153 ast.SendSet init = link.head; | 2097 ast.SendSet init = link.head; |
2154 Link<ast.Node> arguments = init.arguments; | 2098 Link<ast.Node> arguments = init.arguments; |
2155 assert(!arguments.isEmpty && arguments.tail.isEmpty); | 2099 assert(!arguments.isEmpty && arguments.tail.isEmpty); |
2156 inlinedFrom(constructor, () { | 2100 inlinedFrom(constructor, () { |
2157 visit(arguments.head); | 2101 visit(arguments.head); |
2158 }); | 2102 }); |
2159 fieldValues[elements[init]] = pop(); | 2103 fieldValues[elements[init]] = pop(); |
2160 } | 2104 } |
2161 } | 2105 } |
2162 } | 2106 } |
2163 | 2107 |
2164 if (!foundSuperOrRedirect) { | 2108 if (!foundSuperOrRedirect) { |
2165 // No super initializer found. Try to find the default constructor if | 2109 // No super initializer found. Try to find the default constructor if |
2166 // the class is not Object. | 2110 // the class is not Object. |
2167 ClassElement enclosingClass = constructor.enclosingClass; | 2111 ClassElement enclosingClass = constructor.enclosingClass; |
2168 ClassElement superClass = enclosingClass.superclass; | 2112 ClassElement superClass = enclosingClass.superclass; |
2169 if (!enclosingClass.isObject) { | 2113 if (!enclosingClass.isObject) { |
2170 assert(superClass != null); | 2114 assert(superClass != null); |
2171 assert(superClass.isResolved); | 2115 assert(superClass.isResolved); |
2172 // TODO(johnniwinther): Should we find injected constructors as well? | 2116 // TODO(johnniwinther): Should we find injected constructors as well? |
2173 FunctionElement target = superClass.lookupDefaultConstructor(); | 2117 FunctionElement target = superClass.lookupDefaultConstructor(); |
2174 if (target == null) { | 2118 if (target == null) { |
2175 reporter.internalError(superClass, | 2119 reporter.internalError( |
2176 "No default constructor available."); | 2120 superClass, "No default constructor available."); |
2177 } | 2121 } |
2178 List<HInstruction> arguments = | 2122 List<HInstruction> arguments = CallStructure.NO_ARGS.makeArgumentsList( |
2179 CallStructure.NO_ARGS.makeArgumentsList( | 2123 const Link<ast.Node>(), |
2180 const Link<ast.Node>(), | 2124 target.implementation, |
2181 target.implementation, | 2125 null, |
2182 null, | 2126 handleConstantForOptionalParameter); |
2183 handleConstantForOptionalParameter); | 2127 inlineSuperOrRedirect( |
2184 inlineSuperOrRedirect(target, | 2128 target, arguments, constructors, fieldValues, constructor); |
2185 arguments, | |
2186 constructors, | |
2187 fieldValues, | |
2188 constructor); | |
2189 } | 2129 } |
2190 } | 2130 } |
2191 } | 2131 } |
2192 | 2132 |
2193 /** | 2133 /** |
2194 * Run through the fields of [cls] and add their potential | 2134 * Run through the fields of [cls] and add their potential |
2195 * initializers. | 2135 * initializers. |
2196 * | 2136 * |
2197 * Invariant: [classElement] must be an implementation element. | 2137 * Invariant: [classElement] must be an implementation element. |
2198 */ | 2138 */ |
2199 void buildFieldInitializers(ClassElement classElement, | 2139 void buildFieldInitializers( |
2200 Map<Element, HInstruction> fieldValues) { | 2140 ClassElement classElement, Map<Element, HInstruction> fieldValues) { |
2201 assert(invariant(classElement, classElement.isImplementation)); | 2141 assert(invariant(classElement, classElement.isImplementation)); |
2202 classElement.forEachInstanceField( | 2142 classElement.forEachInstanceField( |
2203 (ClassElement enclosingClass, VariableElement member) { | 2143 (ClassElement enclosingClass, VariableElement member) { |
2204 if (compiler.elementHasCompileTimeError(member)) return; | 2144 if (compiler.elementHasCompileTimeError(member)) return; |
2205 reporter.withCurrentElement(member, () { | 2145 reporter.withCurrentElement(member, () { |
2206 TreeElements definitions = member.treeElements; | 2146 TreeElements definitions = member.treeElements; |
2207 ast.Node node = member.node; | 2147 ast.Node node = member.node; |
2208 ast.Expression initializer = member.initializer; | 2148 ast.Expression initializer = member.initializer; |
2209 if (initializer == null) { | 2149 if (initializer == null) { |
2210 // Unassigned fields of native classes are not initialized to | 2150 // Unassigned fields of native classes are not initialized to |
2211 // prevent overwriting pre-initialized native properties. | 2151 // prevent overwriting pre-initialized native properties. |
2212 if (!backend.isNativeOrExtendsNative(classElement)) { | 2152 if (!backend.isNativeOrExtendsNative(classElement)) { |
2213 fieldValues[member] = graph.addConstantNull(compiler); | 2153 fieldValues[member] = graph.addConstantNull(compiler); |
2214 } | 2154 } |
2215 } else { | 2155 } else { |
2216 ast.Node right = initializer; | 2156 ast.Node right = initializer; |
2217 TreeElements savedElements = elements; | 2157 TreeElements savedElements = elements; |
2218 elements = definitions; | 2158 elements = definitions; |
2219 // In case the field initializer uses closures, run the | 2159 // In case the field initializer uses closures, run the |
2220 // closure to class mapper. | 2160 // closure to class mapper. |
2221 compiler.closureToClassMapper.computeClosureToClassMapping( | 2161 compiler.closureToClassMapper |
2222 member, node, elements); | 2162 .computeClosureToClassMapping(member, node, elements); |
2223 inlinedFrom(member, () => right.accept(this)); | 2163 inlinedFrom(member, () => right.accept(this)); |
2224 elements = savedElements; | 2164 elements = savedElements; |
2225 fieldValues[member] = pop(); | 2165 fieldValues[member] = pop(); |
2226 } | 2166 } |
2227 }); | 2167 }); |
2228 }); | 2168 }); |
2229 } | 2169 } |
2230 | 2170 |
2231 /** | 2171 /** |
2232 * Build the factory function corresponding to the constructor | 2172 * Build the factory function corresponding to the constructor |
2233 * [functionElement]: | 2173 * [functionElement]: |
2234 * - Initialize fields with the values of the field initializers of the | 2174 * - Initialize fields with the values of the field initializers of the |
2235 * current constructor and super constructors or constructors redirected | 2175 * current constructor and super constructors or constructors redirected |
2236 * to, starting from the current constructor. | 2176 * to, starting from the current constructor. |
2237 * - Call the constructor bodies, starting from the constructor(s) in the | 2177 * - Call the constructor bodies, starting from the constructor(s) in the |
2238 * super class(es). | 2178 * super class(es). |
2239 */ | 2179 */ |
2240 HGraph buildFactory(ConstructorElement functionElement) { | 2180 HGraph buildFactory(ConstructorElement functionElement) { |
2241 functionElement = functionElement.implementation; | 2181 functionElement = functionElement.implementation; |
2242 ClassElement classElement = | 2182 ClassElement classElement = functionElement.enclosingClass.implementation; |
2243 functionElement.enclosingClass.implementation; | |
2244 bool isNativeUpgradeFactory = | 2183 bool isNativeUpgradeFactory = |
2245 backend.isNativeOrExtendsNative(classElement) | 2184 backend.isNativeOrExtendsNative(classElement) && |
2246 && !backend.isJsInterop(classElement); | 2185 !backend.isJsInterop(classElement); |
2247 ast.FunctionExpression function = functionElement.node; | 2186 ast.FunctionExpression function = functionElement.node; |
2248 // Note that constructors (like any other static function) do not need | 2187 // Note that constructors (like any other static function) do not need |
2249 // to deal with optional arguments. It is the callers job to provide all | 2188 // to deal with optional arguments. It is the callers job to provide all |
2250 // arguments as if they were positional. | 2189 // arguments as if they were positional. |
2251 | 2190 |
2252 if (inliningStack.isEmpty) { | 2191 if (inliningStack.isEmpty) { |
2253 // The initializer list could contain closures. | 2192 // The initializer list could contain closures. |
2254 openFunction(functionElement, function); | 2193 openFunction(functionElement, function); |
2255 } | 2194 } |
2256 | 2195 |
2257 Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); | 2196 Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); |
2258 | 2197 |
2259 // Compile the possible initialization code for local fields and | 2198 // Compile the possible initialization code for local fields and |
2260 // super fields, unless this is a redirecting constructor, in which case | 2199 // super fields, unless this is a redirecting constructor, in which case |
2261 // the effective target will initialize these. | 2200 // the effective target will initialize these. |
2262 if (!functionElement.isRedirectingGenerative) { | 2201 if (!functionElement.isRedirectingGenerative) { |
2263 buildFieldInitializers(classElement, fieldValues); | 2202 buildFieldInitializers(classElement, fieldValues); |
2264 } | 2203 } |
2265 | 2204 |
2266 // Compile field-parameters such as [:this.x:]. | 2205 // Compile field-parameters such as [:this.x:]. |
2267 FunctionSignature params = functionElement.functionSignature; | 2206 FunctionSignature params = functionElement.functionSignature; |
2268 params.orderedForEachParameter((ParameterElement parameter) { | 2207 params.orderedForEachParameter((ParameterElement parameter) { |
2269 if (parameter.isInitializingFormal) { | 2208 if (parameter.isInitializingFormal) { |
2270 // If the [element] is a field-parameter then | 2209 // If the [element] is a field-parameter then |
2271 // initialize the field element with its value. | 2210 // initialize the field element with its value. |
2272 InitializingFormalElement fieldParameter = parameter; | 2211 InitializingFormalElement fieldParameter = parameter; |
2273 HInstruction parameterValue = | 2212 HInstruction parameterValue = localsHandler.readLocal(fieldParameter); |
2274 localsHandler.readLocal(fieldParameter); | |
2275 fieldValues[fieldParameter.fieldElement] = parameterValue; | 2213 fieldValues[fieldParameter.fieldElement] = parameterValue; |
2276 } | 2214 } |
2277 }); | 2215 }); |
2278 | 2216 |
2279 // Analyze the constructor and all referenced constructors and collect | 2217 // Analyze the constructor and all referenced constructors and collect |
2280 // initializers and constructor bodies. | 2218 // initializers and constructor bodies. |
2281 List<FunctionElement> constructors = <FunctionElement>[functionElement]; | 2219 List<FunctionElement> constructors = <FunctionElement>[functionElement]; |
2282 buildInitializers(functionElement, constructors, fieldValues); | 2220 buildInitializers(functionElement, constructors, fieldValues); |
2283 | 2221 |
2284 // Call the JavaScript constructor with the fields as argument. | 2222 // Call the JavaScript constructor with the fields as argument. |
2285 List<HInstruction> constructorArguments = <HInstruction>[]; | 2223 List<HInstruction> constructorArguments = <HInstruction>[]; |
2286 List<Element> fields = <Element>[]; | 2224 List<Element> fields = <Element>[]; |
2287 | 2225 |
2288 classElement.forEachInstanceField( | 2226 classElement.forEachInstanceField( |
2289 (ClassElement enclosingClass, VariableElement member) { | 2227 (ClassElement enclosingClass, VariableElement member) { |
2290 HInstruction value = fieldValues[member]; | 2228 HInstruction value = fieldValues[member]; |
2291 if (value == null) { | 2229 if (value == null) { |
2292 // Uninitialized native fields are pre-initialized by the native | 2230 // Uninitialized native fields are pre-initialized by the native |
2293 // implementation. | 2231 // implementation. |
2294 assert(invariant( | 2232 assert(invariant( |
2295 member, isNativeUpgradeFactory || compiler.compilationFailed)); | 2233 member, isNativeUpgradeFactory || compiler.compilationFailed)); |
2296 } else { | 2234 } else { |
2297 fields.add(member); | 2235 fields.add(member); |
2298 DartType type = localsHandler.substInContext(member.type); | 2236 DartType type = localsHandler.substInContext(member.type); |
2299 constructorArguments.add(potentiallyCheckOrTrustType(value, type)); | 2237 constructorArguments.add(potentiallyCheckOrTrustType(value, type)); |
2300 } | 2238 } |
2301 }, | 2239 }, includeSuperAndInjectedMembers: true); |
2302 includeSuperAndInjectedMembers: true); | |
2303 | 2240 |
2304 InterfaceType type = classElement.thisType; | 2241 InterfaceType type = classElement.thisType; |
2305 TypeMask ssaType = | 2242 TypeMask ssaType = |
2306 new TypeMask.nonNullExact(classElement.declaration, compiler.world); | 2243 new TypeMask.nonNullExact(classElement.declaration, compiler.world); |
2307 List<DartType> instantiatedTypes; | 2244 List<DartType> instantiatedTypes; |
2308 addInlinedInstantiation(type); | 2245 addInlinedInstantiation(type); |
2309 if (!currentInlinedInstantiations.isEmpty) { | 2246 if (!currentInlinedInstantiations.isEmpty) { |
2310 instantiatedTypes = new List<DartType>.from(currentInlinedInstantiations); | 2247 instantiatedTypes = new List<DartType>.from(currentInlinedInstantiations); |
2311 } | 2248 } |
2312 | 2249 |
2313 HInstruction newObject; | 2250 HInstruction newObject; |
2314 if (!isNativeUpgradeFactory) { | 2251 if (!isNativeUpgradeFactory) { |
2315 newObject = new HForeignNew(classElement, | 2252 newObject = new HForeignNew( |
2316 ssaType, | 2253 classElement, ssaType, constructorArguments, instantiatedTypes); |
2317 constructorArguments, | |
2318 instantiatedTypes); | |
2319 if (function != null) { | 2254 if (function != null) { |
2320 // TODO(johnniwinther): Provide source information for creation | 2255 // TODO(johnniwinther): Provide source information for creation |
2321 // through synthetic constructors. | 2256 // through synthetic constructors. |
2322 newObject.sourceInformation = | 2257 newObject.sourceInformation = |
2323 sourceInformationBuilder.buildCreate(function); | 2258 sourceInformationBuilder.buildCreate(function); |
2324 } | 2259 } |
2325 add(newObject); | 2260 add(newObject); |
2326 } else { | 2261 } else { |
2327 // Bulk assign to the initialized fields. | 2262 // Bulk assign to the initialized fields. |
2328 newObject = graph.explicitReceiverParameter; | 2263 newObject = graph.explicitReceiverParameter; |
2329 // Null guard ensures an error if we are being called from an explicit | 2264 // Null guard ensures an error if we are being called from an explicit |
2330 // 'new' of the constructor instead of via an upgrade. It is optimized out | 2265 // 'new' of the constructor instead of via an upgrade. It is optimized out |
2331 // if there are field initializers. | 2266 // if there are field initializers. |
2332 add(new HFieldGet( | 2267 add(new HFieldGet(null, newObject, backend.dynamicType, |
2333 null, newObject, backend.dynamicType, isAssignable: false)); | 2268 isAssignable: false)); |
2334 for (int i = 0; i < fields.length; i++) { | 2269 for (int i = 0; i < fields.length; i++) { |
2335 add(new HFieldSet(fields[i], newObject, constructorArguments[i])); | 2270 add(new HFieldSet(fields[i], newObject, constructorArguments[i])); |
2336 } | 2271 } |
2337 } | 2272 } |
2338 removeInlinedInstantiation(type); | 2273 removeInlinedInstantiation(type); |
2339 // Create the runtime type information, if needed. | 2274 // Create the runtime type information, if needed. |
2340 if (backend.classNeedsRti(classElement)) { | 2275 if (backend.classNeedsRti(classElement)) { |
2341 // Read the values of the type arguments and create a list to set on the | 2276 // Read the values of the type arguments and create a list to set on the |
2342 // newly create object. We can identify the case where the new list | 2277 // newly create object. We can identify the case where the new list |
2343 // would be of the form: | 2278 // would be of the form: |
2344 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] | 2279 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] |
2345 // and k is the number of type arguments of this. If this is the case, | 2280 // and k is the number of type arguments of this. If this is the case, |
2346 // we can simply copy the list from this. | 2281 // we can simply copy the list from this. |
2347 | 2282 |
2348 // These locals are modified by [isIndexedTypeArgumentGet]. | 2283 // These locals are modified by [isIndexedTypeArgumentGet]. |
2349 HThis source; // The source of the type arguments. | 2284 HThis source; // The source of the type arguments. |
2350 bool allIndexed = true; | 2285 bool allIndexed = true; |
2351 int expectedIndex = 0; | 2286 int expectedIndex = 0; |
2352 ClassElement contextClass; // The class of `this`. | 2287 ClassElement contextClass; // The class of `this`. |
2353 int remainingTypeVariables; // The number of 'remaining type variables' | 2288 int remainingTypeVariables; // The number of 'remaining type variables' |
2354 // of `this`. | 2289 // of `this`. |
2355 | 2290 |
2356 /// Helper to identify instructions that read a type variable without | 2291 /// Helper to identify instructions that read a type variable without |
2357 /// substitution (that is, directly use the index). These instructions | 2292 /// substitution (that is, directly use the index). These instructions |
2358 /// are of the form: | 2293 /// are of the form: |
2359 /// HInvokeStatic(getTypeArgumentByIndex, this, index) | 2294 /// HInvokeStatic(getTypeArgumentByIndex, this, index) |
2360 /// | 2295 /// |
2361 /// Return `true` if [instruction] is of that form and the index is the | 2296 /// Return `true` if [instruction] is of that form and the index is the |
2362 /// next index in the sequence (held in [expectedIndex]). | 2297 /// next index in the sequence (held in [expectedIndex]). |
2363 bool isIndexedTypeArgumentGet(HInstruction instruction) { | 2298 bool isIndexedTypeArgumentGet(HInstruction instruction) { |
2364 if (instruction is! HInvokeStatic) return false; | 2299 if (instruction is! HInvokeStatic) return false; |
(...skipping 21 matching lines...) Expand all Loading... |
2386 // a copy. Otherwise remove one argument. | 2321 // a copy. Otherwise remove one argument. |
2387 if (remainingTypeVariables == 0) return false; | 2322 if (remainingTypeVariables == 0) return false; |
2388 remainingTypeVariables--; | 2323 remainingTypeVariables--; |
2389 // Check that the index is the one we expect. | 2324 // Check that the index is the one we expect. |
2390 IntConstantValue constant = index.constant; | 2325 IntConstantValue constant = index.constant; |
2391 return constant.primitiveValue == expectedIndex++; | 2326 return constant.primitiveValue == expectedIndex++; |
2392 } | 2327 } |
2393 | 2328 |
2394 List<HInstruction> typeArguments = <HInstruction>[]; | 2329 List<HInstruction> typeArguments = <HInstruction>[]; |
2395 classElement.typeVariables.forEach((TypeVariableType typeVariable) { | 2330 classElement.typeVariables.forEach((TypeVariableType typeVariable) { |
2396 HInstruction argument = localsHandler.readLocal( | 2331 HInstruction argument = localsHandler |
2397 localsHandler.getTypeVariableAsLocal(typeVariable)); | 2332 .readLocal(localsHandler.getTypeVariableAsLocal(typeVariable)); |
2398 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { | 2333 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { |
2399 allIndexed = false; | 2334 allIndexed = false; |
2400 } | 2335 } |
2401 typeArguments.add(argument); | 2336 typeArguments.add(argument); |
2402 }); | 2337 }); |
2403 | 2338 |
2404 if (source != null && allIndexed && remainingTypeVariables == 0) { | 2339 if (source != null && allIndexed && remainingTypeVariables == 0) { |
2405 copyRuntimeTypeInfo(source, newObject); | 2340 copyRuntimeTypeInfo(source, newObject); |
2406 } else { | 2341 } else { |
2407 newObject = | 2342 newObject = |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2451 } | 2386 } |
2452 | 2387 |
2453 // Type variables arguments must come after the box (if there is one). | 2388 // Type variables arguments must come after the box (if there is one). |
2454 ClassElement currentClass = constructor.enclosingClass; | 2389 ClassElement currentClass = constructor.enclosingClass; |
2455 if (backend.classNeedsRti(currentClass)) { | 2390 if (backend.classNeedsRti(currentClass)) { |
2456 // If [currentClass] needs RTI, we add the type variables as | 2391 // If [currentClass] needs RTI, we add the type variables as |
2457 // parameters of the generative constructor body. | 2392 // parameters of the generative constructor body. |
2458 currentClass.typeVariables.forEach((TypeVariableType argument) { | 2393 currentClass.typeVariables.forEach((TypeVariableType argument) { |
2459 // TODO(johnniwinther): Substitute [argument] with | 2394 // TODO(johnniwinther): Substitute [argument] with |
2460 // `localsHandler.substInContext(argument)`. | 2395 // `localsHandler.substInContext(argument)`. |
2461 bodyCallInputs.add(localsHandler.readLocal( | 2396 bodyCallInputs.add(localsHandler |
2462 localsHandler.getTypeVariableAsLocal(argument))); | 2397 .readLocal(localsHandler.getTypeVariableAsLocal(argument))); |
2463 }); | 2398 }); |
2464 } | 2399 } |
2465 | 2400 |
2466 if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining. | 2401 if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining. |
2467 tryInlineMethod(body, null, null, bodyCallInputs, function)) { | 2402 tryInlineMethod(body, null, null, bodyCallInputs, function)) { |
2468 pop(); | 2403 pop(); |
2469 } else { | 2404 } else { |
2470 HInvokeConstructorBody invoke = new HInvokeConstructorBody( | 2405 HInvokeConstructorBody invoke = new HInvokeConstructorBody( |
2471 body.declaration, bodyCallInputs, backend.nonNullType); | 2406 body.declaration, bodyCallInputs, backend.nonNullType); |
2472 invoke.sideEffects = | 2407 invoke.sideEffects = |
(...skipping 23 matching lines...) Expand all Loading... |
2496 | 2431 |
2497 localsHandler.startFunction(element, node); | 2432 localsHandler.startFunction(element, node); |
2498 close(new HGoto()).addSuccessor(block); | 2433 close(new HGoto()).addSuccessor(block); |
2499 | 2434 |
2500 open(block); | 2435 open(block); |
2501 | 2436 |
2502 // Add the type parameters of the class as parameters of this method. This | 2437 // Add the type parameters of the class as parameters of this method. This |
2503 // must be done before adding the normal parameters, because their types | 2438 // must be done before adding the normal parameters, because their types |
2504 // may contain references to type variables. | 2439 // may contain references to type variables. |
2505 var enclosing = element.enclosingElement; | 2440 var enclosing = element.enclosingElement; |
2506 if ((element.isConstructor || element.isGenerativeConstructorBody) | 2441 if ((element.isConstructor || element.isGenerativeConstructorBody) && |
2507 && backend.classNeedsRti(enclosing)) { | 2442 backend.classNeedsRti(enclosing)) { |
2508 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { | 2443 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { |
2509 HParameterValue param = addParameter( | 2444 HParameterValue param = |
2510 typeVariable.element, backend.nonNullType); | 2445 addParameter(typeVariable.element, backend.nonNullType); |
2511 localsHandler.directLocals[ | 2446 localsHandler.directLocals[ |
2512 localsHandler.getTypeVariableAsLocal(typeVariable)] = param; | 2447 localsHandler.getTypeVariableAsLocal(typeVariable)] = param; |
2513 }); | 2448 }); |
2514 } | 2449 } |
2515 | 2450 |
2516 if (element is FunctionElement) { | 2451 if (element is FunctionElement) { |
2517 FunctionElement functionElement = element; | 2452 FunctionElement functionElement = element; |
2518 FunctionSignature signature = functionElement.functionSignature; | 2453 FunctionSignature signature = functionElement.functionSignature; |
2519 | 2454 |
2520 // Put the type checks in the first successor of the entry, | 2455 // Put the type checks in the first successor of the entry, |
2521 // because that is where the type guards will also be inserted. | 2456 // because that is where the type guards will also be inserted. |
2522 // This way we ensure that a type guard will dominate the type | 2457 // This way we ensure that a type guard will dominate the type |
2523 // check. | 2458 // check. |
2524 ClosureScope scopeData = | 2459 ClosureScope scopeData = localsHandler.closureData.capturingScopes[node]; |
2525 localsHandler.closureData.capturingScopes[node]; | |
2526 signature.orderedForEachParameter((ParameterElement parameterElement) { | 2460 signature.orderedForEachParameter((ParameterElement parameterElement) { |
2527 if (element.isGenerativeConstructorBody) { | 2461 if (element.isGenerativeConstructorBody) { |
2528 if (scopeData != null && | 2462 if (scopeData != null && |
2529 scopeData.isCapturedVariable(parameterElement)) { | 2463 scopeData.isCapturedVariable(parameterElement)) { |
2530 // The parameter will be a field in the box passed as the | 2464 // The parameter will be a field in the box passed as the |
2531 // last parameter. So no need to have it. | 2465 // last parameter. So no need to have it. |
2532 return; | 2466 return; |
2533 } | 2467 } |
2534 } | 2468 } |
2535 HInstruction newParameter = | 2469 HInstruction newParameter = |
(...skipping 26 matching lines...) Expand all Loading... |
2562 | 2496 |
2563 insertTraceCall(element); | 2497 insertTraceCall(element); |
2564 insertCoverageCall(element); | 2498 insertCoverageCall(element); |
2565 } | 2499 } |
2566 | 2500 |
2567 insertTraceCall(Element element) { | 2501 insertTraceCall(Element element) { |
2568 if (JavaScriptBackend.TRACE_METHOD == 'console') { | 2502 if (JavaScriptBackend.TRACE_METHOD == 'console') { |
2569 if (element == backend.traceHelper) return; | 2503 if (element == backend.traceHelper) return; |
2570 n(e) => e == null ? '' : e.name; | 2504 n(e) => e == null ? '' : e.name; |
2571 String name = "${n(element.library)}:${n(element.enclosingClass)}." | 2505 String name = "${n(element.library)}:${n(element.enclosingClass)}." |
2572 "${n(element)}"; | 2506 "${n(element)}"; |
2573 HConstant nameConstant = addConstantString(name); | 2507 HConstant nameConstant = addConstantString(name); |
2574 add(new HInvokeStatic(backend.traceHelper, | 2508 add(new HInvokeStatic(backend.traceHelper, <HInstruction>[nameConstant], |
2575 <HInstruction>[nameConstant], | 2509 backend.dynamicType)); |
2576 backend.dynamicType)); | |
2577 } | 2510 } |
2578 } | 2511 } |
2579 | 2512 |
2580 insertCoverageCall(Element element) { | 2513 insertCoverageCall(Element element) { |
2581 if (JavaScriptBackend.TRACE_METHOD == 'post') { | 2514 if (JavaScriptBackend.TRACE_METHOD == 'post') { |
2582 if (element == backend.traceHelper) return; | 2515 if (element == backend.traceHelper) return; |
2583 // TODO(sigmund): create a better uuid for elements. | 2516 // TODO(sigmund): create a better uuid for elements. |
2584 HConstant idConstant = graph.addConstantInt(element.hashCode, compiler); | 2517 HConstant idConstant = graph.addConstantInt(element.hashCode, compiler); |
2585 HConstant nameConstant = addConstantString(element.name); | 2518 HConstant nameConstant = addConstantString(element.name); |
2586 add(new HInvokeStatic(backend.traceHelper, | 2519 add(new HInvokeStatic(backend.traceHelper, |
2587 <HInstruction>[idConstant, nameConstant], | 2520 <HInstruction>[idConstant, nameConstant], backend.dynamicType)); |
2588 backend.dynamicType)); | |
2589 } | 2521 } |
2590 } | 2522 } |
2591 | 2523 |
2592 /// Check that [type] is valid in the context of `localsHandler.contextClass`. | 2524 /// Check that [type] is valid in the context of `localsHandler.contextClass`. |
2593 /// This should only be called in assertions. | 2525 /// This should only be called in assertions. |
2594 bool assertTypeInContext(DartType type, [Spannable spannable]) { | 2526 bool assertTypeInContext(DartType type, [Spannable spannable]) { |
2595 return invariant(spannable == null ? CURRENT_ELEMENT_SPANNABLE : spannable, | 2527 return invariant(spannable == null ? CURRENT_ELEMENT_SPANNABLE : spannable, |
2596 () { | 2528 () { |
2597 ClassElement contextClass = Types.getClassContext(type); | 2529 ClassElement contextClass = Types.getClassContext(type); |
2598 return contextClass == null || | 2530 return contextClass == null || contextClass == localsHandler.contextClass; |
2599 contextClass == localsHandler.contextClass; | 2531 }, |
2600 }, | |
2601 message: "Type '$type' is not valid context of " | 2532 message: "Type '$type' is not valid context of " |
2602 "${localsHandler.contextClass}."); | 2533 "${localsHandler.contextClass}."); |
2603 } | 2534 } |
2604 | 2535 |
2605 /// Build a [HTypeConversion] for convertion [original] to type [type]. | 2536 /// Build a [HTypeConversion] for convertion [original] to type [type]. |
2606 /// | 2537 /// |
2607 /// Invariant: [type] must be valid in the context. | 2538 /// Invariant: [type] must be valid in the context. |
2608 /// See [LocalsHandler.substInContext]. | 2539 /// See [LocalsHandler.substInContext]. |
2609 HInstruction buildTypeConversion(HInstruction original, | 2540 HInstruction buildTypeConversion( |
2610 DartType type, | 2541 HInstruction original, DartType type, int kind) { |
2611 int kind) { | |
2612 if (type == null) return original; | 2542 if (type == null) return original; |
2613 type = type.unaliased; | 2543 type = type.unaliased; |
2614 assert(assertTypeInContext(type, original)); | 2544 assert(assertTypeInContext(type, original)); |
2615 if (type.isInterfaceType && !type.treatAsRaw) { | 2545 if (type.isInterfaceType && !type.treatAsRaw) { |
2616 TypeMask subtype = new TypeMask.subtype(type.element, compiler.world); | 2546 TypeMask subtype = new TypeMask.subtype(type.element, compiler.world); |
2617 HInstruction representations = buildTypeArgumentRepresentations(type); | 2547 HInstruction representations = buildTypeArgumentRepresentations(type); |
2618 add(representations); | 2548 add(representations); |
2619 return new HTypeConversion.withTypeRepresentation(type, kind, subtype, | 2549 return new HTypeConversion.withTypeRepresentation( |
2620 original, representations); | 2550 type, kind, subtype, original, representations); |
2621 } else if (type.isTypeVariable) { | 2551 } else if (type.isTypeVariable) { |
2622 TypeMask subtype = original.instructionType; | 2552 TypeMask subtype = original.instructionType; |
2623 HInstruction typeVariable = addTypeVariableReference(type); | 2553 HInstruction typeVariable = addTypeVariableReference(type); |
2624 return new HTypeConversion.withTypeRepresentation(type, kind, subtype, | 2554 return new HTypeConversion.withTypeRepresentation( |
2625 original, typeVariable); | 2555 type, kind, subtype, original, typeVariable); |
2626 } else if (type.isFunctionType) { | 2556 } else if (type.isFunctionType) { |
2627 String name = kind == HTypeConversion.CAST_TYPE_CHECK | 2557 String name = |
2628 ? '_asCheck' : '_assertCheck'; | 2558 kind == HTypeConversion.CAST_TYPE_CHECK ? '_asCheck' : '_assertCheck'; |
2629 | 2559 |
2630 List<HInstruction> arguments = | 2560 List<HInstruction> arguments = <HInstruction>[ |
2631 <HInstruction>[buildFunctionType(type), original]; | 2561 buildFunctionType(type), |
| 2562 original |
| 2563 ]; |
2632 pushInvokeDynamic( | 2564 pushInvokeDynamic( |
2633 null, | 2565 null, |
2634 new Selector.call( | 2566 new Selector.call( |
2635 new Name(name, helpers.jsHelperLibrary), CallStructure.ONE_ARG), | 2567 new Name(name, helpers.jsHelperLibrary), CallStructure.ONE_ARG), |
2636 null, | 2568 null, |
2637 arguments); | 2569 arguments); |
2638 | 2570 |
2639 return new HTypeConversion(type, kind, original.instructionType, pop()); | 2571 return new HTypeConversion(type, kind, original.instructionType, pop()); |
2640 } else { | 2572 } else { |
2641 return original.convertType(compiler, type, kind); | 2573 return original.convertType(compiler, type, kind); |
(...skipping 17 matching lines...) Expand all Loading... |
2659 HInstruction _checkType(HInstruction original, DartType type, int kind) { | 2591 HInstruction _checkType(HInstruction original, DartType type, int kind) { |
2660 assert(compiler.options.enableTypeAssertions); | 2592 assert(compiler.options.enableTypeAssertions); |
2661 assert(type != null); | 2593 assert(type != null); |
2662 type = localsHandler.substInContext(type); | 2594 type = localsHandler.substInContext(type); |
2663 HInstruction other = buildTypeConversion(original, type, kind); | 2595 HInstruction other = buildTypeConversion(original, type, kind); |
2664 registry?.registerTypeUse(new TypeUse.isCheck(type)); | 2596 registry?.registerTypeUse(new TypeUse.isCheck(type)); |
2665 return other; | 2597 return other; |
2666 } | 2598 } |
2667 | 2599 |
2668 HInstruction potentiallyCheckOrTrustType(HInstruction original, DartType type, | 2600 HInstruction potentiallyCheckOrTrustType(HInstruction original, DartType type, |
2669 { int kind: HTypeConversion.CHECKED_MODE_CHECK }) { | 2601 {int kind: HTypeConversion.CHECKED_MODE_CHECK}) { |
2670 if (type == null) return original; | 2602 if (type == null) return original; |
2671 HInstruction checkedOrTrusted = original; | 2603 HInstruction checkedOrTrusted = original; |
2672 if (compiler.options.trustTypeAnnotations) { | 2604 if (compiler.options.trustTypeAnnotations) { |
2673 checkedOrTrusted = _trustType(original, type); | 2605 checkedOrTrusted = _trustType(original, type); |
2674 } else if (compiler.options.enableTypeAssertions) { | 2606 } else if (compiler.options.enableTypeAssertions) { |
2675 checkedOrTrusted = _checkType(original, type, kind); | 2607 checkedOrTrusted = _checkType(original, type, kind); |
2676 } | 2608 } |
2677 if (checkedOrTrusted == original) return original; | 2609 if (checkedOrTrusted == original) return original; |
2678 add(checkedOrTrusted); | 2610 add(checkedOrTrusted); |
2679 return checkedOrTrusted; | 2611 return checkedOrTrusted; |
2680 } | 2612 } |
2681 | 2613 |
2682 void assertIsSubtype(ast.Node node, DartType subtype, DartType supertype, | 2614 void assertIsSubtype( |
2683 String message) { | 2615 ast.Node node, DartType subtype, DartType supertype, String message) { |
2684 HInstruction subtypeInstruction = | 2616 HInstruction subtypeInstruction = |
2685 analyzeTypeArgument(localsHandler.substInContext(subtype)); | 2617 analyzeTypeArgument(localsHandler.substInContext(subtype)); |
2686 HInstruction supertypeInstruction = | 2618 HInstruction supertypeInstruction = |
2687 analyzeTypeArgument(localsHandler.substInContext(supertype)); | 2619 analyzeTypeArgument(localsHandler.substInContext(supertype)); |
2688 HInstruction messageInstruction = | 2620 HInstruction messageInstruction = |
2689 graph.addConstantString(new ast.DartString.literal(message), compiler); | 2621 graph.addConstantString(new ast.DartString.literal(message), compiler); |
2690 Element element = helpers.assertIsSubtype; | 2622 Element element = helpers.assertIsSubtype; |
2691 var inputs = <HInstruction>[subtypeInstruction, supertypeInstruction, | 2623 var inputs = <HInstruction>[ |
2692 messageInstruction]; | 2624 subtypeInstruction, |
2693 HInstruction assertIsSubtype = new HInvokeStatic( | 2625 supertypeInstruction, |
2694 element, inputs, subtypeInstruction.instructionType); | 2626 messageInstruction |
| 2627 ]; |
| 2628 HInstruction assertIsSubtype = |
| 2629 new HInvokeStatic(element, inputs, subtypeInstruction.instructionType); |
2695 registry?.registerTypeVariableBoundsSubtypeCheck(subtype, supertype); | 2630 registry?.registerTypeVariableBoundsSubtypeCheck(subtype, supertype); |
2696 add(assertIsSubtype); | 2631 add(assertIsSubtype); |
2697 } | 2632 } |
2698 | 2633 |
2699 HGraph closeFunction() { | 2634 HGraph closeFunction() { |
2700 // TODO(kasperl): Make this goto an implicit return. | 2635 // TODO(kasperl): Make this goto an implicit return. |
2701 if (!isAborted()) closeAndGotoExit(new HGoto()); | 2636 if (!isAborted()) closeAndGotoExit(new HGoto()); |
2702 graph.finalize(); | 2637 graph.finalize(); |
2703 return graph; | 2638 return graph; |
2704 } | 2639 } |
(...skipping 11 matching lines...) Expand all Loading... |
2716 return stack.removeLast(); | 2651 return stack.removeLast(); |
2717 } | 2652 } |
2718 | 2653 |
2719 void dup() { | 2654 void dup() { |
2720 stack.add(stack.last); | 2655 stack.add(stack.last); |
2721 } | 2656 } |
2722 | 2657 |
2723 HInstruction popBoolified() { | 2658 HInstruction popBoolified() { |
2724 HInstruction value = pop(); | 2659 HInstruction value = pop(); |
2725 if (_checkOrTrustTypes) { | 2660 if (_checkOrTrustTypes) { |
2726 return potentiallyCheckOrTrustType( | 2661 return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType, |
2727 value, | |
2728 compiler.coreTypes.boolType, | |
2729 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); | 2662 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); |
2730 } | 2663 } |
2731 HInstruction result = new HBoolify(value, backend.boolType); | 2664 HInstruction result = new HBoolify(value, backend.boolType); |
2732 add(result); | 2665 add(result); |
2733 return result; | 2666 return result; |
2734 } | 2667 } |
2735 | 2668 |
2736 HInstruction attachPosition(HInstruction target, ast.Node node) { | 2669 HInstruction attachPosition(HInstruction target, ast.Node node) { |
2737 if (node != null) { | 2670 if (node != null) { |
2738 target.sourceInformation = sourceInformationBuilder.buildGeneric(node); | 2671 target.sourceInformation = sourceInformationBuilder.buildGeneric(node); |
(...skipping 30 matching lines...) Expand all Loading... |
2769 // | 2702 // |
2770 void buildCondition() { | 2703 void buildCondition() { |
2771 visit(node.condition); | 2704 visit(node.condition); |
2772 pushInvokeStatic(node, helpers.assertTest, [pop()]); | 2705 pushInvokeStatic(node, helpers.assertTest, [pop()]); |
2773 } | 2706 } |
2774 void fail() { | 2707 void fail() { |
2775 visit(node.message); | 2708 visit(node.message); |
2776 pushInvokeStatic(node, helpers.assertThrow, [pop()]); | 2709 pushInvokeStatic(node, helpers.assertThrow, [pop()]); |
2777 pop(); | 2710 pop(); |
2778 } | 2711 } |
2779 handleIf(node, | 2712 handleIf(node, visitCondition: buildCondition, visitThen: fail); |
2780 visitCondition: buildCondition, | |
2781 visitThen: fail); | |
2782 } | 2713 } |
2783 | 2714 |
2784 visitBlock(ast.Block node) { | 2715 visitBlock(ast.Block node) { |
2785 assert(!isAborted()); | 2716 assert(!isAborted()); |
2786 if (!isReachable) return; // This can only happen when inlining. | 2717 if (!isReachable) return; // This can only happen when inlining. |
2787 for (Link<ast.Node> link = node.statements.nodes; | 2718 for (Link<ast.Node> link = node.statements.nodes; |
2788 !link.isEmpty; | 2719 !link.isEmpty; |
2789 link = link.tail) { | 2720 link = link.tail) { |
2790 visit(link.head); | 2721 visit(link.head); |
2791 if (!isReachable) { | 2722 if (!isReachable) { |
2792 // The block has been aborted by a return or a throw. | 2723 // The block has been aborted by a return or a throw. |
2793 if (!stack.isEmpty) { | 2724 if (!stack.isEmpty) { |
2794 reporter.internalError(node, 'Non-empty instruction stack.'); | 2725 reporter.internalError(node, 'Non-empty instruction stack.'); |
2795 } | 2726 } |
2796 return; | 2727 return; |
2797 } | 2728 } |
2798 } | 2729 } |
2799 assert(!current.isClosed()); | 2730 assert(!current.isClosed()); |
2800 if (!stack.isEmpty) { | 2731 if (!stack.isEmpty) { |
2801 reporter.internalError(node, 'Non-empty instruction stack.'); | 2732 reporter.internalError(node, 'Non-empty instruction stack.'); |
2802 } | 2733 } |
2803 } | 2734 } |
2804 | 2735 |
2805 visitClassNode(ast.ClassNode node) { | 2736 visitClassNode(ast.ClassNode node) { |
2806 reporter.internalError(node, | 2737 reporter.internalError( |
2807 'SsaBuilder.visitClassNode should not be called.'); | 2738 node, 'SsaBuilder.visitClassNode should not be called.'); |
2808 } | 2739 } |
2809 | 2740 |
2810 visitThrowExpression(ast.Expression expression) { | 2741 visitThrowExpression(ast.Expression expression) { |
2811 bool old = inExpressionOfThrow; | 2742 bool old = inExpressionOfThrow; |
2812 try { | 2743 try { |
2813 inExpressionOfThrow = true; | 2744 inExpressionOfThrow = true; |
2814 visit(expression); | 2745 visit(expression); |
2815 } finally { | 2746 } finally { |
2816 inExpressionOfThrow = old; | 2747 inExpressionOfThrow = old; |
2817 } | 2748 } |
(...skipping 16 matching lines...) Expand all Loading... |
2834 /** | 2765 /** |
2835 * Creates a new loop-header block. The previous [current] block | 2766 * Creates a new loop-header block. The previous [current] block |
2836 * is closed with an [HGoto] and replaced by the newly created block. | 2767 * is closed with an [HGoto] and replaced by the newly created block. |
2837 * Also notifies the locals handler that we're entering a loop. | 2768 * Also notifies the locals handler that we're entering a loop. |
2838 */ | 2769 */ |
2839 JumpHandler beginLoopHeader(ast.Node node) { | 2770 JumpHandler beginLoopHeader(ast.Node node) { |
2840 assert(!isAborted()); | 2771 assert(!isAborted()); |
2841 HBasicBlock previousBlock = close(new HGoto()); | 2772 HBasicBlock previousBlock = close(new HGoto()); |
2842 | 2773 |
2843 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: true); | 2774 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: true); |
2844 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock( | 2775 HBasicBlock loopEntry = |
2845 jumpHandler.target, | 2776 graph.addNewLoopHeaderBlock(jumpHandler.target, jumpHandler.labels()); |
2846 jumpHandler.labels()); | |
2847 previousBlock.addSuccessor(loopEntry); | 2777 previousBlock.addSuccessor(loopEntry); |
2848 open(loopEntry); | 2778 open(loopEntry); |
2849 | 2779 |
2850 localsHandler.beginLoopHeader(loopEntry); | 2780 localsHandler.beginLoopHeader(loopEntry); |
2851 return jumpHandler; | 2781 return jumpHandler; |
2852 } | 2782 } |
2853 | 2783 |
2854 /** | 2784 /** |
2855 * Ends the loop: | 2785 * Ends the loop: |
2856 * - creates a new block and adds it as successor to the [branchExitBlock] and | 2786 * - creates a new block and adds it as successor to the [branchExitBlock] and |
2857 * any blocks that end in break. | 2787 * any blocks that end in break. |
2858 * - opens the new block (setting as [current]). | 2788 * - opens the new block (setting as [current]). |
2859 * - notifies the locals handler that we're exiting a loop. | 2789 * - notifies the locals handler that we're exiting a loop. |
2860 * [savedLocals] are the locals from the end of the loop condition. | 2790 * [savedLocals] are the locals from the end of the loop condition. |
2861 * [branchExitBlock] is the exit (branching) block of the condition. Generally | 2791 * [branchExitBlock] is the exit (branching) block of the condition. Generally |
2862 * this is not the top of the loop, since this would lead to critical edges. | 2792 * this is not the top of the loop, since this would lead to critical edges. |
2863 * It is null for degenerate do-while loops that have | 2793 * It is null for degenerate do-while loops that have |
2864 * no back edge because they abort (throw/return/break in the body and have | 2794 * no back edge because they abort (throw/return/break in the body and have |
2865 * no continues). | 2795 * no continues). |
2866 */ | 2796 */ |
2867 void endLoop(HBasicBlock loopEntry, | 2797 void endLoop(HBasicBlock loopEntry, HBasicBlock branchExitBlock, |
2868 HBasicBlock branchExitBlock, | 2798 JumpHandler jumpHandler, LocalsHandler savedLocals) { |
2869 JumpHandler jumpHandler, | |
2870 LocalsHandler savedLocals) { | |
2871 HBasicBlock loopExitBlock = addNewBlock(); | 2799 HBasicBlock loopExitBlock = addNewBlock(); |
2872 | 2800 |
2873 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; | 2801 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; |
2874 // Collect data for the successors and the phis at each break. | 2802 // Collect data for the successors and the phis at each break. |
2875 jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { | 2803 jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { |
2876 breakInstruction.block.addSuccessor(loopExitBlock); | 2804 breakInstruction.block.addSuccessor(loopExitBlock); |
2877 breakHandlers.add(locals); | 2805 breakHandlers.add(locals); |
2878 }); | 2806 }); |
2879 | 2807 |
2880 // The exit block is a successor of the loop condition if it is reached. | 2808 // The exit block is a successor of the loop condition if it is reached. |
(...skipping 29 matching lines...) Expand all Loading... |
2910 } | 2838 } |
2911 | 2839 |
2912 HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) { | 2840 HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) { |
2913 if (expression == null) return null; | 2841 if (expression == null) return null; |
2914 return new HSubExpressionBlockInformation(expression); | 2842 return new HSubExpressionBlockInformation(expression); |
2915 } | 2843 } |
2916 | 2844 |
2917 // For while loops, initializer and update are null. | 2845 // For while loops, initializer and update are null. |
2918 // The condition function must return a boolean result. | 2846 // The condition function must return a boolean result. |
2919 // None of the functions must leave anything on the stack. | 2847 // None of the functions must leave anything on the stack. |
2920 void handleLoop(ast.Node loop, | 2848 void handleLoop(ast.Node loop, void initialize(), HInstruction condition(), |
2921 void initialize(), | 2849 void update(), void body()) { |
2922 HInstruction condition(), | |
2923 void update(), | |
2924 void body()) { | |
2925 // Generate: | 2850 // Generate: |
2926 // <initializer> | 2851 // <initializer> |
2927 // loop-entry: | 2852 // loop-entry: |
2928 // if (!<condition>) goto loop-exit; | 2853 // if (!<condition>) goto loop-exit; |
2929 // <body> | 2854 // <body> |
2930 // <updates> | 2855 // <updates> |
2931 // goto loop-entry; | 2856 // goto loop-entry; |
2932 // loop-exit: | 2857 // loop-exit: |
2933 | 2858 |
2934 localsHandler.startLoop(loop); | 2859 localsHandler.startLoop(loop); |
2935 | 2860 |
2936 // The initializer. | 2861 // The initializer. |
2937 SubExpression initializerGraph = null; | 2862 SubExpression initializerGraph = null; |
2938 HBasicBlock startBlock; | 2863 HBasicBlock startBlock; |
2939 if (initialize != null) { | 2864 if (initialize != null) { |
2940 HBasicBlock initializerBlock = openNewBlock(); | 2865 HBasicBlock initializerBlock = openNewBlock(); |
2941 startBlock = initializerBlock; | 2866 startBlock = initializerBlock; |
2942 initialize(); | 2867 initialize(); |
2943 assert(!isAborted()); | 2868 assert(!isAborted()); |
2944 initializerGraph = | 2869 initializerGraph = new SubExpression(initializerBlock, current); |
2945 new SubExpression(initializerBlock, current); | |
2946 } | 2870 } |
2947 | 2871 |
2948 loopNesting++; | 2872 loopNesting++; |
2949 JumpHandler jumpHandler = beginLoopHeader(loop); | 2873 JumpHandler jumpHandler = beginLoopHeader(loop); |
2950 HLoopInformation loopInfo = current.loopInformation; | 2874 HLoopInformation loopInfo = current.loopInformation; |
2951 HBasicBlock conditionBlock = current; | 2875 HBasicBlock conditionBlock = current; |
2952 if (startBlock == null) startBlock = conditionBlock; | 2876 if (startBlock == null) startBlock = conditionBlock; |
2953 | 2877 |
2954 HInstruction conditionInstruction = condition(); | 2878 HInstruction conditionInstruction = condition(); |
2955 HBasicBlock conditionEndBlock = | 2879 HBasicBlock conditionEndBlock = |
(...skipping 22 matching lines...) Expand all Loading... |
2978 | 2902 |
2979 bool loopIsDegenerate = !jumpHandler.hasAnyContinue() && bodyBlock == null; | 2903 bool loopIsDegenerate = !jumpHandler.hasAnyContinue() && bodyBlock == null; |
2980 if (!loopIsDegenerate) { | 2904 if (!loopIsDegenerate) { |
2981 // Update. | 2905 // Update. |
2982 // We create an update block, even when we are in a while loop. There the | 2906 // We create an update block, even when we are in a while loop. There the |
2983 // update block is the jump-target for continue statements. We could avoid | 2907 // update block is the jump-target for continue statements. We could avoid |
2984 // the creation if there is no continue, but for now we always create it. | 2908 // the creation if there is no continue, but for now we always create it. |
2985 HBasicBlock updateBlock = addNewBlock(); | 2909 HBasicBlock updateBlock = addNewBlock(); |
2986 | 2910 |
2987 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; | 2911 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; |
2988 jumpHandler.forEachContinue((HContinue instruction, | 2912 jumpHandler |
2989 LocalsHandler locals) { | 2913 .forEachContinue((HContinue instruction, LocalsHandler locals) { |
2990 instruction.block.addSuccessor(updateBlock); | 2914 instruction.block.addSuccessor(updateBlock); |
2991 continueHandlers.add(locals); | 2915 continueHandlers.add(locals); |
2992 }); | 2916 }); |
2993 | 2917 |
2994 | |
2995 if (bodyBlock != null) { | 2918 if (bodyBlock != null) { |
2996 continueHandlers.add(localsHandler); | 2919 continueHandlers.add(localsHandler); |
2997 bodyBlock.addSuccessor(updateBlock); | 2920 bodyBlock.addSuccessor(updateBlock); |
2998 } | 2921 } |
2999 | 2922 |
3000 open(updateBlock); | 2923 open(updateBlock); |
3001 localsHandler = | 2924 localsHandler = |
3002 continueHandlers[0].mergeMultiple(continueHandlers, updateBlock); | 2925 continueHandlers[0].mergeMultiple(continueHandlers, updateBlock); |
3003 | 2926 |
3004 List<LabelDefinition> labels = jumpHandler.labels(); | 2927 List<LabelDefinition> labels = jumpHandler.labels(); |
3005 JumpTarget target = elements.getTargetDefinition(loop); | 2928 JumpTarget target = elements.getTargetDefinition(loop); |
3006 if (!labels.isEmpty) { | 2929 if (!labels.isEmpty) { |
3007 beginBodyBlock.setBlockFlow( | 2930 beginBodyBlock.setBlockFlow( |
3008 new HLabeledBlockInformation( | 2931 new HLabeledBlockInformation( |
3009 new HSubGraphBlockInformation(bodyGraph), | 2932 new HSubGraphBlockInformation(bodyGraph), jumpHandler.labels(), |
3010 jumpHandler.labels(), | |
3011 isContinue: true), | 2933 isContinue: true), |
3012 updateBlock); | 2934 updateBlock); |
3013 } else if (target != null && target.isContinueTarget) { | 2935 } else if (target != null && target.isContinueTarget) { |
3014 beginBodyBlock.setBlockFlow( | 2936 beginBodyBlock.setBlockFlow( |
3015 new HLabeledBlockInformation.implicit( | 2937 new HLabeledBlockInformation.implicit( |
3016 new HSubGraphBlockInformation(bodyGraph), | 2938 new HSubGraphBlockInformation(bodyGraph), target, |
3017 target, | |
3018 isContinue: true), | 2939 isContinue: true), |
3019 updateBlock); | 2940 updateBlock); |
3020 } | 2941 } |
3021 | 2942 |
3022 localsHandler.enterLoopUpdates(loop); | 2943 localsHandler.enterLoopUpdates(loop); |
3023 | 2944 |
3024 update(); | 2945 update(); |
3025 | 2946 |
3026 HBasicBlock updateEndBlock = close(new HGoto()); | 2947 HBasicBlock updateEndBlock = close(new HGoto()); |
3027 // The back-edge completing the cycle. | 2948 // The back-edge completing the cycle. |
3028 updateEndBlock.addSuccessor(conditionBlock); | 2949 updateEndBlock.addSuccessor(conditionBlock); |
3029 updateGraph = new SubExpression(updateBlock, updateEndBlock); | 2950 updateGraph = new SubExpression(updateBlock, updateEndBlock); |
3030 | 2951 |
3031 // Avoid a critical edge from the condition to the loop-exit body. | 2952 // Avoid a critical edge from the condition to the loop-exit body. |
3032 HBasicBlock conditionExitBlock = addNewBlock(); | 2953 HBasicBlock conditionExitBlock = addNewBlock(); |
3033 open(conditionExitBlock); | 2954 open(conditionExitBlock); |
3034 close(new HGoto()); | 2955 close(new HGoto()); |
3035 conditionEndBlock.addSuccessor(conditionExitBlock); | 2956 conditionEndBlock.addSuccessor(conditionExitBlock); |
3036 | 2957 |
3037 endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals); | 2958 endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals); |
3038 | 2959 |
3039 conditionBlock.postProcessLoopHeader(); | 2960 conditionBlock.postProcessLoopHeader(); |
3040 HLoopBlockInformation info = | 2961 HLoopBlockInformation info = new HLoopBlockInformation( |
3041 new HLoopBlockInformation( | 2962 _loopKind(loop), |
3042 _loopKind(loop), | 2963 wrapExpressionGraph(initializerGraph), |
3043 wrapExpressionGraph(initializerGraph), | 2964 wrapExpressionGraph(conditionExpression), |
3044 wrapExpressionGraph(conditionExpression), | 2965 wrapStatementGraph(bodyGraph), |
3045 wrapStatementGraph(bodyGraph), | 2966 wrapExpressionGraph(updateGraph), |
3046 wrapExpressionGraph(updateGraph), | 2967 conditionBlock.loopInformation.target, |
3047 conditionBlock.loopInformation.target, | 2968 conditionBlock.loopInformation.labels, |
3048 conditionBlock.loopInformation.labels, | 2969 sourceInformationBuilder.buildLoop(loop)); |
3049 sourceInformationBuilder.buildLoop(loop)); | |
3050 | 2970 |
3051 startBlock.setBlockFlow(info, current); | 2971 startBlock.setBlockFlow(info, current); |
3052 loopInfo.loopBlockInformation = info; | 2972 loopInfo.loopBlockInformation = info; |
3053 } else { | 2973 } else { |
3054 // The body of the for/while loop always aborts, so there is no back edge. | 2974 // The body of the for/while loop always aborts, so there is no back edge. |
3055 // We turn the code into: | 2975 // We turn the code into: |
3056 // if (condition) { | 2976 // if (condition) { |
3057 // body; | 2977 // body; |
3058 // } else { | 2978 // } else { |
3059 // // We always create an empty else block to avoid critical edges. | 2979 // // We always create an empty else block to avoid critical edges. |
(...skipping 11 matching lines...) Expand all Loading... |
3071 SubGraph elseGraph = new SubGraph(elseBlock, elseBlock); | 2991 SubGraph elseGraph = new SubGraph(elseBlock, elseBlock); |
3072 // Remove the loop information attached to the header. | 2992 // Remove the loop information attached to the header. |
3073 conditionBlock.loopInformation = null; | 2993 conditionBlock.loopInformation = null; |
3074 | 2994 |
3075 // Remove the [HLoopBranch] instruction and replace it with | 2995 // Remove the [HLoopBranch] instruction and replace it with |
3076 // [HIf]. | 2996 // [HIf]. |
3077 HInstruction condition = conditionEndBlock.last.inputs[0]; | 2997 HInstruction condition = conditionEndBlock.last.inputs[0]; |
3078 conditionEndBlock.addAtExit(new HIf(condition)); | 2998 conditionEndBlock.addAtExit(new HIf(condition)); |
3079 conditionEndBlock.addSuccessor(elseBlock); | 2999 conditionEndBlock.addSuccessor(elseBlock); |
3080 conditionEndBlock.remove(conditionEndBlock.last); | 3000 conditionEndBlock.remove(conditionEndBlock.last); |
3081 HIfBlockInformation info = | 3001 HIfBlockInformation info = new HIfBlockInformation( |
3082 new HIfBlockInformation( | 3002 wrapExpressionGraph(conditionExpression), |
3083 wrapExpressionGraph(conditionExpression), | 3003 wrapStatementGraph(bodyGraph), |
3084 wrapStatementGraph(bodyGraph), | 3004 wrapStatementGraph(elseGraph)); |
3085 wrapStatementGraph(elseGraph)); | |
3086 | 3005 |
3087 conditionEndBlock.setBlockFlow(info, current); | 3006 conditionEndBlock.setBlockFlow(info, current); |
3088 HIf ifBlock = conditionEndBlock.last; | 3007 HIf ifBlock = conditionEndBlock.last; |
3089 ifBlock.blockInformation = conditionEndBlock.blockFlow; | 3008 ifBlock.blockInformation = conditionEndBlock.blockFlow; |
3090 | 3009 |
3091 // If the body has any break, attach a synthesized label to the | 3010 // If the body has any break, attach a synthesized label to the |
3092 // if block. | 3011 // if block. |
3093 if (jumpHandler.hasAnyBreak()) { | 3012 if (jumpHandler.hasAnyBreak()) { |
3094 JumpTarget target = elements.getTargetDefinition(loop); | 3013 JumpTarget target = elements.getTargetDefinition(loop); |
3095 LabelDefinition label = target.addLabel(null, 'loop'); | 3014 LabelDefinition label = target.addLabel(null, 'loop'); |
3096 label.setBreakTarget(); | 3015 label.setBreakTarget(); |
3097 SubGraph labelGraph = new SubGraph(conditionBlock, current); | 3016 SubGraph labelGraph = new SubGraph(conditionBlock, current); |
3098 HLabeledBlockInformation labelInfo = new HLabeledBlockInformation( | 3017 HLabeledBlockInformation labelInfo = new HLabeledBlockInformation( |
3099 new HSubGraphBlockInformation(labelGraph), | 3018 new HSubGraphBlockInformation(labelGraph), |
3100 <LabelDefinition>[label]); | 3019 <LabelDefinition>[label]); |
3101 | 3020 |
3102 conditionBlock.setBlockFlow(labelInfo, current); | 3021 conditionBlock.setBlockFlow(labelInfo, current); |
3103 | 3022 |
3104 jumpHandler.forEachBreak((HBreak breakInstruction, _) { | 3023 jumpHandler.forEachBreak((HBreak breakInstruction, _) { |
3105 HBasicBlock block = breakInstruction.block; | 3024 HBasicBlock block = breakInstruction.block; |
3106 block.addAtExit(new HBreak.toLabel(label)); | 3025 block.addAtExit(new HBreak.toLabel(label)); |
3107 block.remove(breakInstruction); | 3026 block.remove(breakInstruction); |
3108 }); | 3027 }); |
3109 } | 3028 } |
3110 } | 3029 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3144 } | 3063 } |
3145 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 3064 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
3146 } | 3065 } |
3147 | 3066 |
3148 visitWhile(ast.While node) { | 3067 visitWhile(ast.While node) { |
3149 assert(isReachable); | 3068 assert(isReachable); |
3150 HInstruction buildCondition() { | 3069 HInstruction buildCondition() { |
3151 visit(node.condition); | 3070 visit(node.condition); |
3152 return popBoolified(); | 3071 return popBoolified(); |
3153 } | 3072 } |
3154 handleLoop(node, | 3073 handleLoop(node, () {}, buildCondition, () {}, () { |
3155 () {}, | 3074 visit(node.body); |
3156 buildCondition, | 3075 }); |
3157 () {}, | |
3158 () { visit(node.body); }); | |
3159 } | 3076 } |
3160 | 3077 |
3161 visitDoWhile(ast.DoWhile node) { | 3078 visitDoWhile(ast.DoWhile node) { |
3162 assert(isReachable); | 3079 assert(isReachable); |
3163 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 3080 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
3164 localsHandler.startLoop(node); | 3081 localsHandler.startLoop(node); |
3165 loopNesting++; | 3082 loopNesting++; |
3166 JumpHandler jumpHandler = beginLoopHeader(node); | 3083 JumpHandler jumpHandler = beginLoopHeader(node); |
3167 HLoopInformation loopInfo = current.loopInformation; | 3084 HLoopInformation loopInfo = current.loopInformation; |
3168 HBasicBlock loopEntryBlock = current; | 3085 HBasicBlock loopEntryBlock = current; |
(...skipping 23 matching lines...) Expand all Loading... |
3192 isAbortingBody = true; | 3109 isAbortingBody = true; |
3193 bodyExitBlock = lastOpenedBlock; | 3110 bodyExitBlock = lastOpenedBlock; |
3194 } | 3111 } |
3195 | 3112 |
3196 SubExpression conditionExpression; | 3113 SubExpression conditionExpression; |
3197 bool loopIsDegenerate = isAbortingBody && !hasContinues; | 3114 bool loopIsDegenerate = isAbortingBody && !hasContinues; |
3198 if (!loopIsDegenerate) { | 3115 if (!loopIsDegenerate) { |
3199 HBasicBlock conditionBlock = addNewBlock(); | 3116 HBasicBlock conditionBlock = addNewBlock(); |
3200 | 3117 |
3201 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; | 3118 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; |
3202 jumpHandler.forEachContinue((HContinue instruction, | 3119 jumpHandler |
3203 LocalsHandler locals) { | 3120 .forEachContinue((HContinue instruction, LocalsHandler locals) { |
3204 instruction.block.addSuccessor(conditionBlock); | 3121 instruction.block.addSuccessor(conditionBlock); |
3205 continueHandlers.add(locals); | 3122 continueHandlers.add(locals); |
3206 }); | 3123 }); |
3207 | 3124 |
3208 if (!isAbortingBody) { | 3125 if (!isAbortingBody) { |
3209 bodyExitBlock.addSuccessor(conditionBlock); | 3126 bodyExitBlock.addSuccessor(conditionBlock); |
3210 } | 3127 } |
3211 | 3128 |
3212 if (!continueHandlers.isEmpty) { | 3129 if (!continueHandlers.isEmpty) { |
3213 if (!isAbortingBody) continueHandlers.add(localsHandler); | 3130 if (!isAbortingBody) continueHandlers.add(localsHandler); |
3214 localsHandler = | 3131 localsHandler = |
3215 savedLocals.mergeMultiple(continueHandlers, conditionBlock); | 3132 savedLocals.mergeMultiple(continueHandlers, conditionBlock); |
3216 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); | 3133 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); |
3217 List<LabelDefinition> labels = jumpHandler.labels(); | 3134 List<LabelDefinition> labels = jumpHandler.labels(); |
3218 HSubGraphBlockInformation bodyInfo = | 3135 HSubGraphBlockInformation bodyInfo = |
3219 new HSubGraphBlockInformation(bodyGraph); | 3136 new HSubGraphBlockInformation(bodyGraph); |
3220 HLabeledBlockInformation info; | 3137 HLabeledBlockInformation info; |
3221 if (!labels.isEmpty) { | 3138 if (!labels.isEmpty) { |
3222 info = new HLabeledBlockInformation(bodyInfo, labels, | 3139 info = |
3223 isContinue: true); | 3140 new HLabeledBlockInformation(bodyInfo, labels, isContinue: true); |
3224 } else { | 3141 } else { |
3225 info = new HLabeledBlockInformation.implicit(bodyInfo, target, | 3142 info = new HLabeledBlockInformation.implicit(bodyInfo, target, |
3226 isContinue: true); | 3143 isContinue: true); |
3227 } | 3144 } |
3228 bodyEntryBlock.setBlockFlow(info, conditionBlock); | 3145 bodyEntryBlock.setBlockFlow(info, conditionBlock); |
3229 } | 3146 } |
3230 open(conditionBlock); | 3147 open(conditionBlock); |
3231 | 3148 |
3232 visit(node.condition); | 3149 visit(node.condition); |
3233 assert(!isAborted()); | 3150 assert(!isAborted()); |
3234 HInstruction conditionInstruction = popBoolified(); | 3151 HInstruction conditionInstruction = popBoolified(); |
3235 HBasicBlock conditionEndBlock = close( | 3152 HBasicBlock conditionEndBlock = close( |
3236 new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP)); | 3153 new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP)); |
(...skipping 10 matching lines...) Expand all Loading... |
3247 // Avoid a critical edge from the condition to the loop-exit body. | 3164 // Avoid a critical edge from the condition to the loop-exit body. |
3248 HBasicBlock conditionExitBlock = addNewBlock(); | 3165 HBasicBlock conditionExitBlock = addNewBlock(); |
3249 open(conditionExitBlock); | 3166 open(conditionExitBlock); |
3250 close(new HGoto()); | 3167 close(new HGoto()); |
3251 conditionEndBlock.addSuccessor(conditionExitBlock); | 3168 conditionEndBlock.addSuccessor(conditionExitBlock); |
3252 | 3169 |
3253 endLoop(loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); | 3170 endLoop(loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); |
3254 | 3171 |
3255 loopEntryBlock.postProcessLoopHeader(); | 3172 loopEntryBlock.postProcessLoopHeader(); |
3256 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); | 3173 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); |
3257 HLoopBlockInformation loopBlockInfo = | 3174 HLoopBlockInformation loopBlockInfo = new HLoopBlockInformation( |
3258 new HLoopBlockInformation( | 3175 HLoopBlockInformation.DO_WHILE_LOOP, |
3259 HLoopBlockInformation.DO_WHILE_LOOP, | 3176 null, |
3260 null, | 3177 wrapExpressionGraph(conditionExpression), |
3261 wrapExpressionGraph(conditionExpression), | 3178 wrapStatementGraph(bodyGraph), |
3262 wrapStatementGraph(bodyGraph), | 3179 null, |
3263 null, | 3180 loopEntryBlock.loopInformation.target, |
3264 loopEntryBlock.loopInformation.target, | 3181 loopEntryBlock.loopInformation.labels, |
3265 loopEntryBlock.loopInformation.labels, | 3182 sourceInformationBuilder.buildLoop(node)); |
3266 sourceInformationBuilder.buildLoop(node)); | |
3267 loopEntryBlock.setBlockFlow(loopBlockInfo, current); | 3183 loopEntryBlock.setBlockFlow(loopBlockInfo, current); |
3268 loopInfo.loopBlockInformation = loopBlockInfo; | 3184 loopInfo.loopBlockInformation = loopBlockInfo; |
3269 } else { | 3185 } else { |
3270 // Since the loop has no back edge, we remove the loop information on the | 3186 // Since the loop has no back edge, we remove the loop information on the |
3271 // header. | 3187 // header. |
3272 loopEntryBlock.loopInformation = null; | 3188 loopEntryBlock.loopInformation = null; |
3273 | 3189 |
3274 if (jumpHandler.hasAnyBreak()) { | 3190 if (jumpHandler.hasAnyBreak()) { |
3275 // Null branchBlock because the body of the do-while loop always aborts, | 3191 // Null branchBlock because the body of the do-while loop always aborts, |
3276 // so we never get to the condition. | 3192 // so we never get to the condition. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3313 closureClassElement.closureFields.forEach((ClosureFieldElement field) { | 3229 closureClassElement.closureFields.forEach((ClosureFieldElement field) { |
3314 Local capturedLocal = | 3230 Local capturedLocal = |
3315 nestedClosureData.getLocalVariableForClosureField(field); | 3231 nestedClosureData.getLocalVariableForClosureField(field); |
3316 assert(capturedLocal != null); | 3232 assert(capturedLocal != null); |
3317 capturedVariables.add(localsHandler.readLocal(capturedLocal)); | 3233 capturedVariables.add(localsHandler.readLocal(capturedLocal)); |
3318 }); | 3234 }); |
3319 | 3235 |
3320 TypeMask type = | 3236 TypeMask type = |
3321 new TypeMask.nonNullExact(closureClassElement, compiler.world); | 3237 new TypeMask.nonNullExact(closureClassElement, compiler.world); |
3322 push(new HForeignNew(closureClassElement, type, capturedVariables) | 3238 push(new HForeignNew(closureClassElement, type, capturedVariables) |
3323 ..sourceInformation = sourceInformationBuilder.buildCreate(node)); | 3239 ..sourceInformation = sourceInformationBuilder.buildCreate(node)); |
3324 | 3240 |
3325 Element methodElement = nestedClosureData.closureElement; | 3241 Element methodElement = nestedClosureData.closureElement; |
3326 registry?.registerInstantiatedClosure(methodElement); | 3242 registry?.registerInstantiatedClosure(methodElement); |
3327 } | 3243 } |
3328 | 3244 |
3329 visitFunctionDeclaration(ast.FunctionDeclaration node) { | 3245 visitFunctionDeclaration(ast.FunctionDeclaration node) { |
3330 assert(isReachable); | 3246 assert(isReachable); |
3331 visit(node.function); | 3247 visit(node.function); |
3332 LocalFunctionElement localFunction = | 3248 LocalFunctionElement localFunction = |
3333 elements.getFunctionDefinition(node.function); | 3249 elements.getFunctionDefinition(node.function); |
3334 localsHandler.updateLocal(localFunction, pop()); | 3250 localsHandler.updateLocal(localFunction, pop()); |
3335 } | 3251 } |
3336 | 3252 |
3337 @override | 3253 @override |
3338 void visitThisGet(ast.Identifier node, [_]) { | 3254 void visitThisGet(ast.Identifier node, [_]) { |
3339 stack.add(localsHandler.readThis()); | 3255 stack.add(localsHandler.readThis()); |
3340 } | 3256 } |
3341 | 3257 |
3342 visitIdentifier(ast.Identifier node) { | 3258 visitIdentifier(ast.Identifier node) { |
3343 if (node.isThis()) { | 3259 if (node.isThis()) { |
3344 visitThisGet(node); | 3260 visitThisGet(node); |
3345 } else { | 3261 } else { |
3346 reporter.internalError(node, | 3262 reporter.internalError( |
3347 "SsaFromAstMixin.visitIdentifier on non-this."); | 3263 node, "SsaFromAstMixin.visitIdentifier on non-this."); |
3348 } | 3264 } |
3349 } | 3265 } |
3350 | 3266 |
3351 visitIf(ast.If node) { | 3267 visitIf(ast.If node) { |
3352 assert(isReachable); | 3268 assert(isReachable); |
3353 handleIf( | 3269 handleIf(node, |
3354 node, | |
3355 visitCondition: () => visit(node.condition), | 3270 visitCondition: () => visit(node.condition), |
3356 visitThen: () => visit(node.thenPart), | 3271 visitThen: () => visit(node.thenPart), |
3357 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, | 3272 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, |
3358 sourceInformation: sourceInformationBuilder.buildIf(node)); | 3273 sourceInformation: sourceInformationBuilder.buildIf(node)); |
3359 } | 3274 } |
3360 | 3275 |
3361 void handleIf(ast.Node diagnosticNode, | 3276 void handleIf(ast.Node diagnosticNode, |
3362 {void visitCondition(), | 3277 {void visitCondition(), |
3363 void visitThen(), | 3278 void visitThen(), |
3364 void visitElse(), | 3279 void visitElse(), |
3365 SourceInformation sourceInformation}) { | 3280 SourceInformation sourceInformation}) { |
3366 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); | 3281 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); |
3367 branchBuilder.handleIf( | 3282 branchBuilder.handleIf(visitCondition, visitThen, visitElse, |
3368 visitCondition, visitThen, visitElse, | |
3369 sourceInformation: sourceInformation); | 3283 sourceInformation: sourceInformation); |
3370 } | 3284 } |
3371 | 3285 |
3372 @override | 3286 @override |
3373 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { | 3287 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { |
3374 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3288 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
3375 brancher.handleIfNull(() => visit(left), () => visit(right)); | 3289 brancher.handleIfNull(() => visit(left), () => visit(right)); |
3376 } | 3290 } |
3377 | 3291 |
3378 @override | 3292 @override |
3379 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { | 3293 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { |
3380 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 3294 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
3381 branchBuilder.handleLogicalAndOrWithLeftNode( | 3295 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { |
3382 left, | 3296 visit(right); |
3383 () { visit(right); }, | 3297 }, isAnd: true); |
3384 isAnd: true); | |
3385 } | 3298 } |
3386 | 3299 |
3387 @override | 3300 @override |
3388 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { | 3301 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { |
3389 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 3302 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
3390 branchBuilder.handleLogicalAndOrWithLeftNode( | 3303 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { |
3391 left, | 3304 visit(right); |
3392 () { visit(right); }, | 3305 }, isAnd: false); |
3393 isAnd: false); | |
3394 } | 3306 } |
3395 | 3307 |
3396 @override | 3308 @override |
3397 void visitNot(ast.Send node, ast.Node expression, _) { | 3309 void visitNot(ast.Send node, ast.Node expression, _) { |
3398 assert(node.argumentsNode is ast.Prefix); | 3310 assert(node.argumentsNode is ast.Prefix); |
3399 visit(expression); | 3311 visit(expression); |
3400 SourceInformation sourceInformation = | 3312 SourceInformation sourceInformation = |
3401 sourceInformationBuilder.buildGeneric(node); | 3313 sourceInformationBuilder.buildGeneric(node); |
3402 push(new HNot(popBoolified(), backend.boolType) | 3314 push(new HNot(popBoolified(), backend.boolType) |
3403 ..sourceInformation = sourceInformation); | 3315 ..sourceInformation = sourceInformation); |
3404 } | 3316 } |
3405 | 3317 |
3406 @override | 3318 @override |
3407 void visitUnary(ast.Send node, | 3319 void visitUnary( |
3408 UnaryOperator operator, | 3320 ast.Send node, UnaryOperator operator, ast.Node expression, _) { |
3409 ast.Node expression,_) { | |
3410 assert(node.argumentsNode is ast.Prefix); | 3321 assert(node.argumentsNode is ast.Prefix); |
3411 HInstruction operand = visitAndPop(expression); | 3322 HInstruction operand = visitAndPop(expression); |
3412 | 3323 |
3413 // See if we can constant-fold right away. This avoids rewrites later on. | 3324 // See if we can constant-fold right away. This avoids rewrites later on. |
3414 if (operand is HConstant) { | 3325 if (operand is HConstant) { |
3415 UnaryOperation operation = constantSystem.lookupUnary(operator); | 3326 UnaryOperation operation = constantSystem.lookupUnary(operator); |
3416 HConstant constant = operand; | 3327 HConstant constant = operand; |
3417 ConstantValue folded = operation.fold(constant.constant); | 3328 ConstantValue folded = operation.fold(constant.constant); |
3418 if (folded != null) { | 3329 if (folded != null) { |
3419 stack.add(graph.addConstant(folded, compiler)); | 3330 stack.add(graph.addConstant(folded, compiler)); |
3420 return; | 3331 return; |
3421 } | 3332 } |
3422 } | 3333 } |
3423 | 3334 |
3424 pushInvokeDynamic( | 3335 pushInvokeDynamic( |
3425 node, | 3336 node, elements.getSelector(node), elements.getTypeMask(node), [operand], |
3426 elements.getSelector(node), | |
3427 elements.getTypeMask(node), | |
3428 [operand], | |
3429 sourceInformation: sourceInformationBuilder.buildGeneric(node)); | 3337 sourceInformation: sourceInformationBuilder.buildGeneric(node)); |
3430 } | 3338 } |
3431 | 3339 |
3432 @override | 3340 @override |
3433 void visitBinary(ast.Send node, | 3341 void visitBinary(ast.Send node, ast.Node left, BinaryOperator operator, |
3434 ast.Node left, | 3342 ast.Node right, _) { |
3435 BinaryOperator operator, | |
3436 ast.Node right, _) { | |
3437 handleBinary(node, left, right); | 3343 handleBinary(node, left, right); |
3438 } | 3344 } |
3439 | 3345 |
3440 @override | 3346 @override |
3441 void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) { | 3347 void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) { |
3442 generateDynamicSend(node); | 3348 generateDynamicSend(node); |
3443 } | 3349 } |
3444 | 3350 |
3445 @override | 3351 @override |
3446 void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) { | 3352 void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
3447 handleBinary(node, left, right); | 3353 handleBinary(node, left, right); |
3448 } | 3354 } |
3449 | 3355 |
3450 @override | 3356 @override |
3451 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { | 3357 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
3452 handleBinary(node, left, right); | 3358 handleBinary(node, left, right); |
3453 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); | 3359 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); |
3454 } | 3360 } |
3455 | 3361 |
3456 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { | 3362 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { |
3457 visitBinarySend( | 3363 visitBinarySend(visitAndPop(left), visitAndPop(right), |
3458 visitAndPop(left), | 3364 elements.getSelector(node), elements.getTypeMask(node), node, |
3459 visitAndPop(right), | |
3460 elements.getSelector(node), | |
3461 elements.getTypeMask(node), | |
3462 node, | |
3463 sourceInformation: | 3365 sourceInformation: |
3464 sourceInformationBuilder.buildGeneric(node.selector)); | 3366 sourceInformationBuilder.buildGeneric(node.selector)); |
3465 } | 3367 } |
3466 | 3368 |
3467 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and | 3369 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and |
3468 /// remove use of [location] for source information. | 3370 /// remove use of [location] for source information. |
3469 void visitBinarySend(HInstruction left, | 3371 void visitBinarySend(HInstruction left, HInstruction right, Selector selector, |
3470 HInstruction right, | 3372 TypeMask mask, ast.Send send, |
3471 Selector selector, | 3373 {SourceInformation sourceInformation}) { |
3472 TypeMask mask, | |
3473 ast.Send send, | |
3474 {SourceInformation sourceInformation}) { | |
3475 pushInvokeDynamic(send, selector, mask, [left, right], | 3374 pushInvokeDynamic(send, selector, mask, [left, right], |
3476 sourceInformation: sourceInformation); | 3375 sourceInformation: sourceInformation); |
3477 } | 3376 } |
3478 | 3377 |
3479 HInstruction generateInstanceSendReceiver(ast.Send send) { | 3378 HInstruction generateInstanceSendReceiver(ast.Send send) { |
3480 assert(Elements.isInstanceSend(send, elements)); | 3379 assert(Elements.isInstanceSend(send, elements)); |
3481 if (send.receiver == null) { | 3380 if (send.receiver == null) { |
3482 return localsHandler.readThis(); | 3381 return localsHandler.readThis(); |
3483 } | 3382 } |
3484 visit(send.receiver); | 3383 visit(send.receiver); |
3485 return pop(); | 3384 return pop(); |
3486 } | 3385 } |
3487 | 3386 |
3488 String noSuchMethodTargetSymbolString(Element error, [String prefix]) { | 3387 String noSuchMethodTargetSymbolString(Element error, [String prefix]) { |
3489 String result = error.name; | 3388 String result = error.name; |
3490 if (prefix == "set") return "$result="; | 3389 if (prefix == "set") return "$result="; |
3491 return result; | 3390 return result; |
3492 } | 3391 } |
3493 | 3392 |
3494 /** | 3393 /** |
3495 * Returns a set of interceptor classes that contain the given | 3394 * Returns a set of interceptor classes that contain the given |
3496 * [selector]. | 3395 * [selector]. |
3497 */ | 3396 */ |
3498 void generateInstanceGetterWithCompiledReceiver( | 3397 void generateInstanceGetterWithCompiledReceiver( |
3499 ast.Send send, | 3398 ast.Send send, Selector selector, TypeMask mask, HInstruction receiver) { |
3500 Selector selector, | |
3501 TypeMask mask, | |
3502 HInstruction receiver) { | |
3503 assert(Elements.isInstanceSend(send, elements)); | 3399 assert(Elements.isInstanceSend(send, elements)); |
3504 assert(selector.isGetter); | 3400 assert(selector.isGetter); |
3505 pushInvokeDynamic(send, selector, mask, [receiver], | 3401 pushInvokeDynamic(send, selector, mask, [receiver], |
3506 sourceInformation: sourceInformationBuilder.buildGet(send)); | 3402 sourceInformation: sourceInformationBuilder.buildGet(send)); |
3507 } | 3403 } |
3508 | 3404 |
3509 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. | 3405 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. |
3510 /// If [prefixElement] is [null] ndo nothing. | 3406 /// If [prefixElement] is [null] ndo nothing. |
3511 void generateIsDeferredLoadedCheckIfNeeded(PrefixElement prefixElement, | 3407 void generateIsDeferredLoadedCheckIfNeeded( |
3512 ast.Node location) { | 3408 PrefixElement prefixElement, ast.Node location) { |
3513 if (prefixElement == null) return; | 3409 if (prefixElement == null) return; |
3514 String loadId = | 3410 String loadId = |
3515 compiler.deferredLoadTask.getImportDeferName(location, prefixElement); | 3411 compiler.deferredLoadTask.getImportDeferName(location, prefixElement); |
3516 HInstruction loadIdConstant = addConstantString(loadId); | 3412 HInstruction loadIdConstant = addConstantString(loadId); |
3517 String uri = prefixElement.deferredImport.uri.toString(); | 3413 String uri = prefixElement.deferredImport.uri.toString(); |
3518 HInstruction uriConstant = addConstantString(uri); | 3414 HInstruction uriConstant = addConstantString(uri); |
3519 Element helper = helpers.checkDeferredIsLoaded; | 3415 Element helper = helpers.checkDeferredIsLoaded; |
3520 pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]); | 3416 pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]); |
3521 pop(); | 3417 pop(); |
3522 } | 3418 } |
3523 | 3419 |
3524 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that | 3420 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that |
3525 /// resolves to a deferred library. | 3421 /// resolves to a deferred library. |
3526 void generateIsDeferredLoadedCheckOfSend(ast.Send node) { | 3422 void generateIsDeferredLoadedCheckOfSend(ast.Send node) { |
3527 generateIsDeferredLoadedCheckIfNeeded( | 3423 generateIsDeferredLoadedCheckIfNeeded( |
3528 compiler.deferredLoadTask.deferredPrefixElement(node, elements), | 3424 compiler.deferredLoadTask.deferredPrefixElement(node, elements), node); |
3529 node); | |
3530 } | 3425 } |
3531 | 3426 |
3532 void handleInvalidStaticGet(ast.Send node, Element element) { | 3427 void handleInvalidStaticGet(ast.Send node, Element element) { |
3533 SourceInformation sourceInformation = | 3428 SourceInformation sourceInformation = |
3534 sourceInformationBuilder.buildGet(node); | 3429 sourceInformationBuilder.buildGet(node); |
3535 generateThrowNoSuchMethod( | 3430 generateThrowNoSuchMethod( |
3536 node, | 3431 node, noSuchMethodTargetSymbolString(element, 'get'), |
3537 noSuchMethodTargetSymbolString(element, 'get'), | |
3538 argumentNodes: const Link<ast.Node>(), | 3432 argumentNodes: const Link<ast.Node>(), |
3539 sourceInformation: sourceInformation); | 3433 sourceInformation: sourceInformation); |
3540 } | 3434 } |
3541 | 3435 |
3542 /// Generate read access of an unresolved static or top level entity. | 3436 /// Generate read access of an unresolved static or top level entity. |
3543 void generateStaticUnresolvedGet(ast.Send node, Element element) { | 3437 void generateStaticUnresolvedGet(ast.Send node, Element element) { |
3544 if (element is ErroneousElement) { | 3438 if (element is ErroneousElement) { |
3545 SourceInformation sourceInformation = | 3439 SourceInformation sourceInformation = |
3546 sourceInformationBuilder.buildGet(node); | 3440 sourceInformationBuilder.buildGet(node); |
3547 // An erroneous element indicates an unresolved static getter. | 3441 // An erroneous element indicates an unresolved static getter. |
3548 handleInvalidStaticGet(node, element); | 3442 handleInvalidStaticGet(node, element); |
3549 } else { | 3443 } else { |
3550 // This happens when [element] has parse errors. | 3444 // This happens when [element] has parse errors. |
3551 assert(invariant(node, element == null || element.isMalformed)); | 3445 assert(invariant(node, element == null || element.isMalformed)); |
3552 // TODO(ahe): Do something like the above, that is, emit a runtime | 3446 // TODO(ahe): Do something like the above, that is, emit a runtime |
3553 // error. | 3447 // error. |
3554 stack.add(graph.addConstantNull(compiler)); | 3448 stack.add(graph.addConstantNull(compiler)); |
3555 } | 3449 } |
3556 } | 3450 } |
3557 | 3451 |
3558 /// Read a static or top level [field] of constant value. | 3452 /// Read a static or top level [field] of constant value. |
3559 void generateStaticConstGet( | 3453 void generateStaticConstGet(ast.Send node, FieldElement field, |
3560 ast.Send node, | 3454 ConstantExpression constant, SourceInformation sourceInformation) { |
3561 FieldElement field, | |
3562 ConstantExpression constant, | |
3563 SourceInformation sourceInformation) { | |
3564 ConstantValue value = backend.constants.getConstantValue(constant); | 3455 ConstantValue value = backend.constants.getConstantValue(constant); |
3565 HConstant instruction; | 3456 HConstant instruction; |
3566 // Constants that are referred via a deferred prefix should be referred | 3457 // Constants that are referred via a deferred prefix should be referred |
3567 // by reference. | 3458 // by reference. |
3568 PrefixElement prefix = compiler.deferredLoadTask | 3459 PrefixElement prefix = |
3569 .deferredPrefixElement(node, elements); | 3460 compiler.deferredLoadTask.deferredPrefixElement(node, elements); |
3570 if (prefix != null) { | 3461 if (prefix != null) { |
3571 instruction = | 3462 instruction = |
3572 graph.addDeferredConstant(value, prefix, sourceInformation, compiler); | 3463 graph.addDeferredConstant(value, prefix, sourceInformation, compiler); |
3573 } else { | 3464 } else { |
3574 instruction = graph.addConstant( | 3465 instruction = graph.addConstant(value, compiler, |
3575 value, compiler, sourceInformation: sourceInformation); | 3466 sourceInformation: sourceInformation); |
3576 } | 3467 } |
3577 stack.add(instruction); | 3468 stack.add(instruction); |
3578 // The inferrer may have found a better type than the constant | 3469 // The inferrer may have found a better type than the constant |
3579 // handler in the case of lists, because the constant handler | 3470 // handler in the case of lists, because the constant handler |
3580 // does not look at elements in the list. | 3471 // does not look at elements in the list. |
3581 TypeMask type = | 3472 TypeMask type = TypeMaskFactory.inferredTypeForElement(field, compiler); |
3582 TypeMaskFactory.inferredTypeForElement(field, compiler); | 3473 if (!type.containsAll(compiler.world) && !instruction.isConstantNull()) { |
3583 if (!type.containsAll(compiler.world) && | |
3584 !instruction.isConstantNull()) { | |
3585 // TODO(13429): The inferrer should know that an element | 3474 // TODO(13429): The inferrer should know that an element |
3586 // cannot be null. | 3475 // cannot be null. |
3587 instruction.instructionType = type.nonNullable(); | 3476 instruction.instructionType = type.nonNullable(); |
3588 } | 3477 } |
3589 } | 3478 } |
3590 | 3479 |
3591 @override | 3480 @override |
3592 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) { | 3481 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) { |
3593 generateIsDeferredLoadedCheckIfNeeded(prefix, node); | 3482 generateIsDeferredLoadedCheckIfNeeded(prefix, node); |
3594 } | 3483 } |
3595 | 3484 |
3596 /// Read a static or top level [field]. | 3485 /// Read a static or top level [field]. |
3597 void generateStaticFieldGet(ast.Send node, FieldElement field) { | 3486 void generateStaticFieldGet(ast.Send node, FieldElement field) { |
3598 ConstantExpression constant = | 3487 ConstantExpression constant = |
3599 backend.constants.getConstantForVariable(field); | 3488 backend.constants.getConstantForVariable(field); |
3600 SourceInformation sourceInformation = | 3489 SourceInformation sourceInformation = |
3601 sourceInformationBuilder.buildGet(node); | 3490 sourceInformationBuilder.buildGet(node); |
3602 if (constant != null) { | 3491 if (constant != null) { |
3603 if (!field.isAssignable) { | 3492 if (!field.isAssignable) { |
3604 // A static final or const. Get its constant value and inline it if | 3493 // A static final or const. Get its constant value and inline it if |
3605 // the value can be compiled eagerly. | 3494 // the value can be compiled eagerly. |
3606 generateStaticConstGet(node, field, constant, sourceInformation); | 3495 generateStaticConstGet(node, field, constant, sourceInformation); |
3607 } else { | 3496 } else { |
3608 // TODO(5346): Try to avoid the need for calling [declaration] before | 3497 // TODO(5346): Try to avoid the need for calling [declaration] before |
3609 // creating an [HStatic]. | 3498 // creating an [HStatic]. |
3610 HInstruction instruction = new HStatic( | 3499 HInstruction instruction = new HStatic(field.declaration, |
3611 field.declaration, | |
3612 TypeMaskFactory.inferredTypeForElement(field, compiler)) | 3500 TypeMaskFactory.inferredTypeForElement(field, compiler)) |
3613 ..sourceInformation = sourceInformation; | 3501 ..sourceInformation = sourceInformation; |
3614 push(instruction); | 3502 push(instruction); |
3615 } | 3503 } |
3616 } else { | 3504 } else { |
3617 HInstruction instruction = new HLazyStatic( | 3505 HInstruction instruction = new HLazyStatic( |
3618 field, | 3506 field, TypeMaskFactory.inferredTypeForElement(field, compiler)) |
3619 TypeMaskFactory.inferredTypeForElement(field, compiler)) | 3507 ..sourceInformation = sourceInformation; |
3620 ..sourceInformation = sourceInformation; | |
3621 push(instruction); | 3508 push(instruction); |
3622 } | 3509 } |
3623 } | 3510 } |
3624 | 3511 |
3625 /// Generate a getter invocation of the static or top level [getter]. | 3512 /// Generate a getter invocation of the static or top level [getter]. |
3626 void generateStaticGetterGet(ast.Send node, MethodElement getter) { | 3513 void generateStaticGetterGet(ast.Send node, MethodElement getter) { |
3627 SourceInformation sourceInformation = | 3514 SourceInformation sourceInformation = |
3628 sourceInformationBuilder.buildGet(node); | 3515 sourceInformationBuilder.buildGet(node); |
3629 if (getter.isDeferredLoaderGetter) { | 3516 if (getter.isDeferredLoaderGetter) { |
3630 generateDeferredLoaderGet(node, getter, sourceInformation); | 3517 generateDeferredLoaderGet(node, getter, sourceInformation); |
3631 } else { | 3518 } else { |
3632 pushInvokeStatic(node, getter, <HInstruction>[], | 3519 pushInvokeStatic(node, getter, <HInstruction>[], |
3633 sourceInformation: sourceInformation); | 3520 sourceInformation: sourceInformation); |
3634 } | 3521 } |
3635 } | 3522 } |
3636 | 3523 |
3637 /// Generate a dynamic getter invocation. | 3524 /// Generate a dynamic getter invocation. |
3638 void generateDynamicGet(ast.Send node) { | 3525 void generateDynamicGet(ast.Send node) { |
3639 HInstruction receiver = generateInstanceSendReceiver(node); | 3526 HInstruction receiver = generateInstanceSendReceiver(node); |
3640 generateInstanceGetterWithCompiledReceiver( | 3527 generateInstanceGetterWithCompiledReceiver( |
3641 node, elements.getSelector(node), elements.getTypeMask(node), receiver); | 3528 node, elements.getSelector(node), elements.getTypeMask(node), receiver); |
3642 } | 3529 } |
3643 | 3530 |
3644 /// Generate a closurization of the static or top level [function]. | 3531 /// Generate a closurization of the static or top level [function]. |
3645 void generateStaticFunctionGet(ast.Send node, MethodElement function) { | 3532 void generateStaticFunctionGet(ast.Send node, MethodElement function) { |
3646 // TODO(5346): Try to avoid the need for calling [declaration] before | 3533 // TODO(5346): Try to avoid the need for calling [declaration] before |
3647 // creating an [HStatic]. | 3534 // creating an [HStatic]. |
3648 SourceInformation sourceInformation = | 3535 SourceInformation sourceInformation = |
3649 sourceInformationBuilder.buildGet(node); | 3536 sourceInformationBuilder.buildGet(node); |
3650 push(new HStatic(function.declaration, backend.nonNullType) | 3537 push(new HStatic(function.declaration, backend.nonNullType) |
3651 ..sourceInformation = sourceInformation); | 3538 ..sourceInformation = sourceInformation); |
3652 } | 3539 } |
3653 | 3540 |
3654 /// Read a local variable, function or parameter. | 3541 /// Read a local variable, function or parameter. |
3655 void buildLocalGet(LocalElement local, SourceInformation sourceInformation) { | 3542 void buildLocalGet(LocalElement local, SourceInformation sourceInformation) { |
3656 stack.add(localsHandler.readLocal( | 3543 stack.add( |
3657 local, sourceInformation: sourceInformation)); | 3544 localsHandler.readLocal(local, sourceInformation: sourceInformation)); |
3658 } | 3545 } |
3659 | 3546 |
3660 void handleLocalGet(ast.Send node, LocalElement local) { | 3547 void handleLocalGet(ast.Send node, LocalElement local) { |
3661 buildLocalGet(local, sourceInformationBuilder.buildGet(node)); | 3548 buildLocalGet(local, sourceInformationBuilder.buildGet(node)); |
3662 } | 3549 } |
3663 | 3550 |
3664 @override | 3551 @override |
3665 void visitDynamicPropertyGet( | 3552 void visitDynamicPropertyGet(ast.Send node, ast.Node receiver, Name name, _) { |
3666 ast.Send node, | |
3667 ast.Node receiver, | |
3668 Name name, | |
3669 _) { | |
3670 generateDynamicGet(node); | 3553 generateDynamicGet(node); |
3671 } | 3554 } |
3672 | 3555 |
3673 @override | 3556 @override |
3674 void visitIfNotNullDynamicPropertyGet( | 3557 void visitIfNotNullDynamicPropertyGet( |
3675 ast.Send node, | 3558 ast.Send node, ast.Node receiver, Name name, _) { |
3676 ast.Node receiver, | |
3677 Name name, | |
3678 _) { | |
3679 // exp?.x compiled as: | 3559 // exp?.x compiled as: |
3680 // t1 = exp; | 3560 // t1 = exp; |
3681 // result = t1 == null ? t1 : t1.x; | 3561 // result = t1 == null ? t1 : t1.x; |
3682 // This is equivalent to t1 == null ? null : t1.x, but in the current form | 3562 // This is equivalent to t1 == null ? null : t1.x, but in the current form |
3683 // we will be able to later compress it as: | 3563 // we will be able to later compress it as: |
3684 // t1 || t1.x | 3564 // t1 || t1.x |
3685 HInstruction expression; | 3565 HInstruction expression; |
3686 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3566 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
3687 brancher.handleConditional( | 3567 brancher.handleConditional( |
3688 () { | 3568 () { |
3689 expression = visitAndPop(receiver); | 3569 expression = visitAndPop(receiver); |
3690 pushCheckNull(expression); | 3570 pushCheckNull(expression); |
3691 }, | 3571 }, |
3692 () => stack.add(expression), | 3572 () => stack.add(expression), |
3693 () { | 3573 () { |
3694 generateInstanceGetterWithCompiledReceiver( | 3574 generateInstanceGetterWithCompiledReceiver( |
3695 node, | 3575 node, |
3696 elements.getSelector(node), | 3576 elements.getSelector(node), |
3697 elements.getTypeMask(node), | 3577 elements.getTypeMask(node), |
3698 expression); | 3578 expression); |
3699 }); | 3579 }); |
3700 } | 3580 } |
3701 | 3581 |
3702 /// Pushes a boolean checking [expression] against null. | 3582 /// Pushes a boolean checking [expression] against null. |
3703 pushCheckNull(HInstruction expression) { | 3583 pushCheckNull(HInstruction expression) { |
3704 push(new HIdentity(expression, graph.addConstantNull(compiler), | 3584 push(new HIdentity( |
3705 null, backend.boolType)); | 3585 expression, graph.addConstantNull(compiler), null, backend.boolType)); |
3706 } | 3586 } |
3707 | 3587 |
3708 @override | 3588 @override |
3709 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { | 3589 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { |
3710 handleLocalGet(node, variable); | 3590 handleLocalGet(node, variable); |
3711 } | 3591 } |
3712 | 3592 |
3713 @override | 3593 @override |
3714 void visitParameterGet(ast.Send node, ParameterElement parameter, _) { | 3594 void visitParameterGet(ast.Send node, ParameterElement parameter, _) { |
3715 handleLocalGet(node, parameter); | 3595 handleLocalGet(node, parameter); |
3716 } | 3596 } |
3717 | 3597 |
3718 @override | 3598 @override |
3719 void visitLocalFunctionGet(ast.Send node, LocalFunctionElement function, _) { | 3599 void visitLocalFunctionGet(ast.Send node, LocalFunctionElement function, _) { |
3720 handleLocalGet(node, function); | 3600 handleLocalGet(node, function); |
3721 } | 3601 } |
3722 | 3602 |
3723 @override | 3603 @override |
3724 void visitStaticFieldGet( | 3604 void visitStaticFieldGet(ast.Send node, FieldElement field, _) { |
3725 ast.Send node, | |
3726 FieldElement field, | |
3727 _) { | |
3728 generateStaticFieldGet(node, field); | 3605 generateStaticFieldGet(node, field); |
3729 } | 3606 } |
3730 | 3607 |
3731 @override | 3608 @override |
3732 void visitStaticFunctionGet( | 3609 void visitStaticFunctionGet(ast.Send node, MethodElement function, _) { |
3733 ast.Send node, | |
3734 MethodElement function, | |
3735 _) { | |
3736 generateStaticFunctionGet(node, function); | 3610 generateStaticFunctionGet(node, function); |
3737 } | 3611 } |
3738 | 3612 |
3739 @override | 3613 @override |
3740 void visitStaticGetterGet( | 3614 void visitStaticGetterGet(ast.Send node, FunctionElement getter, _) { |
3741 ast.Send node, | |
3742 FunctionElement getter, | |
3743 _) { | |
3744 generateStaticGetterGet(node, getter); | 3615 generateStaticGetterGet(node, getter); |
3745 } | 3616 } |
3746 | 3617 |
3747 @override | 3618 @override |
3748 void visitThisPropertyGet( | 3619 void visitThisPropertyGet(ast.Send node, Name name, _) { |
3749 ast.Send node, | |
3750 Name name, | |
3751 _) { | |
3752 generateDynamicGet(node); | 3620 generateDynamicGet(node); |
3753 } | 3621 } |
3754 | 3622 |
3755 @override | 3623 @override |
3756 void visitTopLevelFieldGet( | 3624 void visitTopLevelFieldGet(ast.Send node, FieldElement field, _) { |
3757 ast.Send node, | |
3758 FieldElement field, | |
3759 _) { | |
3760 generateStaticFieldGet(node, field); | 3625 generateStaticFieldGet(node, field); |
3761 } | 3626 } |
3762 | 3627 |
3763 @override | 3628 @override |
3764 void visitTopLevelFunctionGet( | 3629 void visitTopLevelFunctionGet(ast.Send node, MethodElement function, _) { |
3765 ast.Send node, | |
3766 MethodElement function, | |
3767 _) { | |
3768 generateStaticFunctionGet(node, function); | 3630 generateStaticFunctionGet(node, function); |
3769 } | 3631 } |
3770 | 3632 |
3771 @override | 3633 @override |
3772 void visitTopLevelGetterGet( | 3634 void visitTopLevelGetterGet(ast.Send node, FunctionElement getter, _) { |
3773 ast.Send node, | |
3774 FunctionElement getter, | |
3775 _) { | |
3776 generateStaticGetterGet(node, getter); | 3635 generateStaticGetterGet(node, getter); |
3777 } | 3636 } |
3778 | 3637 |
3779 void generateInstanceSetterWithCompiledReceiver(ast.Send send, | 3638 void generateInstanceSetterWithCompiledReceiver( |
3780 HInstruction receiver, | 3639 ast.Send send, HInstruction receiver, HInstruction value, |
3781 HInstruction value, | 3640 {Selector selector, TypeMask mask, ast.Node location}) { |
3782 {Selector selector, | 3641 assert(invariant(send == null ? location : send, |
3783 TypeMask mask, | |
3784 ast.Node location}) { | |
3785 assert(invariant( | |
3786 send == null ? location : send, | |
3787 send == null || Elements.isInstanceSend(send, elements), | 3642 send == null || Elements.isInstanceSend(send, elements), |
3788 message: "Unexpected instance setter" | 3643 message: "Unexpected instance setter" |
3789 "${send != null ? " element: ${elements[send]}" : ""}")); | 3644 "${send != null ? " element: ${elements[send]}" : ""}")); |
3790 if (selector == null) { | 3645 if (selector == null) { |
3791 assert(send != null); | 3646 assert(send != null); |
3792 selector = elements.getSelector(send); | 3647 selector = elements.getSelector(send); |
3793 if (mask == null) { | 3648 if (mask == null) { |
3794 mask = elements.getTypeMask(send); | 3649 mask = elements.getTypeMask(send); |
3795 } | 3650 } |
3796 } | 3651 } |
3797 if (location == null) { | 3652 if (location == null) { |
3798 assert(send != null); | 3653 assert(send != null); |
3799 location = send; | 3654 location = send; |
3800 } | 3655 } |
3801 assert(selector.isSetter); | 3656 assert(selector.isSetter); |
3802 pushInvokeDynamic(location, selector, mask, [receiver, value], | 3657 pushInvokeDynamic(location, selector, mask, [receiver, value], |
3803 sourceInformation: sourceInformationBuilder.buildAssignment(location)); | 3658 sourceInformation: sourceInformationBuilder.buildAssignment(location)); |
3804 pop(); | 3659 pop(); |
3805 stack.add(value); | 3660 stack.add(value); |
3806 } | 3661 } |
3807 | 3662 |
3808 void generateNoSuchSetter(ast.Node location, | 3663 void generateNoSuchSetter( |
3809 Element element, | 3664 ast.Node location, Element element, HInstruction value) { |
3810 HInstruction value) { | |
3811 List<HInstruction> arguments = | 3665 List<HInstruction> arguments = |
3812 value == null ? const <HInstruction>[] : <HInstruction>[value]; | 3666 value == null ? const <HInstruction>[] : <HInstruction>[value]; |
3813 // An erroneous element indicates an unresolved static setter. | 3667 // An erroneous element indicates an unresolved static setter. |
3814 generateThrowNoSuchMethod( | 3668 generateThrowNoSuchMethod( |
3815 location, noSuchMethodTargetSymbolString(element, 'set'), | 3669 location, noSuchMethodTargetSymbolString(element, 'set'), |
3816 argumentValues: arguments); | 3670 argumentValues: arguments); |
3817 } | 3671 } |
3818 | 3672 |
3819 void generateNonInstanceSetter(ast.SendSet send, | 3673 void generateNonInstanceSetter( |
3820 Element element, | 3674 ast.SendSet send, Element element, HInstruction value, |
3821 HInstruction value, | 3675 {ast.Node location}) { |
3822 {ast.Node location}) { | |
3823 if (location == null) { | 3676 if (location == null) { |
3824 assert(send != null); | 3677 assert(send != null); |
3825 location = send; | 3678 location = send; |
3826 } | 3679 } |
3827 assert(invariant(location, | 3680 assert(invariant( |
3828 send == null || !Elements.isInstanceSend(send, elements), | 3681 location, send == null || !Elements.isInstanceSend(send, elements), |
3829 message: "Unexpected non instance setter: $element.")); | 3682 message: "Unexpected non instance setter: $element.")); |
3830 if (Elements.isStaticOrTopLevelField(element)) { | 3683 if (Elements.isStaticOrTopLevelField(element)) { |
3831 if (element.isSetter) { | 3684 if (element.isSetter) { |
3832 pushInvokeStatic(location, element, <HInstruction>[value]); | 3685 pushInvokeStatic(location, element, <HInstruction>[value]); |
3833 pop(); | 3686 pop(); |
3834 } else { | 3687 } else { |
3835 VariableElement field = element; | 3688 VariableElement field = element; |
3836 value = potentiallyCheckOrTrustType(value, field.type); | 3689 value = potentiallyCheckOrTrustType(value, field.type); |
3837 addWithPosition(new HStaticStore(element, value), location); | 3690 addWithPosition(new HStaticStore(element, value), location); |
3838 } | 3691 } |
3839 stack.add(value); | 3692 stack.add(value); |
3840 } else if (Elements.isError(element)) { | 3693 } else if (Elements.isError(element)) { |
3841 generateNoSuchSetter(location, element, send == null ? null : value); | 3694 generateNoSuchSetter(location, element, send == null ? null : value); |
3842 } else if (Elements.isMalformed(element)) { | 3695 } else if (Elements.isMalformed(element)) { |
3843 // TODO(ahe): Do something like [generateWrongArgumentCountError]. | 3696 // TODO(ahe): Do something like [generateWrongArgumentCountError]. |
3844 stack.add(graph.addConstantNull(compiler)); | 3697 stack.add(graph.addConstantNull(compiler)); |
3845 } else { | 3698 } else { |
3846 stack.add(value); | 3699 stack.add(value); |
3847 LocalElement local = element; | 3700 LocalElement local = element; |
3848 // If the value does not already have a name, give it here. | 3701 // If the value does not already have a name, give it here. |
3849 if (value.sourceElement == null) { | 3702 if (value.sourceElement == null) { |
3850 value.sourceElement = local; | 3703 value.sourceElement = local; |
3851 } | 3704 } |
(...skipping 30 matching lines...) Expand all Loading... |
3882 } else { | 3735 } else { |
3883 assert(type.element.isClass); | 3736 assert(type.element.isClass); |
3884 InterfaceType interface = type; | 3737 InterfaceType interface = type; |
3885 List<HInstruction> inputs = <HInstruction>[]; | 3738 List<HInstruction> inputs = <HInstruction>[]; |
3886 List<js.Expression> templates = <js.Expression>[]; | 3739 List<js.Expression> templates = <js.Expression>[]; |
3887 for (DartType argument in interface.typeArguments) { | 3740 for (DartType argument in interface.typeArguments) { |
3888 // As we construct the template in stages, we have to make sure that for | 3741 // As we construct the template in stages, we have to make sure that for |
3889 // each part the generated sub-template's holes match the index of the | 3742 // each part the generated sub-template's holes match the index of the |
3890 // inputs that are later used to instantiate it. We do this by starting | 3743 // inputs that are later used to instantiate it. We do this by starting |
3891 // the indexing with the number of inputs from previous sub-templates. | 3744 // the indexing with the number of inputs from previous sub-templates. |
3892 templates.add( | 3745 templates.add(rtiEncoder.getTypeRepresentationWithPlaceholders(argument, |
3893 rtiEncoder.getTypeRepresentationWithPlaceholders( | 3746 (variable) { |
3894 argument, (variable) { | 3747 HInstruction runtimeType = addTypeVariableReference(variable); |
3895 HInstruction runtimeType = addTypeVariableReference(variable); | 3748 inputs.add(runtimeType); |
3896 inputs.add(runtimeType); | 3749 }, firstPlaceholderIndex: inputs.length)); |
3897 }, firstPlaceholderIndex: inputs.length)); | |
3898 } | 3750 } |
3899 // TODO(sra): This is a fresh template each time. We can't let the | 3751 // TODO(sra): This is a fresh template each time. We can't let the |
3900 // template manager build them. | 3752 // template manager build them. |
3901 js.Template code = new js.Template(null, | 3753 js.Template code = |
3902 new js.ArrayInitializer(templates)); | 3754 new js.Template(null, new js.ArrayInitializer(templates)); |
3903 HInstruction representation = | 3755 HInstruction representation = new HForeignCode( |
3904 new HForeignCode(code, backend.readableArrayType, inputs, | 3756 code, backend.readableArrayType, inputs, |
3905 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); | 3757 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); |
3906 return representation; | 3758 return representation; |
3907 } | 3759 } |
3908 } | 3760 } |
3909 | 3761 |
3910 @override | 3762 @override |
3911 void visitAs(ast.Send node, ast.Node expression, DartType type, _) { | 3763 void visitAs(ast.Send node, ast.Node expression, DartType type, _) { |
3912 HInstruction expressionInstruction = visitAndPop(expression); | 3764 HInstruction expressionInstruction = visitAndPop(expression); |
3913 if (type.isMalformed) { | 3765 if (type.isMalformed) { |
3914 ErroneousElement element = type.element; | 3766 ErroneousElement element = type.element; |
3915 generateTypeError(node, element.message); | 3767 generateTypeError(node, element.message); |
3916 } else { | 3768 } else { |
3917 HInstruction converted = buildTypeConversion( | 3769 HInstruction converted = buildTypeConversion(expressionInstruction, |
3918 expressionInstruction, | 3770 localsHandler.substInContext(type), HTypeConversion.CAST_TYPE_CHECK); |
3919 localsHandler.substInContext(type), | |
3920 HTypeConversion.CAST_TYPE_CHECK); | |
3921 if (converted != expressionInstruction) add(converted); | 3771 if (converted != expressionInstruction) add(converted); |
3922 stack.add(converted); | 3772 stack.add(converted); |
3923 } | 3773 } |
3924 } | 3774 } |
3925 | 3775 |
3926 @override | 3776 @override |
3927 void visitIs(ast.Send node, ast.Node expression, DartType type, _) { | 3777 void visitIs(ast.Send node, ast.Node expression, DartType type, _) { |
3928 HInstruction expressionInstruction = visitAndPop(expression); | 3778 HInstruction expressionInstruction = visitAndPop(expression); |
3929 push(buildIsNode(node, type, expressionInstruction)); | 3779 push(buildIsNode(node, type, expressionInstruction)); |
3930 } | 3780 } |
3931 | 3781 |
3932 @override | 3782 @override |
3933 void visitIsNot(ast.Send node, ast.Node expression, DartType type, _) { | 3783 void visitIsNot(ast.Send node, ast.Node expression, DartType type, _) { |
3934 HInstruction expressionInstruction = visitAndPop(expression); | 3784 HInstruction expressionInstruction = visitAndPop(expression); |
3935 HInstruction instruction = buildIsNode(node, type, expressionInstruction); | 3785 HInstruction instruction = buildIsNode(node, type, expressionInstruction); |
3936 add(instruction); | 3786 add(instruction); |
3937 push(new HNot(instruction, backend.boolType)); | 3787 push(new HNot(instruction, backend.boolType)); |
3938 } | 3788 } |
3939 | 3789 |
3940 HInstruction buildIsNode(ast.Node node, | 3790 HInstruction buildIsNode( |
3941 DartType type, | 3791 ast.Node node, DartType type, HInstruction expression) { |
3942 HInstruction expression) { | |
3943 type = localsHandler.substInContext(type).unaliased; | 3792 type = localsHandler.substInContext(type).unaliased; |
3944 if (type.isFunctionType) { | 3793 if (type.isFunctionType) { |
3945 List arguments = [buildFunctionType(type), expression]; | 3794 List arguments = [buildFunctionType(type), expression]; |
3946 pushInvokeDynamic( | 3795 pushInvokeDynamic( |
3947 node, | 3796 node, |
3948 new Selector.call( | 3797 new Selector.call(new PrivateName('_isTest', helpers.jsHelperLibrary), |
3949 new PrivateName('_isTest', helpers.jsHelperLibrary), | |
3950 CallStructure.ONE_ARG), | 3798 CallStructure.ONE_ARG), |
3951 null, | 3799 null, |
3952 arguments); | 3800 arguments); |
3953 return new HIs.compound(type, expression, pop(), backend.boolType); | 3801 return new HIs.compound(type, expression, pop(), backend.boolType); |
3954 } else if (type.isTypeVariable) { | 3802 } else if (type.isTypeVariable) { |
3955 HInstruction runtimeType = addTypeVariableReference(type); | 3803 HInstruction runtimeType = addTypeVariableReference(type); |
3956 Element helper = helpers.checkSubtypeOfRuntimeType; | 3804 Element helper = helpers.checkSubtypeOfRuntimeType; |
3957 List<HInstruction> inputs = <HInstruction>[expression, runtimeType]; | 3805 List<HInstruction> inputs = <HInstruction>[expression, runtimeType]; |
3958 pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType); | 3806 pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType); |
3959 HInstruction call = pop(); | 3807 HInstruction call = pop(); |
3960 return new HIs.variable(type, expression, call, backend.boolType); | 3808 return new HIs.variable(type, expression, call, backend.boolType); |
3961 } else if (RuntimeTypes.hasTypeArguments(type)) { | 3809 } else if (RuntimeTypes.hasTypeArguments(type)) { |
3962 ClassElement element = type.element; | 3810 ClassElement element = type.element; |
3963 Element helper = helpers.checkSubtype; | 3811 Element helper = helpers.checkSubtype; |
3964 HInstruction representations = | 3812 HInstruction representations = buildTypeArgumentRepresentations(type); |
3965 buildTypeArgumentRepresentations(type); | |
3966 add(representations); | 3813 add(representations); |
3967 js.Name operator = backend.namer.operatorIs(element); | 3814 js.Name operator = backend.namer.operatorIs(element); |
3968 HInstruction isFieldName = addConstantStringFromName(operator); | 3815 HInstruction isFieldName = addConstantStringFromName(operator); |
3969 HInstruction asFieldName = compiler.world.hasAnyStrictSubtype(element) | 3816 HInstruction asFieldName = compiler.world.hasAnyStrictSubtype(element) |
3970 ? addConstantStringFromName(backend.namer.substitutionName(element)) | 3817 ? addConstantStringFromName(backend.namer.substitutionName(element)) |
3971 : graph.addConstantNull(compiler); | 3818 : graph.addConstantNull(compiler); |
3972 List<HInstruction> inputs = <HInstruction>[expression, | 3819 List<HInstruction> inputs = <HInstruction>[ |
3973 isFieldName, | 3820 expression, |
3974 representations, | 3821 isFieldName, |
3975 asFieldName]; | 3822 representations, |
| 3823 asFieldName |
| 3824 ]; |
3976 pushInvokeStatic(node, helper, inputs, typeMask: backend.boolType); | 3825 pushInvokeStatic(node, helper, inputs, typeMask: backend.boolType); |
3977 HInstruction call = pop(); | 3826 HInstruction call = pop(); |
3978 return new HIs.compound(type, expression, call, backend.boolType); | 3827 return new HIs.compound(type, expression, call, backend.boolType); |
3979 } else if (type.isMalformed) { | 3828 } else if (type.isMalformed) { |
3980 ErroneousElement element = type.element; | 3829 ErroneousElement element = type.element; |
3981 generateTypeError(node, element.message); | 3830 generateTypeError(node, element.message); |
3982 HInstruction call = pop(); | 3831 HInstruction call = pop(); |
3983 return new HIs.compound(type, expression, call, backend.boolType); | 3832 return new HIs.compound(type, expression, call, backend.boolType); |
3984 } else { | 3833 } else { |
3985 if (backend.hasDirectCheckFor(type)) { | 3834 if (backend.hasDirectCheckFor(type)) { |
(...skipping 13 matching lines...) Expand all Loading... |
3999 | 3848 |
4000 void addDynamicSendArgumentsToList(ast.Send node, List<HInstruction> list) { | 3849 void addDynamicSendArgumentsToList(ast.Send node, List<HInstruction> list) { |
4001 CallStructure callStructure = elements.getSelector(node).callStructure; | 3850 CallStructure callStructure = elements.getSelector(node).callStructure; |
4002 if (callStructure.namedArgumentCount == 0) { | 3851 if (callStructure.namedArgumentCount == 0) { |
4003 addGenericSendArgumentsToList(node.arguments, list); | 3852 addGenericSendArgumentsToList(node.arguments, list); |
4004 } else { | 3853 } else { |
4005 // Visit positional arguments and add them to the list. | 3854 // Visit positional arguments and add them to the list. |
4006 Link<ast.Node> arguments = node.arguments; | 3855 Link<ast.Node> arguments = node.arguments; |
4007 int positionalArgumentCount = callStructure.positionalArgumentCount; | 3856 int positionalArgumentCount = callStructure.positionalArgumentCount; |
4008 for (int i = 0; | 3857 for (int i = 0; |
4009 i < positionalArgumentCount; | 3858 i < positionalArgumentCount; |
4010 arguments = arguments.tail, i++) { | 3859 arguments = arguments.tail, i++) { |
4011 visit(arguments.head); | 3860 visit(arguments.head); |
4012 list.add(pop()); | 3861 list.add(pop()); |
4013 } | 3862 } |
4014 | 3863 |
4015 // Visit named arguments and add them into a temporary map. | 3864 // Visit named arguments and add them into a temporary map. |
4016 Map<String, HInstruction> instructions = | 3865 Map<String, HInstruction> instructions = new Map<String, HInstruction>(); |
4017 new Map<String, HInstruction>(); | |
4018 List<String> namedArguments = callStructure.namedArguments; | 3866 List<String> namedArguments = callStructure.namedArguments; |
4019 int nameIndex = 0; | 3867 int nameIndex = 0; |
4020 for (; !arguments.isEmpty; arguments = arguments.tail) { | 3868 for (; !arguments.isEmpty; arguments = arguments.tail) { |
4021 visit(arguments.head); | 3869 visit(arguments.head); |
4022 instructions[namedArguments[nameIndex++]] = pop(); | 3870 instructions[namedArguments[nameIndex++]] = pop(); |
4023 } | 3871 } |
4024 | 3872 |
4025 // Iterate through the named arguments to add them to the list | 3873 // Iterate through the named arguments to add them to the list |
4026 // of instructions, in an order that can be shared with | 3874 // of instructions, in an order that can be shared with |
4027 // selectors with the same named arguments. | 3875 // selectors with the same named arguments. |
4028 List<String> orderedNames = callStructure.getOrderedNamedArguments(); | 3876 List<String> orderedNames = callStructure.getOrderedNamedArguments(); |
4029 for (String name in orderedNames) { | 3877 for (String name in orderedNames) { |
4030 list.add(instructions[name]); | 3878 list.add(instructions[name]); |
4031 } | 3879 } |
4032 } | 3880 } |
4033 } | 3881 } |
4034 | 3882 |
4035 /** | 3883 /** |
4036 * Returns a list with the evaluated [arguments] in the normalized order. | 3884 * Returns a list with the evaluated [arguments] in the normalized order. |
4037 * | 3885 * |
4038 * Precondition: `this.applies(element, world)`. | 3886 * Precondition: `this.applies(element, world)`. |
4039 * Invariant: [element] must be an implementation element. | 3887 * Invariant: [element] must be an implementation element. |
4040 */ | 3888 */ |
4041 List<HInstruction> makeStaticArgumentList(CallStructure callStructure, | 3889 List<HInstruction> makeStaticArgumentList(CallStructure callStructure, |
4042 Link<ast.Node> arguments, | 3890 Link<ast.Node> arguments, FunctionElement element) { |
4043 FunctionElement element) { | |
4044 assert(invariant(element, element.isImplementation)); | 3891 assert(invariant(element, element.isImplementation)); |
4045 | 3892 |
4046 HInstruction compileArgument(ast.Node argument) { | 3893 HInstruction compileArgument(ast.Node argument) { |
4047 visit(argument); | 3894 visit(argument); |
4048 return pop(); | 3895 return pop(); |
4049 } | 3896 } |
4050 | 3897 |
4051 return callStructure.makeArgumentsList( | 3898 return callStructure.makeArgumentsList( |
4052 arguments, | 3899 arguments, |
4053 element, | 3900 element, |
4054 compileArgument, | 3901 compileArgument, |
4055 backend.isJsInterop(element) ? | 3902 backend.isJsInterop(element) |
4056 handleConstantForOptionalParameterJsInterop : | 3903 ? handleConstantForOptionalParameterJsInterop |
4057 handleConstantForOptionalParameter); | 3904 : handleConstantForOptionalParameter); |
4058 } | 3905 } |
4059 | 3906 |
4060 void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> lis
t) { | 3907 void addGenericSendArgumentsToList( |
| 3908 Link<ast.Node> link, List<HInstruction> list) { |
4061 for (; !link.isEmpty; link = link.tail) { | 3909 for (; !link.isEmpty; link = link.tail) { |
4062 visit(link.head); | 3910 visit(link.head); |
4063 list.add(pop()); | 3911 list.add(pop()); |
4064 } | 3912 } |
4065 } | 3913 } |
4066 | 3914 |
4067 /// Generate a dynamic method, getter or setter invocation. | 3915 /// Generate a dynamic method, getter or setter invocation. |
4068 void generateDynamicSend(ast.Send node) { | 3916 void generateDynamicSend(ast.Send node) { |
4069 HInstruction receiver = generateInstanceSendReceiver(node); | 3917 HInstruction receiver = generateInstanceSendReceiver(node); |
4070 _generateDynamicSend(node, receiver); | 3918 _generateDynamicSend(node, receiver); |
4071 } | 3919 } |
4072 | 3920 |
4073 void _generateDynamicSend(ast.Send node, HInstruction receiver) { | 3921 void _generateDynamicSend(ast.Send node, HInstruction receiver) { |
4074 Selector selector = elements.getSelector(node); | 3922 Selector selector = elements.getSelector(node); |
4075 TypeMask mask = elements.getTypeMask(node); | 3923 TypeMask mask = elements.getTypeMask(node); |
4076 SourceInformation sourceInformation = | 3924 SourceInformation sourceInformation = |
4077 sourceInformationBuilder.buildCall(node, node.selector); | 3925 sourceInformationBuilder.buildCall(node, node.selector); |
4078 | 3926 |
4079 List<HInstruction> inputs = <HInstruction>[]; | 3927 List<HInstruction> inputs = <HInstruction>[]; |
4080 inputs.add(receiver); | 3928 inputs.add(receiver); |
4081 addDynamicSendArgumentsToList(node, inputs); | 3929 addDynamicSendArgumentsToList(node, inputs); |
4082 | 3930 |
4083 pushInvokeDynamic(node, selector, mask, inputs, | 3931 pushInvokeDynamic(node, selector, mask, inputs, |
4084 sourceInformation: sourceInformation); | 3932 sourceInformation: sourceInformation); |
4085 if (selector.isSetter || selector.isIndexSet) { | 3933 if (selector.isSetter || selector.isIndexSet) { |
4086 pop(); | 3934 pop(); |
4087 stack.add(inputs.last); | 3935 stack.add(inputs.last); |
4088 } | 3936 } |
4089 } | 3937 } |
4090 | 3938 |
4091 @override | 3939 @override |
4092 visitDynamicPropertyInvoke( | 3940 visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
4093 ast.Send node, | 3941 ast.NodeList arguments, Selector selector, _) { |
4094 ast.Node receiver, | |
4095 ast.NodeList arguments, | |
4096 Selector selector, | |
4097 _) { | |
4098 generateDynamicSend(node); | 3942 generateDynamicSend(node); |
4099 } | 3943 } |
4100 | 3944 |
4101 @override | 3945 @override |
4102 visitIfNotNullDynamicPropertyInvoke( | 3946 visitIfNotNullDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
4103 ast.Send node, | 3947 ast.NodeList arguments, Selector selector, _) { |
4104 ast.Node receiver, | |
4105 ast.NodeList arguments, | |
4106 Selector selector, | |
4107 _) { | |
4108 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` | 3948 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` |
4109 HInstruction receiver; | 3949 HInstruction receiver; |
4110 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3950 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
4111 brancher.handleConditional( | 3951 brancher.handleConditional(() { |
4112 () { | 3952 receiver = generateInstanceSendReceiver(node); |
4113 receiver = generateInstanceSendReceiver(node); | 3953 pushCheckNull(receiver); |
4114 pushCheckNull(receiver); | 3954 }, () => stack.add(receiver), () => _generateDynamicSend(node, receiver)); |
4115 }, | |
4116 () => stack.add(receiver), | |
4117 () => _generateDynamicSend(node, receiver)); | |
4118 } | 3955 } |
4119 | 3956 |
4120 @override | 3957 @override |
4121 visitThisPropertyInvoke( | 3958 visitThisPropertyInvoke( |
4122 ast.Send node, | 3959 ast.Send node, ast.NodeList arguments, Selector selector, _) { |
4123 ast.NodeList arguments, | |
4124 Selector selector, | |
4125 _) { | |
4126 generateDynamicSend(node); | 3960 generateDynamicSend(node); |
4127 } | 3961 } |
4128 | 3962 |
4129 @override | 3963 @override |
4130 visitExpressionInvoke( | 3964 visitExpressionInvoke(ast.Send node, ast.Node expression, |
4131 ast.Send node, | 3965 ast.NodeList arguments, CallStructure callStructure, _) { |
4132 ast.Node expression, | 3966 generateCallInvoke(node, visitAndPop(expression), |
4133 ast.NodeList arguments, | |
4134 CallStructure callStructure, | |
4135 _) { | |
4136 generateCallInvoke( | |
4137 node, | |
4138 visitAndPop(expression), | |
4139 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3967 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
4140 } | 3968 } |
4141 | 3969 |
4142 @override | 3970 @override |
4143 visitThisInvoke( | 3971 visitThisInvoke( |
4144 ast.Send node, | 3972 ast.Send node, ast.NodeList arguments, CallStructure callStructure, _) { |
4145 ast.NodeList arguments, | 3973 generateCallInvoke(node, localsHandler.readThis(), |
4146 CallStructure callStructure, | |
4147 _) { | |
4148 generateCallInvoke( | |
4149 node, | |
4150 localsHandler.readThis(), | |
4151 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3974 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
4152 } | 3975 } |
4153 | 3976 |
4154 @override | 3977 @override |
4155 visitParameterInvoke( | 3978 visitParameterInvoke(ast.Send node, ParameterElement parameter, |
4156 ast.Send node, | 3979 ast.NodeList arguments, CallStructure callStructure, _) { |
4157 ParameterElement parameter, | 3980 generateCallInvoke(node, localsHandler.readLocal(parameter), |
4158 ast.NodeList arguments, | |
4159 CallStructure callStructure, | |
4160 _) { | |
4161 generateCallInvoke( | |
4162 node, | |
4163 localsHandler.readLocal(parameter), | |
4164 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3981 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
4165 } | 3982 } |
4166 | 3983 |
4167 @override | 3984 @override |
4168 visitLocalVariableInvoke( | 3985 visitLocalVariableInvoke(ast.Send node, LocalVariableElement variable, |
4169 ast.Send node, | 3986 ast.NodeList arguments, CallStructure callStructure, _) { |
4170 LocalVariableElement variable, | 3987 generateCallInvoke(node, localsHandler.readLocal(variable), |
4171 ast.NodeList arguments, | |
4172 CallStructure callStructure, | |
4173 _) { | |
4174 generateCallInvoke( | |
4175 node, | |
4176 localsHandler.readLocal(variable), | |
4177 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3988 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
4178 } | 3989 } |
4179 | 3990 |
4180 @override | 3991 @override |
4181 visitLocalFunctionInvoke( | 3992 visitLocalFunctionInvoke(ast.Send node, LocalFunctionElement function, |
4182 ast.Send node, | 3993 ast.NodeList arguments, CallStructure callStructure, _) { |
4183 LocalFunctionElement function, | 3994 generateCallInvoke(node, localsHandler.readLocal(function), |
4184 ast.NodeList arguments, | |
4185 CallStructure callStructure, | |
4186 _) { | |
4187 generateCallInvoke( | |
4188 node, | |
4189 localsHandler.readLocal(function), | |
4190 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3995 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
4191 } | 3996 } |
4192 | 3997 |
4193 @override | 3998 @override |
4194 visitLocalFunctionIncompatibleInvoke( | 3999 visitLocalFunctionIncompatibleInvoke( |
4195 ast.Send node, | 4000 ast.Send node, |
4196 LocalFunctionElement function, | 4001 LocalFunctionElement function, |
4197 ast.NodeList arguments, | 4002 ast.NodeList arguments, |
4198 CallStructure callStructure, | 4003 CallStructure callStructure, |
4199 _) { | 4004 _) { |
4200 generateCallInvoke(node, localsHandler.readLocal(function), | 4005 generateCallInvoke(node, localsHandler.readLocal(function), |
4201 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 4006 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
4202 } | 4007 } |
4203 | 4008 |
4204 void handleForeignJs(ast.Send node) { | 4009 void handleForeignJs(ast.Send node) { |
4205 Link<ast.Node> link = node.arguments; | 4010 Link<ast.Node> link = node.arguments; |
4206 // Don't visit the first argument, which is the type, and the second | 4011 // Don't visit the first argument, which is the type, and the second |
4207 // argument, which is the foreign code. | 4012 // argument, which is the foreign code. |
4208 if (link.isEmpty || link.tail.isEmpty) { | 4013 if (link.isEmpty || link.tail.isEmpty) { |
4209 // We should not get here because the call should be compiled to NSM. | 4014 // We should not get here because the call should be compiled to NSM. |
4210 reporter.internalError(node.argumentsNode, | 4015 reporter.internalError( |
4211 'At least two arguments expected.'); | 4016 node.argumentsNode, 'At least two arguments expected.'); |
4212 } | 4017 } |
4213 native.NativeBehavior nativeBehavior = | 4018 native.NativeBehavior nativeBehavior = |
4214 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | 4019 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); |
4215 | 4020 |
4216 List<HInstruction> inputs = <HInstruction>[]; | 4021 List<HInstruction> inputs = <HInstruction>[]; |
4217 addGenericSendArgumentsToList(link.tail.tail, inputs); | 4022 addGenericSendArgumentsToList(link.tail.tail, inputs); |
4218 | 4023 |
4219 if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) { | 4024 if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) { |
4220 reporter.reportErrorMessage( | 4025 reporter.reportErrorMessage(node, MessageKind.GENERIC, { |
4221 node, MessageKind.GENERIC, | 4026 'text': 'Mismatch between number of placeholders' |
4222 {'text': | 4027 ' and number of arguments.' |
4223 'Mismatch between number of placeholders' | 4028 }); |
4224 ' and number of arguments.'}); | 4029 stack.add(graph.addConstantNull(compiler)); // Result expected on stack. |
4225 stack.add(graph.addConstantNull(compiler)); // Result expected on stack. | |
4226 return; | 4030 return; |
4227 } | 4031 } |
4228 | 4032 |
4229 if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) { | 4033 if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) { |
4230 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE); | 4034 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE); |
4231 } | 4035 } |
4232 | 4036 |
4233 TypeMask ssaType = | 4037 TypeMask ssaType = |
4234 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); | 4038 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); |
4235 | 4039 |
4236 SourceInformation sourceInformation = | 4040 SourceInformation sourceInformation = |
4237 sourceInformationBuilder.buildCall(node, node.argumentsNode); | 4041 sourceInformationBuilder.buildCall(node, node.argumentsNode); |
4238 if (nativeBehavior.codeTemplate.isExpression) { | 4042 if (nativeBehavior.codeTemplate.isExpression) { |
4239 push(new HForeignCode( | 4043 push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs, |
4240 nativeBehavior.codeTemplate, ssaType, inputs, | 4044 effects: nativeBehavior.sideEffects, nativeBehavior: nativeBehavior) |
4241 effects: nativeBehavior.sideEffects, | 4045 ..sourceInformation = sourceInformation); |
4242 nativeBehavior: nativeBehavior) | |
4243 ..sourceInformation = sourceInformation); | |
4244 } else { | 4046 } else { |
4245 push(new HForeignCode( | 4047 push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs, |
4246 nativeBehavior.codeTemplate, ssaType, inputs, | |
4247 isStatement: true, | 4048 isStatement: true, |
4248 effects: nativeBehavior.sideEffects, | 4049 effects: nativeBehavior.sideEffects, |
4249 nativeBehavior: nativeBehavior) | 4050 nativeBehavior: nativeBehavior) |
4250 ..sourceInformation = sourceInformation); | 4051 ..sourceInformation = sourceInformation); |
4251 } | 4052 } |
4252 } | 4053 } |
4253 | 4054 |
4254 void handleJsStringConcat(ast.Send node) { | 4055 void handleJsStringConcat(ast.Send node) { |
4255 List<HInstruction> inputs = <HInstruction>[]; | 4056 List<HInstruction> inputs = <HInstruction>[]; |
4256 addGenericSendArgumentsToList(node.arguments, inputs); | 4057 addGenericSendArgumentsToList(node.arguments, inputs); |
4257 if (inputs.length != 2) { | 4058 if (inputs.length != 2) { |
4258 reporter.internalError(node.argumentsNode, 'Two arguments expected.'); | 4059 reporter.internalError(node.argumentsNode, 'Two arguments expected.'); |
4259 } | 4060 } |
4260 push(new HStringConcat(inputs[0], inputs[1], backend.stringType)); | 4061 push(new HStringConcat(inputs[0], inputs[1], backend.stringType)); |
4261 } | 4062 } |
4262 | 4063 |
4263 void handleForeignJsCurrentIsolateContext(ast.Send node) { | 4064 void handleForeignJsCurrentIsolateContext(ast.Send node) { |
4264 if (!node.arguments.isEmpty) { | 4065 if (!node.arguments.isEmpty) { |
4265 reporter.internalError(node, | 4066 reporter.internalError( |
4266 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.'); | 4067 node, 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.'); |
4267 } | 4068 } |
4268 | 4069 |
4269 if (!compiler.hasIsolateSupport) { | 4070 if (!compiler.hasIsolateSupport) { |
4270 // If the isolate library is not used, we just generate code | 4071 // If the isolate library is not used, we just generate code |
4271 // to fetch the static state. | 4072 // to fetch the static state. |
4272 String name = backend.namer.staticStateHolder; | 4073 String name = backend.namer.staticStateHolder; |
4273 push(new HForeignCode( | 4074 push(new HForeignCode( |
4274 js.js.parseForeignJS(name), | 4075 js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[], |
4275 backend.dynamicType, | |
4276 <HInstruction>[], | |
4277 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); | 4076 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); |
4278 } else { | 4077 } else { |
4279 // Call a helper method from the isolate library. The isolate | 4078 // Call a helper method from the isolate library. The isolate |
4280 // library uses its own isolate structure, that encapsulates | 4079 // library uses its own isolate structure, that encapsulates |
4281 // Leg's isolate. | 4080 // Leg's isolate. |
4282 Element element = helpers.currentIsolate; | 4081 Element element = helpers.currentIsolate; |
4283 if (element == null) { | 4082 if (element == null) { |
4284 reporter.internalError(node, | 4083 reporter.internalError(node, 'Isolate library and compiler mismatch.'); |
4285 'Isolate library and compiler mismatch.'); | |
4286 } | 4084 } |
4287 pushInvokeStatic(null, element, [], typeMask: backend.dynamicType); | 4085 pushInvokeStatic(null, element, [], typeMask: backend.dynamicType); |
4288 } | 4086 } |
4289 } | 4087 } |
4290 | 4088 |
4291 void handleForeignJsGetFlag(ast.Send node) { | 4089 void handleForeignJsGetFlag(ast.Send node) { |
4292 List<ast.Node> arguments = node.arguments.toList(); | 4090 List<ast.Node> arguments = node.arguments.toList(); |
4293 ast.Node argument; | 4091 ast.Node argument; |
4294 switch (arguments.length) { | 4092 switch (arguments.length) { |
4295 case 0: | 4093 case 0: |
4296 reporter.reportErrorMessage( | 4094 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
4297 node, MessageKind.GENERIC, | 4095 {'text': 'Error: Expected one argument to JS_GET_FLAG.'}); |
4298 {'text': 'Error: Expected one argument to JS_GET_FLAG.'}); | 4096 return; |
4299 return; | 4097 case 1: |
4300 case 1: | 4098 argument = arguments[0]; |
4301 argument = arguments[0]; | 4099 break; |
4302 break; | 4100 default: |
4303 default: | 4101 for (int i = 1; i < arguments.length; i++) { |
4304 for (int i = 1; i < arguments.length; i++) { | 4102 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC, |
4305 reporter.reportErrorMessage( | 4103 {'text': 'Error: Extra argument to JS_GET_FLAG.'}); |
4306 arguments[i], MessageKind.GENERIC, | 4104 } |
4307 {'text': 'Error: Extra argument to JS_GET_FLAG.'}); | 4105 return; |
4308 } | 4106 } |
4309 return; | 4107 ast.LiteralString string = argument.asLiteralString(); |
4310 } | 4108 if (string == null) { |
4311 ast.LiteralString string = argument.asLiteralString(); | 4109 reporter.reportErrorMessage(argument, MessageKind.GENERIC, |
4312 if (string == null) { | 4110 {'text': 'Error: Expected a literal string.'}); |
4313 reporter.reportErrorMessage( | 4111 } |
4314 argument, MessageKind.GENERIC, | 4112 String name = string.dartString.slowToString(); |
4315 {'text': 'Error: Expected a literal string.'}); | 4113 bool value = false; |
4316 } | 4114 switch (name) { |
4317 String name = string.dartString.slowToString(); | 4115 case 'MUST_RETAIN_METADATA': |
4318 bool value = false; | 4116 value = backend.mustRetainMetadata; |
4319 switch (name) { | 4117 break; |
4320 case 'MUST_RETAIN_METADATA': | 4118 case 'USE_CONTENT_SECURITY_POLICY': |
4321 value = backend.mustRetainMetadata; | 4119 value = compiler.options.useContentSecurityPolicy; |
4322 break; | 4120 break; |
4323 case 'USE_CONTENT_SECURITY_POLICY': | 4121 default: |
4324 value = compiler.options.useContentSecurityPolicy; | 4122 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
4325 break; | 4123 {'text': 'Error: Unknown internal flag "$name".'}); |
4326 default: | 4124 } |
4327 reporter.reportErrorMessage( | 4125 stack.add(graph.addConstantBool(value, compiler)); |
4328 node, MessageKind.GENERIC, | |
4329 {'text': 'Error: Unknown internal flag "$name".'}); | |
4330 } | |
4331 stack.add(graph.addConstantBool(value, compiler)); | |
4332 } | 4126 } |
4333 | 4127 |
4334 void handleForeignJsGetName(ast.Send node) { | 4128 void handleForeignJsGetName(ast.Send node) { |
4335 List<ast.Node> arguments = node.arguments.toList(); | 4129 List<ast.Node> arguments = node.arguments.toList(); |
4336 ast.Node argument; | 4130 ast.Node argument; |
4337 switch (arguments.length) { | 4131 switch (arguments.length) { |
4338 case 0: | 4132 case 0: |
4339 reporter.reportErrorMessage( | 4133 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
4340 node, MessageKind.GENERIC, | 4134 {'text': 'Error: Expected one argument to JS_GET_NAME.'}); |
4341 {'text': 'Error: Expected one argument to JS_GET_NAME.'}); | 4135 return; |
4342 return; | 4136 case 1: |
4343 case 1: | 4137 argument = arguments[0]; |
4344 argument = arguments[0]; | 4138 break; |
4345 break; | 4139 default: |
4346 default: | 4140 for (int i = 1; i < arguments.length; i++) { |
4347 for (int i = 1; i < arguments.length; i++) { | 4141 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC, |
4348 reporter.reportErrorMessage( | 4142 {'text': 'Error: Extra argument to JS_GET_NAME.'}); |
4349 arguments[i], MessageKind.GENERIC, | 4143 } |
4350 {'text': 'Error: Extra argument to JS_GET_NAME.'}); | 4144 return; |
4351 } | |
4352 return; | |
4353 } | 4145 } |
4354 Element element = elements[argument]; | 4146 Element element = elements[argument]; |
4355 if (element == null || | 4147 if (element == null || |
4356 element is! FieldElement || | 4148 element is! FieldElement || |
4357 element.enclosingClass != helpers.jsGetNameEnum) { | 4149 element.enclosingClass != helpers.jsGetNameEnum) { |
4358 reporter.reportErrorMessage( | 4150 reporter.reportErrorMessage(argument, MessageKind.GENERIC, |
4359 argument, MessageKind.GENERIC, | |
4360 {'text': 'Error: Expected a JsGetName enum value.'}); | 4151 {'text': 'Error: Expected a JsGetName enum value.'}); |
4361 } | 4152 } |
4362 EnumClassElement enumClass = element.enclosingClass; | 4153 EnumClassElement enumClass = element.enclosingClass; |
4363 int index = enumClass.enumValues.indexOf(element); | 4154 int index = enumClass.enumValues.indexOf(element); |
4364 stack.add( | 4155 stack.add(addConstantStringFromName( |
4365 addConstantStringFromName( | 4156 backend.namer.getNameForJsGetName(argument, JsGetName.values[index]))); |
4366 backend.namer.getNameForJsGetName( | |
4367 argument, JsGetName.values[index]))); | |
4368 } | 4157 } |
4369 | 4158 |
4370 void handleForeignJsBuiltin(ast.Send node) { | 4159 void handleForeignJsBuiltin(ast.Send node) { |
4371 List<ast.Node> arguments = node.arguments.toList(); | 4160 List<ast.Node> arguments = node.arguments.toList(); |
4372 ast.Node argument; | 4161 ast.Node argument; |
4373 if (arguments.length < 2) { | 4162 if (arguments.length < 2) { |
4374 reporter.reportErrorMessage( | 4163 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
4375 node, MessageKind.GENERIC, | |
4376 {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'}); | 4164 {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'}); |
4377 } | 4165 } |
4378 | 4166 |
4379 Element builtinElement = elements[arguments[1]]; | 4167 Element builtinElement = elements[arguments[1]]; |
4380 if (builtinElement == null || | 4168 if (builtinElement == null || |
4381 (builtinElement is! FieldElement) || | 4169 (builtinElement is! FieldElement) || |
4382 builtinElement.enclosingClass != helpers.jsBuiltinEnum) { | 4170 builtinElement.enclosingClass != helpers.jsBuiltinEnum) { |
4383 reporter.reportErrorMessage( | 4171 reporter.reportErrorMessage(argument, MessageKind.GENERIC, |
4384 argument, MessageKind.GENERIC, | |
4385 {'text': 'Error: Expected a JsBuiltin enum value.'}); | 4172 {'text': 'Error: Expected a JsBuiltin enum value.'}); |
4386 } | 4173 } |
4387 EnumClassElement enumClass = builtinElement.enclosingClass; | 4174 EnumClassElement enumClass = builtinElement.enclosingClass; |
4388 int index = enumClass.enumValues.indexOf(builtinElement); | 4175 int index = enumClass.enumValues.indexOf(builtinElement); |
4389 | 4176 |
4390 js.Template template = | 4177 js.Template template = |
4391 backend.emitter.builtinTemplateFor(JsBuiltin.values[index]); | 4178 backend.emitter.builtinTemplateFor(JsBuiltin.values[index]); |
4392 | 4179 |
4393 List<HInstruction> compiledArguments = <HInstruction>[]; | 4180 List<HInstruction> compiledArguments = <HInstruction>[]; |
4394 for (int i = 2; i < arguments.length; i++) { | 4181 for (int i = 2; i < arguments.length; i++) { |
4395 visit(arguments[i]); | 4182 visit(arguments[i]); |
4396 compiledArguments.add(pop()); | 4183 compiledArguments.add(pop()); |
4397 } | 4184 } |
4398 | 4185 |
4399 native.NativeBehavior nativeBehavior = | 4186 native.NativeBehavior nativeBehavior = |
4400 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | 4187 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); |
4401 | 4188 |
4402 TypeMask ssaType = | 4189 TypeMask ssaType = |
4403 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); | 4190 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); |
4404 | 4191 |
4405 push(new HForeignCode(template, | 4192 push(new HForeignCode(template, ssaType, compiledArguments, |
4406 ssaType, | 4193 nativeBehavior: nativeBehavior)); |
4407 compiledArguments, | |
4408 nativeBehavior: nativeBehavior)); | |
4409 } | 4194 } |
4410 | 4195 |
4411 void handleForeignJsEmbeddedGlobal(ast.Send node) { | 4196 void handleForeignJsEmbeddedGlobal(ast.Send node) { |
4412 List<ast.Node> arguments = node.arguments.toList(); | 4197 List<ast.Node> arguments = node.arguments.toList(); |
4413 ast.Node globalNameNode; | 4198 ast.Node globalNameNode; |
4414 switch (arguments.length) { | 4199 switch (arguments.length) { |
4415 case 0: | 4200 case 0: |
4416 case 1: | 4201 case 1: |
4417 reporter.reportErrorMessage( | 4202 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
4418 node, MessageKind.GENERIC, | 4203 {'text': 'Error: Expected two arguments to JS_EMBEDDED_GLOBAL.'}); |
4419 {'text': 'Error: Expected two arguments to JS_EMBEDDED_GLOBAL.'}); | 4204 return; |
4420 return; | 4205 case 2: |
4421 case 2: | 4206 // The type has been extracted earlier. We are only interested in the |
4422 // The type has been extracted earlier. We are only interested in the | 4207 // name in this function. |
4423 // name in this function. | 4208 globalNameNode = arguments[1]; |
4424 globalNameNode = arguments[1]; | 4209 break; |
4425 break; | 4210 default: |
4426 default: | 4211 for (int i = 2; i < arguments.length; i++) { |
4427 for (int i = 2; i < arguments.length; i++) { | 4212 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC, |
4428 reporter.reportErrorMessage( | 4213 {'text': 'Error: Extra argument to JS_EMBEDDED_GLOBAL.'}); |
4429 arguments[i], MessageKind.GENERIC, | 4214 } |
4430 {'text': 'Error: Extra argument to JS_EMBEDDED_GLOBAL.'}); | 4215 return; |
4431 } | |
4432 return; | |
4433 } | 4216 } |
4434 visit(globalNameNode); | 4217 visit(globalNameNode); |
4435 HInstruction globalNameHNode = pop(); | 4218 HInstruction globalNameHNode = pop(); |
4436 if (!globalNameHNode.isConstantString()) { | 4219 if (!globalNameHNode.isConstantString()) { |
4437 reporter.reportErrorMessage( | 4220 reporter.reportErrorMessage(arguments[1], MessageKind.GENERIC, { |
4438 arguments[1], MessageKind.GENERIC, | 4221 'text': 'Error: Expected String as second argument ' |
4439 {'text': 'Error: Expected String as second argument ' | 4222 'to JS_EMBEDDED_GLOBAL.' |
4440 'to JS_EMBEDDED_GLOBAL.'}); | 4223 }); |
4441 return; | 4224 return; |
4442 } | 4225 } |
4443 HConstant hConstant = globalNameHNode; | 4226 HConstant hConstant = globalNameHNode; |
4444 StringConstantValue constant = hConstant.constant; | 4227 StringConstantValue constant = hConstant.constant; |
4445 String globalName = constant.primitiveValue.slowToString(); | 4228 String globalName = constant.primitiveValue.slowToString(); |
4446 js.Template expr = js.js.expressionTemplateYielding( | 4229 js.Template expr = js.js.expressionTemplateYielding( |
4447 backend.emitter.generateEmbeddedGlobalAccess(globalName)); | 4230 backend.emitter.generateEmbeddedGlobalAccess(globalName)); |
4448 native.NativeBehavior nativeBehavior = | 4231 native.NativeBehavior nativeBehavior = |
4449 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | 4232 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); |
4450 TypeMask ssaType = | 4233 TypeMask ssaType = |
4451 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); | 4234 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); |
4452 push(new HForeignCode(expr, ssaType, const [], | 4235 push(new HForeignCode(expr, ssaType, const [], |
4453 nativeBehavior: nativeBehavior)); | 4236 nativeBehavior: nativeBehavior)); |
4454 } | 4237 } |
4455 | 4238 |
4456 void handleJsInterceptorConstant(ast.Send node) { | 4239 void handleJsInterceptorConstant(ast.Send node) { |
4457 // Single argument must be a TypeConstant which is converted into a | 4240 // Single argument must be a TypeConstant which is converted into a |
4458 // InterceptorConstant. | 4241 // InterceptorConstant. |
4459 if (!node.arguments.isEmpty && node.arguments.tail.isEmpty) { | 4242 if (!node.arguments.isEmpty && node.arguments.tail.isEmpty) { |
4460 ast.Node argument = node.arguments.head; | 4243 ast.Node argument = node.arguments.head; |
4461 visit(argument); | 4244 visit(argument); |
4462 HInstruction argumentInstruction = pop(); | 4245 HInstruction argumentInstruction = pop(); |
4463 if (argumentInstruction is HConstant) { | 4246 if (argumentInstruction is HConstant) { |
4464 ConstantValue argumentConstant = argumentInstruction.constant; | 4247 ConstantValue argumentConstant = argumentInstruction.constant; |
4465 if (argumentConstant is TypeConstantValue) { | 4248 if (argumentConstant is TypeConstantValue) { |
4466 ConstantValue constant = | 4249 ConstantValue constant = |
4467 new InterceptorConstantValue(argumentConstant.representedType); | 4250 new InterceptorConstantValue(argumentConstant.representedType); |
4468 HInstruction instruction = graph.addConstant(constant, compiler); | 4251 HInstruction instruction = graph.addConstant(constant, compiler); |
4469 stack.add(instruction); | 4252 stack.add(instruction); |
4470 return; | 4253 return; |
4471 } | 4254 } |
4472 } | 4255 } |
4473 } | 4256 } |
4474 reporter.reportErrorMessage( | 4257 reporter.reportErrorMessage( |
4475 node, | 4258 node, MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
4476 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | |
4477 stack.add(graph.addConstantNull(compiler)); | 4259 stack.add(graph.addConstantNull(compiler)); |
4478 } | 4260 } |
4479 | 4261 |
4480 void handleForeignJsCallInIsolate(ast.Send node) { | 4262 void handleForeignJsCallInIsolate(ast.Send node) { |
4481 Link<ast.Node> link = node.arguments; | 4263 Link<ast.Node> link = node.arguments; |
4482 if (!compiler.hasIsolateSupport) { | 4264 if (!compiler.hasIsolateSupport) { |
4483 // If the isolate library is not used, we just invoke the | 4265 // If the isolate library is not used, we just invoke the |
4484 // closure. | 4266 // closure. |
4485 visit(link.tail.head); | 4267 visit(link.tail.head); |
4486 push(new HInvokeClosure(new Selector.callClosure(0), | 4268 push(new HInvokeClosure(new Selector.callClosure(0), |
4487 <HInstruction>[pop()], | 4269 <HInstruction>[pop()], backend.dynamicType)); |
4488 backend.dynamicType)); | |
4489 } else { | 4270 } else { |
4490 // Call a helper method from the isolate library. | 4271 // Call a helper method from the isolate library. |
4491 Element element = helpers.callInIsolate; | 4272 Element element = helpers.callInIsolate; |
4492 if (element == null) { | 4273 if (element == null) { |
4493 reporter.internalError(node, | 4274 reporter.internalError(node, 'Isolate library and compiler mismatch.'); |
4494 'Isolate library and compiler mismatch.'); | |
4495 } | 4275 } |
4496 List<HInstruction> inputs = <HInstruction>[]; | 4276 List<HInstruction> inputs = <HInstruction>[]; |
4497 addGenericSendArgumentsToList(link, inputs); | 4277 addGenericSendArgumentsToList(link, inputs); |
4498 pushInvokeStatic(node, element, inputs, typeMask: backend.dynamicType); | 4278 pushInvokeStatic(node, element, inputs, typeMask: backend.dynamicType); |
4499 } | 4279 } |
4500 } | 4280 } |
4501 | 4281 |
4502 FunctionSignature handleForeignRawFunctionRef(ast.Send node, String name) { | 4282 FunctionSignature handleForeignRawFunctionRef(ast.Send node, String name) { |
4503 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { | 4283 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { |
4504 reporter.internalError(node.argumentsNode, | 4284 reporter.internalError( |
4505 '"$name" requires exactly one argument.'); | 4285 node.argumentsNode, '"$name" requires exactly one argument.'); |
4506 } | 4286 } |
4507 ast.Node closure = node.arguments.head; | 4287 ast.Node closure = node.arguments.head; |
4508 Element element = elements[closure]; | 4288 Element element = elements[closure]; |
4509 if (!Elements.isStaticOrTopLevelFunction(element)) { | 4289 if (!Elements.isStaticOrTopLevelFunction(element)) { |
4510 reporter.internalError(closure, | 4290 reporter.internalError( |
4511 '"$name" requires a static or top-level method.'); | 4291 closure, '"$name" requires a static or top-level method.'); |
4512 } | 4292 } |
4513 FunctionElement function = element; | 4293 FunctionElement function = element; |
4514 // TODO(johnniwinther): Try to eliminate the need to distinguish declaration | 4294 // TODO(johnniwinther): Try to eliminate the need to distinguish declaration |
4515 // and implementation signatures. Currently it is need because the | 4295 // and implementation signatures. Currently it is need because the |
4516 // signatures have different elements for parameters. | 4296 // signatures have different elements for parameters. |
4517 FunctionElement implementation = function.implementation; | 4297 FunctionElement implementation = function.implementation; |
4518 FunctionSignature params = implementation.functionSignature; | 4298 FunctionSignature params = implementation.functionSignature; |
4519 if (params.optionalParameterCount != 0) { | 4299 if (params.optionalParameterCount != 0) { |
4520 reporter.internalError(closure, | 4300 reporter.internalError( |
4521 '"$name" does not handle closure with optional parameters.'); | 4301 closure, '"$name" does not handle closure with optional parameters.'); |
4522 } | 4302 } |
4523 | 4303 |
4524 registry?.registerStaticUse( | 4304 registry?.registerStaticUse(new StaticUse.foreignUse(function)); |
4525 new StaticUse.foreignUse(function)); | |
4526 push(new HForeignCode( | 4305 push(new HForeignCode( |
4527 js.js.expressionTemplateYielding( | 4306 js.js.expressionTemplateYielding( |
4528 backend.emitter.staticFunctionAccess(function)), | 4307 backend.emitter.staticFunctionAccess(function)), |
4529 backend.dynamicType, | 4308 backend.dynamicType, |
4530 <HInstruction>[], | 4309 <HInstruction>[], |
4531 nativeBehavior: native.NativeBehavior.PURE)); | 4310 nativeBehavior: native.NativeBehavior.PURE)); |
4532 return params; | 4311 return params; |
4533 } | 4312 } |
4534 | 4313 |
4535 void handleForeignDartClosureToJs(ast.Send node, String name) { | 4314 void handleForeignDartClosureToJs(ast.Send node, String name) { |
4536 // TODO(ahe): This implements DART_CLOSURE_TO_JS and should probably take | 4315 // TODO(ahe): This implements DART_CLOSURE_TO_JS and should probably take |
4537 // care to wrap the closure in another closure that saves the current | 4316 // care to wrap the closure in another closure that saves the current |
4538 // isolate. | 4317 // isolate. |
4539 handleForeignRawFunctionRef(node, name); | 4318 handleForeignRawFunctionRef(node, name); |
4540 } | 4319 } |
4541 | 4320 |
4542 void handleForeignJsSetStaticState(ast.Send node) { | 4321 void handleForeignJsSetStaticState(ast.Send node) { |
4543 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { | 4322 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { |
4544 reporter.internalError(node.argumentsNode, | 4323 reporter.internalError( |
4545 'Exactly one argument required.'); | 4324 node.argumentsNode, 'Exactly one argument required.'); |
4546 } | 4325 } |
4547 visit(node.arguments.head); | 4326 visit(node.arguments.head); |
4548 String isolateName = backend.namer.staticStateHolder; | 4327 String isolateName = backend.namer.staticStateHolder; |
4549 SideEffects sideEffects = new SideEffects.empty(); | 4328 SideEffects sideEffects = new SideEffects.empty(); |
4550 sideEffects.setAllSideEffects(); | 4329 sideEffects.setAllSideEffects(); |
4551 push(new HForeignCode( | 4330 push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"), |
4552 js.js.parseForeignJS("$isolateName = #"), | 4331 backend.dynamicType, <HInstruction>[pop()], |
4553 backend.dynamicType, | |
4554 <HInstruction>[pop()], | |
4555 nativeBehavior: native.NativeBehavior.CHANGES_OTHER, | 4332 nativeBehavior: native.NativeBehavior.CHANGES_OTHER, |
4556 effects: sideEffects)); | 4333 effects: sideEffects)); |
4557 } | 4334 } |
4558 | 4335 |
4559 void handleForeignJsGetStaticState(ast.Send node) { | 4336 void handleForeignJsGetStaticState(ast.Send node) { |
4560 if (!node.arguments.isEmpty) { | 4337 if (!node.arguments.isEmpty) { |
4561 reporter.internalError(node.argumentsNode, 'Too many arguments.'); | 4338 reporter.internalError(node.argumentsNode, 'Too many arguments.'); |
4562 } | 4339 } |
4563 push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder), | 4340 push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder), |
4564 backend.dynamicType, | 4341 backend.dynamicType, <HInstruction>[], |
4565 <HInstruction>[], | 4342 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); |
4566 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); | |
4567 } | 4343 } |
4568 | 4344 |
4569 void handleForeignSend(ast.Send node, FunctionElement element) { | 4345 void handleForeignSend(ast.Send node, FunctionElement element) { |
4570 String name = element.name; | 4346 String name = element.name; |
4571 if (name == 'JS') { | 4347 if (name == 'JS') { |
4572 handleForeignJs(node); | 4348 handleForeignJs(node); |
4573 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { | 4349 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { |
4574 handleForeignJsCurrentIsolateContext(node); | 4350 handleForeignJsCurrentIsolateContext(node); |
4575 } else if (name == 'JS_CALL_IN_ISOLATE') { | 4351 } else if (name == 'JS_CALL_IN_ISOLATE') { |
4576 handleForeignJsCallInIsolate(node); | 4352 handleForeignJsCallInIsolate(node); |
(...skipping 17 matching lines...) Expand all Loading... |
4594 stack.add(graph.addConstantNull(compiler)); | 4370 stack.add(graph.addConstantNull(compiler)); |
4595 } else if (name == 'JS_INTERCEPTOR_CONSTANT') { | 4371 } else if (name == 'JS_INTERCEPTOR_CONSTANT') { |
4596 handleJsInterceptorConstant(node); | 4372 handleJsInterceptorConstant(node); |
4597 } else if (name == 'JS_STRING_CONCAT') { | 4373 } else if (name == 'JS_STRING_CONCAT') { |
4598 handleJsStringConcat(node); | 4374 handleJsStringConcat(node); |
4599 } else { | 4375 } else { |
4600 reporter.internalError(node, "Unknown foreign: ${element}"); | 4376 reporter.internalError(node, "Unknown foreign: ${element}"); |
4601 } | 4377 } |
4602 } | 4378 } |
4603 | 4379 |
4604 generateDeferredLoaderGet(ast.Send node, | 4380 generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader, |
4605 FunctionElement deferredLoader, | 4381 SourceInformation sourceInformation) { |
4606 SourceInformation sourceInformation) { | |
4607 // Until now we only handle these as getters. | 4382 // Until now we only handle these as getters. |
4608 invariant(node, deferredLoader.isDeferredLoaderGetter); | 4383 invariant(node, deferredLoader.isDeferredLoaderGetter); |
4609 Element loadFunction = compiler.loadLibraryFunction; | 4384 Element loadFunction = compiler.loadLibraryFunction; |
4610 PrefixElement prefixElement = deferredLoader.enclosingElement; | 4385 PrefixElement prefixElement = deferredLoader.enclosingElement; |
4611 String loadId = | 4386 String loadId = |
4612 compiler.deferredLoadTask.getImportDeferName(node, prefixElement); | 4387 compiler.deferredLoadTask.getImportDeferName(node, prefixElement); |
4613 var inputs = [graph.addConstantString( | 4388 var inputs = [ |
4614 new ast.DartString.literal(loadId), compiler)]; | 4389 graph.addConstantString(new ast.DartString.literal(loadId), compiler) |
| 4390 ]; |
4615 push(new HInvokeStatic(loadFunction, inputs, backend.nonNullType, | 4391 push(new HInvokeStatic(loadFunction, inputs, backend.nonNullType, |
4616 targetCanThrow: false) | 4392 targetCanThrow: false)..sourceInformation = sourceInformation); |
4617 ..sourceInformation = sourceInformation); | |
4618 } | 4393 } |
4619 | 4394 |
4620 generateSuperNoSuchMethodSend(ast.Send node, | 4395 generateSuperNoSuchMethodSend( |
4621 Selector selector, | 4396 ast.Send node, Selector selector, List<HInstruction> arguments) { |
4622 List<HInstruction> arguments) { | |
4623 String name = selector.name; | 4397 String name = selector.name; |
4624 | 4398 |
4625 ClassElement cls = currentNonClosureClass; | 4399 ClassElement cls = currentNonClosureClass; |
4626 MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_); | 4400 MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_); |
4627 if (!Selectors.noSuchMethod_.signatureApplies(element)) { | 4401 if (!Selectors.noSuchMethod_.signatureApplies(element)) { |
4628 element = coreClasses.objectClass.lookupMember(Identifiers.noSuchMethod_); | 4402 element = coreClasses.objectClass.lookupMember(Identifiers.noSuchMethod_); |
4629 } | 4403 } |
4630 if (compiler.enabledInvokeOn && !element.enclosingClass.isObject) { | 4404 if (compiler.enabledInvokeOn && !element.enclosingClass.isObject) { |
4631 // Register the call as dynamic if [noSuchMethod] on the super | 4405 // Register the call as dynamic if [noSuchMethod] on the super |
4632 // class is _not_ the default implementation from [Object], in | 4406 // class is _not_ the default implementation from [Object], in |
4633 // case the [noSuchMethod] implementation calls | 4407 // case the [noSuchMethod] implementation calls |
4634 // [JSInvocationMirror._invokeOn]. | 4408 // [JSInvocationMirror._invokeOn]. |
4635 // TODO(johnniwinther): Register this more precisely. | 4409 // TODO(johnniwinther): Register this more precisely. |
4636 registry?.registerDynamicUse(new DynamicUse(selector, null)); | 4410 registry?.registerDynamicUse(new DynamicUse(selector, null)); |
4637 } | 4411 } |
4638 String publicName = name; | 4412 String publicName = name; |
4639 if (selector.isSetter) publicName += '='; | 4413 if (selector.isSetter) publicName += '='; |
4640 | 4414 |
4641 ConstantValue nameConstant = constantSystem.createString( | 4415 ConstantValue nameConstant = |
4642 new ast.DartString.literal(publicName)); | 4416 constantSystem.createString(new ast.DartString.literal(publicName)); |
4643 | 4417 |
4644 js.Name internalName = backend.namer.invocationName(selector); | 4418 js.Name internalName = backend.namer.invocationName(selector); |
4645 | 4419 |
4646 Element createInvocationMirror = helpers.createInvocationMirror; | 4420 Element createInvocationMirror = helpers.createInvocationMirror; |
4647 var argumentsInstruction = buildLiteralList(arguments); | 4421 var argumentsInstruction = buildLiteralList(arguments); |
4648 add(argumentsInstruction); | 4422 add(argumentsInstruction); |
4649 | 4423 |
4650 var argumentNames = new List<HInstruction>(); | 4424 var argumentNames = new List<HInstruction>(); |
4651 for (String argumentName in selector.namedArguments) { | 4425 for (String argumentName in selector.namedArguments) { |
4652 ConstantValue argumentNameConstant = | 4426 ConstantValue argumentNameConstant = |
4653 constantSystem.createString(new ast.DartString.literal(argumentName)); | 4427 constantSystem.createString(new ast.DartString.literal(argumentName)); |
4654 argumentNames.add(graph.addConstant(argumentNameConstant, compiler)); | 4428 argumentNames.add(graph.addConstant(argumentNameConstant, compiler)); |
4655 } | 4429 } |
4656 var argumentNamesInstruction = buildLiteralList(argumentNames); | 4430 var argumentNamesInstruction = buildLiteralList(argumentNames); |
4657 add(argumentNamesInstruction); | 4431 add(argumentNamesInstruction); |
4658 | 4432 |
4659 ConstantValue kindConstant = | 4433 ConstantValue kindConstant = |
4660 constantSystem.createInt(selector.invocationMirrorKind); | 4434 constantSystem.createInt(selector.invocationMirrorKind); |
4661 | 4435 |
4662 pushInvokeStatic(null, | 4436 pushInvokeStatic( |
4663 createInvocationMirror, | 4437 null, |
4664 [graph.addConstant(nameConstant, compiler), | 4438 createInvocationMirror, |
4665 graph.addConstantStringFromName(internalName, compiler), | 4439 [ |
4666 graph.addConstant(kindConstant, compiler), | 4440 graph.addConstant(nameConstant, compiler), |
4667 argumentsInstruction, | 4441 graph.addConstantStringFromName(internalName, compiler), |
4668 argumentNamesInstruction], | 4442 graph.addConstant(kindConstant, compiler), |
4669 typeMask: backend.dynamicType); | 4443 argumentsInstruction, |
| 4444 argumentNamesInstruction |
| 4445 ], |
| 4446 typeMask: backend.dynamicType); |
4670 | 4447 |
4671 var inputs = <HInstruction>[pop()]; | 4448 var inputs = <HInstruction>[pop()]; |
4672 push(buildInvokeSuper(Selectors.noSuchMethod_, element, inputs)); | 4449 push(buildInvokeSuper(Selectors.noSuchMethod_, element, inputs)); |
4673 } | 4450 } |
4674 | 4451 |
4675 /// Generate a call to a super method or constructor. | 4452 /// Generate a call to a super method or constructor. |
4676 void generateSuperInvoke(ast.Send node, | 4453 void generateSuperInvoke(ast.Send node, FunctionElement function, |
4677 FunctionElement function, | 4454 SourceInformation sourceInformation) { |
4678 SourceInformation sourceInformation) { | |
4679 // TODO(5347): Try to avoid the need for calling [implementation] before | 4455 // TODO(5347): Try to avoid the need for calling [implementation] before |
4680 // calling [makeStaticArgumentList]. | 4456 // calling [makeStaticArgumentList]. |
4681 Selector selector = elements.getSelector(node); | 4457 Selector selector = elements.getSelector(node); |
4682 assert(invariant(node, | 4458 assert(invariant( |
4683 selector.applies(function.implementation, compiler.world), | 4459 node, selector.applies(function.implementation, compiler.world), |
4684 message: "$selector does not apply to ${function.implementation}")); | 4460 message: "$selector does not apply to ${function.implementation}")); |
4685 List<HInstruction> inputs = | 4461 List<HInstruction> inputs = makeStaticArgumentList( |
4686 makeStaticArgumentList(selector.callStructure, | 4462 selector.callStructure, node.arguments, function.implementation); |
4687 node.arguments, | |
4688 function.implementation); | |
4689 push(buildInvokeSuper(selector, function, inputs, sourceInformation)); | 4463 push(buildInvokeSuper(selector, function, inputs, sourceInformation)); |
4690 } | 4464 } |
4691 | 4465 |
4692 /// Access the value from the super [element]. | 4466 /// Access the value from the super [element]. |
4693 void handleSuperGet(ast.Send node, Element element) { | 4467 void handleSuperGet(ast.Send node, Element element) { |
4694 Selector selector = elements.getSelector(node); | 4468 Selector selector = elements.getSelector(node); |
4695 SourceInformation sourceInformation = | 4469 SourceInformation sourceInformation = |
4696 sourceInformationBuilder.buildGet(node); | 4470 sourceInformationBuilder.buildGet(node); |
4697 push(buildInvokeSuper( | 4471 push(buildInvokeSuper( |
4698 selector, element, const <HInstruction>[], sourceInformation)); | 4472 selector, element, const <HInstruction>[], sourceInformation)); |
4699 } | 4473 } |
4700 | 4474 |
4701 /// Invoke .call on the value retrieved from the super [element]. | 4475 /// Invoke .call on the value retrieved from the super [element]. |
4702 void handleSuperCallInvoke(ast.Send node, Element element) { | 4476 void handleSuperCallInvoke(ast.Send node, Element element) { |
4703 Selector selector = elements.getSelector(node); | 4477 Selector selector = elements.getSelector(node); |
4704 HInstruction target = buildInvokeSuper( | 4478 HInstruction target = buildInvokeSuper(selector, element, |
4705 selector, element, const <HInstruction>[], | 4479 const <HInstruction>[], sourceInformationBuilder.buildGet(node)); |
4706 sourceInformationBuilder.buildGet(node)); | |
4707 add(target); | 4480 add(target); |
4708 generateCallInvoke( | 4481 generateCallInvoke(node, target, |
4709 node, | |
4710 target, | |
4711 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 4482 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
4712 } | 4483 } |
4713 | 4484 |
4714 /// Invoke super [method]. | 4485 /// Invoke super [method]. |
4715 void handleSuperMethodInvoke( | 4486 void handleSuperMethodInvoke(ast.Send node, MethodElement method) { |
4716 ast.Send node, | 4487 generateSuperInvoke( |
4717 MethodElement method) { | 4488 node, method, sourceInformationBuilder.buildCall(node, node.selector)); |
4718 generateSuperInvoke(node, method, | |
4719 sourceInformationBuilder.buildCall(node, node.selector)); | |
4720 } | 4489 } |
4721 | 4490 |
4722 /// Access an unresolved super property. | 4491 /// Access an unresolved super property. |
4723 void handleUnresolvedSuperInvoke(ast.Send node) { | 4492 void handleUnresolvedSuperInvoke(ast.Send node) { |
4724 Selector selector = elements.getSelector(node); | 4493 Selector selector = elements.getSelector(node); |
4725 List<HInstruction> arguments = <HInstruction>[]; | 4494 List<HInstruction> arguments = <HInstruction>[]; |
4726 if (!node.isPropertyAccess) { | 4495 if (!node.isPropertyAccess) { |
4727 addGenericSendArgumentsToList(node.arguments, arguments); | 4496 addGenericSendArgumentsToList(node.arguments, arguments); |
4728 } | 4497 } |
4729 generateSuperNoSuchMethodSend(node, selector, arguments); | 4498 generateSuperNoSuchMethodSend(node, selector, arguments); |
4730 } | 4499 } |
4731 | 4500 |
4732 @override | 4501 @override |
4733 void visitUnresolvedSuperIndex( | 4502 void visitUnresolvedSuperIndex( |
4734 ast.Send node, | 4503 ast.Send node, Element element, ast.Node index, _) { |
4735 Element element, | |
4736 ast.Node index, | |
4737 _) { | |
4738 handleUnresolvedSuperInvoke(node); | 4504 handleUnresolvedSuperInvoke(node); |
4739 } | 4505 } |
4740 | 4506 |
4741 @override | 4507 @override |
4742 void visitUnresolvedSuperUnary( | 4508 void visitUnresolvedSuperUnary( |
4743 ast.Send node, | 4509 ast.Send node, UnaryOperator operator, Element element, _) { |
4744 UnaryOperator operator, | |
4745 Element element, | |
4746 _) { | |
4747 handleUnresolvedSuperInvoke(node); | 4510 handleUnresolvedSuperInvoke(node); |
4748 } | 4511 } |
4749 | 4512 |
4750 @override | 4513 @override |
4751 void visitUnresolvedSuperBinary( | 4514 void visitUnresolvedSuperBinary(ast.Send node, Element element, |
4752 ast.Send node, | 4515 BinaryOperator operator, ast.Node argument, _) { |
4753 Element element, | |
4754 BinaryOperator operator, | |
4755 ast.Node argument, | |
4756 _) { | |
4757 handleUnresolvedSuperInvoke(node); | 4516 handleUnresolvedSuperInvoke(node); |
4758 } | 4517 } |
4759 | 4518 |
4760 @override | 4519 @override |
4761 void visitUnresolvedSuperGet( | 4520 void visitUnresolvedSuperGet(ast.Send node, Element element, _) { |
4762 ast.Send node, | |
4763 Element element, | |
4764 _) { | |
4765 handleUnresolvedSuperInvoke(node); | 4521 handleUnresolvedSuperInvoke(node); |
4766 } | 4522 } |
4767 | 4523 |
4768 @override | 4524 @override |
4769 void visitUnresolvedSuperSet( | 4525 void visitUnresolvedSuperSet( |
4770 ast.Send node, | 4526 ast.Send node, Element element, ast.Node rhs, _) { |
4771 Element element, | |
4772 ast.Node rhs, | |
4773 _) { | |
4774 handleSuperSendSet(node); | 4527 handleSuperSendSet(node); |
4775 } | 4528 } |
4776 | 4529 |
4777 @override | 4530 @override |
4778 void visitSuperSetterGet( | 4531 void visitSuperSetterGet(ast.Send node, MethodElement setter, _) { |
4779 ast.Send node, | |
4780 MethodElement setter, | |
4781 _) { | |
4782 handleUnresolvedSuperInvoke(node); | 4532 handleUnresolvedSuperInvoke(node); |
4783 } | 4533 } |
4784 | 4534 |
4785 @override | 4535 @override |
4786 void visitUnresolvedSuperInvoke( | 4536 void visitUnresolvedSuperInvoke( |
4787 ast.Send node, | 4537 ast.Send node, Element element, ast.Node argument, Selector selector, _) { |
4788 Element element, | |
4789 ast.Node argument, | |
4790 Selector selector, | |
4791 _) { | |
4792 handleUnresolvedSuperInvoke(node); | 4538 handleUnresolvedSuperInvoke(node); |
4793 } | 4539 } |
4794 | 4540 |
4795 @override | 4541 @override |
4796 void visitSuperFieldGet( | 4542 void visitSuperFieldGet(ast.Send node, FieldElement field, _) { |
4797 ast.Send node, | |
4798 FieldElement field, | |
4799 _) { | |
4800 handleSuperGet(node, field); | 4543 handleSuperGet(node, field); |
4801 } | 4544 } |
4802 | 4545 |
4803 @override | 4546 @override |
4804 void visitSuperGetterGet( | 4547 void visitSuperGetterGet(ast.Send node, MethodElement method, _) { |
4805 ast.Send node, | |
4806 MethodElement method, | |
4807 _) { | |
4808 handleSuperGet(node, method); | 4548 handleSuperGet(node, method); |
4809 } | 4549 } |
4810 | 4550 |
4811 @override | 4551 @override |
4812 void visitSuperMethodGet( | 4552 void visitSuperMethodGet(ast.Send node, MethodElement method, _) { |
4813 ast.Send node, | |
4814 MethodElement method, | |
4815 _) { | |
4816 handleSuperGet(node, method); | 4553 handleSuperGet(node, method); |
4817 } | 4554 } |
4818 | 4555 |
4819 @override | 4556 @override |
4820 void visitSuperFieldInvoke( | 4557 void visitSuperFieldInvoke(ast.Send node, FieldElement field, |
4821 ast.Send node, | 4558 ast.NodeList arguments, CallStructure callStructure, _) { |
4822 FieldElement field, | |
4823 ast.NodeList arguments, | |
4824 CallStructure callStructure, | |
4825 _) { | |
4826 handleSuperCallInvoke(node, field); | 4559 handleSuperCallInvoke(node, field); |
4827 } | 4560 } |
4828 | 4561 |
4829 @override | 4562 @override |
4830 void visitSuperGetterInvoke( | 4563 void visitSuperGetterInvoke(ast.Send node, MethodElement getter, |
4831 ast.Send node, | 4564 ast.NodeList arguments, CallStructure callStructure, _) { |
4832 MethodElement getter, | |
4833 ast.NodeList arguments, | |
4834 CallStructure callStructure, | |
4835 _) { | |
4836 handleSuperCallInvoke(node, getter); | 4565 handleSuperCallInvoke(node, getter); |
4837 } | 4566 } |
4838 | 4567 |
4839 @override | 4568 @override |
4840 void visitSuperMethodInvoke( | 4569 void visitSuperMethodInvoke(ast.Send node, MethodElement method, |
4841 ast.Send node, | 4570 ast.NodeList arguments, CallStructure callStructure, _) { |
4842 MethodElement method, | |
4843 ast.NodeList arguments, | |
4844 CallStructure callStructure, | |
4845 _) { | |
4846 handleSuperMethodInvoke(node, method); | 4571 handleSuperMethodInvoke(node, method); |
4847 } | 4572 } |
4848 | 4573 |
4849 @override | 4574 @override |
4850 void visitSuperIndex( | 4575 void visitSuperIndex(ast.Send node, MethodElement method, ast.Node index, _) { |
4851 ast.Send node, | |
4852 MethodElement method, | |
4853 ast.Node index, | |
4854 _) { | |
4855 handleSuperMethodInvoke(node, method); | 4576 handleSuperMethodInvoke(node, method); |
4856 } | 4577 } |
4857 | 4578 |
4858 @override | 4579 @override |
4859 void visitSuperEquals( | 4580 void visitSuperEquals( |
4860 ast.Send node, | 4581 ast.Send node, MethodElement method, ast.Node argument, _) { |
4861 MethodElement method, | |
4862 ast.Node argument, | |
4863 _) { | |
4864 handleSuperMethodInvoke(node, method); | 4582 handleSuperMethodInvoke(node, method); |
4865 } | 4583 } |
4866 | 4584 |
4867 @override | 4585 @override |
4868 void visitSuperBinary( | 4586 void visitSuperBinary(ast.Send node, MethodElement method, |
4869 ast.Send node, | 4587 BinaryOperator operator, ast.Node argument, _) { |
4870 MethodElement method, | |
4871 BinaryOperator operator, | |
4872 ast.Node argument, | |
4873 _) { | |
4874 handleSuperMethodInvoke(node, method); | 4588 handleSuperMethodInvoke(node, method); |
4875 } | 4589 } |
4876 | 4590 |
4877 @override | 4591 @override |
4878 void visitSuperNotEquals( | 4592 void visitSuperNotEquals( |
4879 ast.Send node, | 4593 ast.Send node, MethodElement method, ast.Node argument, _) { |
4880 MethodElement method, | |
4881 ast.Node argument, | |
4882 _) { | |
4883 handleSuperMethodInvoke(node, method); | 4594 handleSuperMethodInvoke(node, method); |
4884 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); | 4595 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); |
4885 } | 4596 } |
4886 | 4597 |
4887 @override | 4598 @override |
4888 void visitSuperUnary( | 4599 void visitSuperUnary( |
4889 ast.Send node, | 4600 ast.Send node, UnaryOperator operator, MethodElement method, _) { |
4890 UnaryOperator operator, | |
4891 MethodElement method, | |
4892 _) { | |
4893 handleSuperMethodInvoke(node, method); | 4601 handleSuperMethodInvoke(node, method); |
4894 } | 4602 } |
4895 | 4603 |
4896 @override | 4604 @override |
4897 void visitSuperMethodIncompatibleInvoke( | 4605 void visitSuperMethodIncompatibleInvoke(ast.Send node, MethodElement method, |
4898 ast.Send node, | 4606 ast.NodeList arguments, CallStructure callStructure, _) { |
4899 MethodElement method, | |
4900 ast.NodeList arguments, | |
4901 CallStructure callStructure, | |
4902 _) { | |
4903 handleInvalidSuperInvoke(node, arguments); | 4607 handleInvalidSuperInvoke(node, arguments); |
4904 } | 4608 } |
4905 | 4609 |
4906 @override | 4610 @override |
4907 void visitSuperSetterInvoke( | 4611 void visitSuperSetterInvoke(ast.Send node, SetterElement setter, |
4908 ast.Send node, | 4612 ast.NodeList arguments, CallStructure callStructure, _) { |
4909 SetterElement setter, | |
4910 ast.NodeList arguments, | |
4911 CallStructure callStructure, | |
4912 _) { | |
4913 handleInvalidSuperInvoke(node, arguments); | 4613 handleInvalidSuperInvoke(node, arguments); |
4914 } | 4614 } |
4915 | 4615 |
4916 void handleInvalidSuperInvoke(ast.Send node, ast.NodeList arguments) { | 4616 void handleInvalidSuperInvoke(ast.Send node, ast.NodeList arguments) { |
4917 Selector selector = elements.getSelector(node); | 4617 Selector selector = elements.getSelector(node); |
4918 List<HInstruction> inputs = <HInstruction>[]; | 4618 List<HInstruction> inputs = <HInstruction>[]; |
4919 addGenericSendArgumentsToList(arguments.nodes, inputs); | 4619 addGenericSendArgumentsToList(arguments.nodes, inputs); |
4920 generateSuperNoSuchMethodSend(node, selector, inputs); | 4620 generateSuperNoSuchMethodSend(node, selector, inputs); |
4921 } | 4621 } |
4922 | 4622 |
4923 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { | 4623 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { |
4924 ClassWorld classWorld = compiler.world; | 4624 ClassWorld classWorld = compiler.world; |
4925 if (classWorld.isUsedAsMixin(cls)) return true; | 4625 if (classWorld.isUsedAsMixin(cls)) return true; |
4926 | 4626 |
4927 return compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) { | 4627 return compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) { |
4928 return !rti.isTrivialSubstitution(subclass, cls); | 4628 return !rti.isTrivialSubstitution(subclass, cls); |
4929 }); | 4629 }); |
4930 } | 4630 } |
4931 | 4631 |
4932 /** | 4632 /** |
4933 * Generate code to extract the type arguments from the object, substitute | 4633 * Generate code to extract the type arguments from the object, substitute |
4934 * them as an instance of the type we are testing against (if necessary), and | 4634 * them as an instance of the type we are testing against (if necessary), and |
4935 * extract the type argument by the index of the variable in the list of type | 4635 * extract the type argument by the index of the variable in the list of type |
4936 * variables for that class. | 4636 * variables for that class. |
4937 */ | 4637 */ |
4938 HInstruction readTypeVariable( | 4638 HInstruction readTypeVariable(ClassElement cls, TypeVariableElement variable, |
4939 ClassElement cls, | |
4940 TypeVariableElement variable, | |
4941 {SourceInformation sourceInformation}) { | 4639 {SourceInformation sourceInformation}) { |
4942 assert(sourceElement.isInstanceMember); | 4640 assert(sourceElement.isInstanceMember); |
4943 | 4641 |
4944 HInstruction target = localsHandler.readThis(); | 4642 HInstruction target = localsHandler.readThis(); |
4945 HConstant index = graph.addConstantInt(variable.index, compiler); | 4643 HConstant index = graph.addConstantInt(variable.index, compiler); |
4946 | 4644 |
4947 if (needsSubstitutionForTypeVariableAccess(cls)) { | 4645 if (needsSubstitutionForTypeVariableAccess(cls)) { |
4948 // TODO(ahe): Creating a string here is unfortunate. It is slow (due to | 4646 // TODO(ahe): Creating a string here is unfortunate. It is slow (due to |
4949 // string concatenation in the implementation), and may prevent | 4647 // string concatenation in the implementation), and may prevent |
4950 // segmentation of '$'. | 4648 // segmentation of '$'. |
4951 js.Name substitutionName = backend.namer.runtimeTypeName(cls); | 4649 js.Name substitutionName = backend.namer.runtimeTypeName(cls); |
4952 HInstruction substitutionNameInstr = graph.addConstantStringFromName( | 4650 HInstruction substitutionNameInstr = |
4953 substitutionName, compiler); | 4651 graph.addConstantStringFromName(substitutionName, compiler); |
4954 pushInvokeStatic(null, | 4652 pushInvokeStatic(null, helpers.getRuntimeTypeArgument, |
4955 helpers.getRuntimeTypeArgument, | 4653 [target, substitutionNameInstr, index], |
4956 [target, substitutionNameInstr, index], | 4654 typeMask: backend.dynamicType, sourceInformation: sourceInformation); |
4957 typeMask: backend.dynamicType, | |
4958 sourceInformation: sourceInformation); | |
4959 } else { | 4655 } else { |
4960 pushInvokeStatic( | 4656 pushInvokeStatic(null, helpers.getTypeArgumentByIndex, [target, index], |
4961 null, | 4657 typeMask: backend.dynamicType, sourceInformation: sourceInformation); |
4962 helpers.getTypeArgumentByIndex, | |
4963 [target, index], | |
4964 typeMask: backend.dynamicType, | |
4965 sourceInformation: sourceInformation); | |
4966 } | 4658 } |
4967 return pop(); | 4659 return pop(); |
4968 } | 4660 } |
4969 | 4661 |
4970 // TODO(karlklose): this is needed to avoid a bug where the resolved type is | 4662 // TODO(karlklose): this is needed to avoid a bug where the resolved type is |
4971 // not stored on a type annotation in the closure translator. Remove when | 4663 // not stored on a type annotation in the closure translator. Remove when |
4972 // fixed. | 4664 // fixed. |
4973 bool hasDirectLocal(Local local) { | 4665 bool hasDirectLocal(Local local) { |
4974 return !localsHandler.isAccessedDirectly(local) || | 4666 return !localsHandler.isAccessedDirectly(local) || |
4975 localsHandler.directLocals[local] != null; | 4667 localsHandler.directLocals[local] != null; |
4976 } | 4668 } |
4977 | 4669 |
4978 /** | 4670 /** |
4979 * Helper to create an instruction that gets the value of a type variable. | 4671 * Helper to create an instruction that gets the value of a type variable. |
4980 */ | 4672 */ |
4981 HInstruction addTypeVariableReference( | 4673 HInstruction addTypeVariableReference(TypeVariableType type, |
4982 TypeVariableType type, | |
4983 {SourceInformation sourceInformation}) { | 4674 {SourceInformation sourceInformation}) { |
4984 | |
4985 assert(assertTypeInContext(type)); | 4675 assert(assertTypeInContext(type)); |
4986 Element member = sourceElement; | 4676 Element member = sourceElement; |
4987 bool isClosure = member.enclosingElement.isClosure; | 4677 bool isClosure = member.enclosingElement.isClosure; |
4988 if (isClosure) { | 4678 if (isClosure) { |
4989 ClosureClassElement closureClass = member.enclosingElement; | 4679 ClosureClassElement closureClass = member.enclosingElement; |
4990 member = closureClass.methodElement; | 4680 member = closureClass.methodElement; |
4991 member = member.outermostEnclosingMemberOrTopLevel; | 4681 member = member.outermostEnclosingMemberOrTopLevel; |
4992 } | 4682 } |
4993 bool isInConstructorContext = member.isConstructor || | 4683 bool isInConstructorContext = |
4994 member.isGenerativeConstructorBody; | 4684 member.isConstructor || member.isGenerativeConstructorBody; |
4995 Local typeVariableLocal = localsHandler.getTypeVariableAsLocal(type); | 4685 Local typeVariableLocal = localsHandler.getTypeVariableAsLocal(type); |
4996 if (isClosure) { | 4686 if (isClosure) { |
4997 if (member.isFactoryConstructor || | 4687 if (member.isFactoryConstructor || |
4998 (isInConstructorContext && hasDirectLocal(typeVariableLocal))) { | 4688 (isInConstructorContext && hasDirectLocal(typeVariableLocal))) { |
4999 // The type variable is used from a closure in a factory constructor. | 4689 // The type variable is used from a closure in a factory constructor. |
5000 // The value of the type argument is stored as a local on the closure | 4690 // The value of the type argument is stored as a local on the closure |
5001 // itself. | 4691 // itself. |
5002 return localsHandler.readLocal( | 4692 return localsHandler.readLocal(typeVariableLocal, |
5003 typeVariableLocal, sourceInformation: sourceInformation); | 4693 sourceInformation: sourceInformation); |
5004 } else if (member.isFunction || | 4694 } else if (member.isFunction || |
5005 member.isGetter || | 4695 member.isGetter || |
5006 member.isSetter || | 4696 member.isSetter || |
5007 isInConstructorContext) { | 4697 isInConstructorContext) { |
5008 // The type variable is stored on the "enclosing object" and needs to be | 4698 // The type variable is stored on the "enclosing object" and needs to be |
5009 // accessed using the this-reference in the closure. | 4699 // accessed using the this-reference in the closure. |
5010 return readTypeVariable( | 4700 return readTypeVariable(member.enclosingClass, type.element, |
5011 member.enclosingClass, | |
5012 type.element, | |
5013 sourceInformation: sourceInformation); | 4701 sourceInformation: sourceInformation); |
5014 } else { | 4702 } else { |
5015 assert(member.isField); | 4703 assert(member.isField); |
5016 // The type variable is stored in a parameter of the method. | 4704 // The type variable is stored in a parameter of the method. |
5017 return localsHandler.readLocal(typeVariableLocal); | 4705 return localsHandler.readLocal(typeVariableLocal); |
5018 } | 4706 } |
5019 } else if (isInConstructorContext || | 4707 } else if (isInConstructorContext || |
5020 // When [member] is a field, we can be either | 4708 // When [member] is a field, we can be either |
5021 // generating a checked setter or inlining its | 4709 // generating a checked setter or inlining its |
5022 // initializer in a constructor. An initializer is | 4710 // initializer in a constructor. An initializer is |
5023 // never built standalone, so in that case [target] is not | 4711 // never built standalone, so in that case [target] is not |
5024 // the [member] itself. | 4712 // the [member] itself. |
5025 (member.isField && member != target)) { | 4713 (member.isField && member != target)) { |
5026 // The type variable is stored in a parameter of the method. | 4714 // The type variable is stored in a parameter of the method. |
5027 return localsHandler.readLocal( | 4715 return localsHandler.readLocal(typeVariableLocal, |
5028 typeVariableLocal, sourceInformation: sourceInformation); | 4716 sourceInformation: sourceInformation); |
5029 } else if (member.isInstanceMember) { | 4717 } else if (member.isInstanceMember) { |
5030 // The type variable is stored on the object. | 4718 // The type variable is stored on the object. |
5031 return readTypeVariable( | 4719 return readTypeVariable(member.enclosingClass, type.element, |
5032 member.enclosingClass, | |
5033 type.element, | |
5034 sourceInformation: sourceInformation); | 4720 sourceInformation: sourceInformation); |
5035 } else { | 4721 } else { |
5036 reporter.internalError(type.element, | 4722 reporter.internalError( |
5037 'Unexpected type variable in static context.'); | 4723 type.element, 'Unexpected type variable in static context.'); |
5038 return null; | 4724 return null; |
5039 } | 4725 } |
5040 } | 4726 } |
5041 | 4727 |
5042 HInstruction analyzeTypeArgument( | 4728 HInstruction analyzeTypeArgument(DartType argument, |
5043 DartType argument, | |
5044 {SourceInformation sourceInformation}) { | 4729 {SourceInformation sourceInformation}) { |
5045 | |
5046 assert(assertTypeInContext(argument)); | 4730 assert(assertTypeInContext(argument)); |
5047 if (argument.treatAsDynamic) { | 4731 if (argument.treatAsDynamic) { |
5048 // Represent [dynamic] as [null]. | 4732 // Represent [dynamic] as [null]. |
5049 return graph.addConstantNull(compiler); | 4733 return graph.addConstantNull(compiler); |
5050 } | 4734 } |
5051 | 4735 |
5052 if (argument.isTypeVariable) { | 4736 if (argument.isTypeVariable) { |
5053 return addTypeVariableReference( | 4737 return addTypeVariableReference(argument, |
5054 argument, sourceInformation: sourceInformation); | 4738 sourceInformation: sourceInformation); |
5055 } | 4739 } |
5056 | 4740 |
5057 List<HInstruction> inputs = <HInstruction>[]; | 4741 List<HInstruction> inputs = <HInstruction>[]; |
5058 | 4742 |
5059 js.Expression template = | 4743 js.Expression template = |
5060 rtiEncoder.getTypeRepresentationWithPlaceholders(argument, (variable) { | 4744 rtiEncoder.getTypeRepresentationWithPlaceholders(argument, (variable) { |
5061 inputs.add(addTypeVariableReference(variable)); | 4745 inputs.add(addTypeVariableReference(variable)); |
5062 }); | 4746 }); |
5063 | 4747 |
5064 js.Template code = new js.Template(null, template); | 4748 js.Template code = new js.Template(null, template); |
5065 HInstruction result = new HForeignCode(code, backend.stringType, inputs, | 4749 HInstruction result = new HForeignCode(code, backend.stringType, inputs, |
5066 nativeBehavior: native.NativeBehavior.PURE); | 4750 nativeBehavior: native.NativeBehavior.PURE); |
5067 add(result); | 4751 add(result); |
5068 return result; | 4752 return result; |
5069 } | 4753 } |
5070 | 4754 |
5071 HInstruction handleListConstructor(InterfaceType type, | 4755 HInstruction handleListConstructor( |
5072 ast.Node currentNode, | 4756 InterfaceType type, ast.Node currentNode, HInstruction newObject) { |
5073 HInstruction newObject) { | |
5074 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { | 4757 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { |
5075 return newObject; | 4758 return newObject; |
5076 } | 4759 } |
5077 List<HInstruction> inputs = <HInstruction>[]; | 4760 List<HInstruction> inputs = <HInstruction>[]; |
5078 type = localsHandler.substInContext(type); | 4761 type = localsHandler.substInContext(type); |
5079 type.typeArguments.forEach((DartType argument) { | 4762 type.typeArguments.forEach((DartType argument) { |
5080 inputs.add(analyzeTypeArgument(argument)); | 4763 inputs.add(analyzeTypeArgument(argument)); |
5081 }); | 4764 }); |
5082 // TODO(15489): Register at codegen. | 4765 // TODO(15489): Register at codegen. |
5083 registry?.registerInstantiation(type); | 4766 registry?.registerInstantiation(type); |
5084 return callSetRuntimeTypeInfo(type.element, inputs, newObject); | 4767 return callSetRuntimeTypeInfo(type.element, inputs, newObject); |
5085 } | 4768 } |
5086 | 4769 |
5087 void copyRuntimeTypeInfo(HInstruction source, HInstruction target) { | 4770 void copyRuntimeTypeInfo(HInstruction source, HInstruction target) { |
5088 Element copyHelper = helpers.copyTypeArguments; | 4771 Element copyHelper = helpers.copyTypeArguments; |
5089 pushInvokeStatic(null, copyHelper, [source, target], | 4772 pushInvokeStatic(null, copyHelper, [source, target], |
5090 sourceInformation: target.sourceInformation); | 4773 sourceInformation: target.sourceInformation); |
5091 pop(); | 4774 pop(); |
5092 } | 4775 } |
5093 | 4776 |
5094 HInstruction callSetRuntimeTypeInfo(ClassElement element, | 4777 HInstruction callSetRuntimeTypeInfo(ClassElement element, |
5095 List<HInstruction> rtiInputs, | 4778 List<HInstruction> rtiInputs, HInstruction newObject) { |
5096 HInstruction newObject) { | |
5097 if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) { | 4779 if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) { |
5098 return newObject; | 4780 return newObject; |
5099 } | 4781 } |
5100 | 4782 |
5101 HInstruction typeInfo = buildLiteralList(rtiInputs); | 4783 HInstruction typeInfo = buildLiteralList(rtiInputs); |
5102 add(typeInfo); | 4784 add(typeInfo); |
5103 | 4785 |
5104 // Set the runtime type information on the object. | 4786 // Set the runtime type information on the object. |
5105 Element typeInfoSetterElement = helpers.setRuntimeTypeInfo; | 4787 Element typeInfoSetterElement = helpers.setRuntimeTypeInfo; |
5106 pushInvokeStatic( | 4788 pushInvokeStatic( |
5107 null, | 4789 null, typeInfoSetterElement, <HInstruction>[newObject, typeInfo], |
5108 typeInfoSetterElement, | |
5109 <HInstruction>[newObject, typeInfo], | |
5110 typeMask: backend.dynamicType, | 4790 typeMask: backend.dynamicType, |
5111 sourceInformation: newObject.sourceInformation); | 4791 sourceInformation: newObject.sourceInformation); |
5112 | 4792 |
5113 // The new object will now be referenced through the | 4793 // The new object will now be referenced through the |
5114 // `setRuntimeTypeInfo` call. We therefore set the type of that | 4794 // `setRuntimeTypeInfo` call. We therefore set the type of that |
5115 // instruction to be of the object's type. | 4795 // instruction to be of the object's type. |
5116 assert(invariant( | 4796 assert(invariant(CURRENT_ELEMENT_SPANNABLE, |
5117 CURRENT_ELEMENT_SPANNABLE, | |
5118 stack.last is HInvokeStatic || stack.last == newObject, | 4797 stack.last is HInvokeStatic || stack.last == newObject, |
5119 message: | 4798 message: "Unexpected `stack.last`: Found ${stack.last}, " |
5120 "Unexpected `stack.last`: Found ${stack.last}, " | 4799 "expected ${newObject} or an HInvokeStatic. " |
5121 "expected ${newObject} or an HInvokeStatic. " | 4800 "State: element=$element, rtiInputs=$rtiInputs, stack=$stack.")); |
5122 "State: element=$element, rtiInputs=$rtiInputs, stack=$stack.")); | |
5123 stack.last.instructionType = newObject.instructionType; | 4801 stack.last.instructionType = newObject.instructionType; |
5124 return pop(); | 4802 return pop(); |
5125 } | 4803 } |
5126 | 4804 |
5127 void handleNewSend(ast.NewExpression node) { | 4805 void handleNewSend(ast.NewExpression node) { |
5128 ast.Send send = node.send; | 4806 ast.Send send = node.send; |
5129 generateIsDeferredLoadedCheckOfSend(send); | 4807 generateIsDeferredLoadedCheckOfSend(send); |
5130 | 4808 |
5131 bool isFixedList = false; | 4809 bool isFixedList = false; |
5132 bool isFixedListConstructorCall = | 4810 bool isFixedListConstructorCall = |
5133 Elements.isFixedListConstructorCall(elements[send], send, compiler); | 4811 Elements.isFixedListConstructorCall(elements[send], send, compiler); |
5134 bool isGrowableListConstructorCall = | 4812 bool isGrowableListConstructorCall = |
5135 Elements.isGrowableListConstructorCall(elements[send], send, compiler); | 4813 Elements.isGrowableListConstructorCall(elements[send], send, compiler); |
5136 | 4814 |
5137 TypeMask computeType(element) { | 4815 TypeMask computeType(element) { |
5138 Element originalElement = elements[send]; | 4816 Element originalElement = elements[send]; |
5139 if (isFixedListConstructorCall | 4817 if (isFixedListConstructorCall || |
5140 || Elements.isFilledListConstructorCall( | 4818 Elements.isFilledListConstructorCall( |
5141 originalElement, send, compiler)) { | 4819 originalElement, send, compiler)) { |
5142 isFixedList = true; | 4820 isFixedList = true; |
5143 TypeMask inferred = | 4821 TypeMask inferred = |
5144 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | 4822 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); |
5145 return inferred.containsAll(compiler.world) | 4823 return inferred.containsAll(compiler.world) |
5146 ? backend.fixedArrayType | 4824 ? backend.fixedArrayType |
5147 : inferred; | 4825 : inferred; |
5148 } else if (isGrowableListConstructorCall) { | 4826 } else if (isGrowableListConstructorCall) { |
5149 TypeMask inferred = | 4827 TypeMask inferred = |
5150 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | 4828 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); |
5151 return inferred.containsAll(compiler.world) | 4829 return inferred.containsAll(compiler.world) |
5152 ? backend.extendableArrayType | 4830 ? backend.extendableArrayType |
5153 : inferred; | 4831 : inferred; |
5154 } else if (Elements.isConstructorOfTypedArraySubclass( | 4832 } else if (Elements.isConstructorOfTypedArraySubclass( |
5155 originalElement, compiler)) { | 4833 originalElement, compiler)) { |
5156 isFixedList = true; | 4834 isFixedList = true; |
5157 TypeMask inferred = | 4835 TypeMask inferred = |
5158 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | 4836 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); |
5159 ClassElement cls = element.enclosingClass; | 4837 ClassElement cls = element.enclosingClass; |
5160 assert(backend.isNative(cls.thisType.element)); | 4838 assert(backend.isNative(cls.thisType.element)); |
5161 return inferred.containsAll(compiler.world) | 4839 return inferred.containsAll(compiler.world) |
5162 ? new TypeMask.nonNullExact(cls.thisType.element, compiler.world) | 4840 ? new TypeMask.nonNullExact(cls.thisType.element, compiler.world) |
5163 : inferred; | 4841 : inferred; |
5164 } else if (element.isGenerativeConstructor) { | 4842 } else if (element.isGenerativeConstructor) { |
5165 ClassElement cls = element.enclosingClass; | 4843 ClassElement cls = element.enclosingClass; |
(...skipping 17 matching lines...) Expand all Loading... |
5183 constructor = constructorImplementation.effectiveTarget; | 4861 constructor = constructorImplementation.effectiveTarget; |
5184 | 4862 |
5185 final bool isSymbolConstructor = | 4863 final bool isSymbolConstructor = |
5186 constructorDeclaration == compiler.symbolConstructor; | 4864 constructorDeclaration == compiler.symbolConstructor; |
5187 final bool isJSArrayTypedConstructor = | 4865 final bool isJSArrayTypedConstructor = |
5188 constructorDeclaration == helpers.jsArrayTypedConstructor; | 4866 constructorDeclaration == helpers.jsArrayTypedConstructor; |
5189 | 4867 |
5190 if (isSymbolConstructor) { | 4868 if (isSymbolConstructor) { |
5191 constructor = compiler.symbolValidatedConstructor; | 4869 constructor = compiler.symbolValidatedConstructor; |
5192 assert(invariant(send, constructor != null, | 4870 assert(invariant(send, constructor != null, |
5193 message: 'Constructor Symbol.validated is missing')); | 4871 message: 'Constructor Symbol.validated is missing')); |
5194 callStructure = compiler.symbolValidatedConstructorSelector.callStructure; | 4872 callStructure = compiler.symbolValidatedConstructorSelector.callStructure; |
5195 assert(invariant(send, callStructure != null, | 4873 assert(invariant(send, callStructure != null, |
5196 message: 'Constructor Symbol.validated is missing')); | 4874 message: 'Constructor Symbol.validated is missing')); |
5197 } | 4875 } |
5198 | 4876 |
5199 bool isRedirected = constructorDeclaration.isRedirectingFactory; | 4877 bool isRedirected = constructorDeclaration.isRedirectingFactory; |
5200 if (!constructorDeclaration.isCyclicRedirection) { | 4878 if (!constructorDeclaration.isCyclicRedirection) { |
5201 // Insert a check for every deferred redirection on the path to the | 4879 // Insert a check for every deferred redirection on the path to the |
5202 // final target. | 4880 // final target. |
5203 ConstructorElement target = constructorDeclaration; | 4881 ConstructorElement target = constructorDeclaration; |
5204 while (target.isRedirectingFactory) { | 4882 while (target.isRedirectingFactory) { |
5205 if (constructorDeclaration.redirectionDeferredPrefix != null) { | 4883 if (constructorDeclaration.redirectionDeferredPrefix != null) { |
5206 generateIsDeferredLoadedCheckIfNeeded( | 4884 generateIsDeferredLoadedCheckIfNeeded( |
5207 target.redirectionDeferredPrefix, | 4885 target.redirectionDeferredPrefix, node); |
5208 node); | |
5209 } | 4886 } |
5210 target = target.immediateRedirectionTarget; | 4887 target = target.immediateRedirectionTarget; |
5211 } | 4888 } |
5212 } | 4889 } |
5213 InterfaceType type = elements.getType(node); | 4890 InterfaceType type = elements.getType(node); |
5214 InterfaceType expectedType = | 4891 InterfaceType expectedType = |
5215 constructorDeclaration.computeEffectiveTargetType(type); | 4892 constructorDeclaration.computeEffectiveTargetType(type); |
5216 expectedType = localsHandler.substInContext(expectedType); | 4893 expectedType = localsHandler.substInContext(expectedType); |
5217 | 4894 |
5218 if (compiler.elementHasCompileTimeError(constructor)) { | 4895 if (compiler.elementHasCompileTimeError(constructor)) { |
(...skipping 15 matching lines...) Expand all Loading... |
5234 pop(); | 4911 pop(); |
5235 }); | 4912 }); |
5236 generateAbstractClassInstantiationError(send, cls.name); | 4913 generateAbstractClassInstantiationError(send, cls.name); |
5237 return; | 4914 return; |
5238 } | 4915 } |
5239 | 4916 |
5240 // TODO(5347): Try to avoid the need for calling [implementation] before | 4917 // TODO(5347): Try to avoid the need for calling [implementation] before |
5241 // calling [makeStaticArgumentList]. | 4918 // calling [makeStaticArgumentList]. |
5242 constructorImplementation = constructor.implementation; | 4919 constructorImplementation = constructor.implementation; |
5243 if (constructorImplementation.isMalformed || | 4920 if (constructorImplementation.isMalformed || |
5244 !callStructure.signatureApplies( | 4921 !callStructure |
5245 constructorImplementation.functionSignature)) { | 4922 .signatureApplies(constructorImplementation.functionSignature)) { |
5246 generateWrongArgumentCountError(send, constructor, send.arguments); | 4923 generateWrongArgumentCountError(send, constructor, send.arguments); |
5247 return; | 4924 return; |
5248 } | 4925 } |
5249 | 4926 |
5250 var inputs = <HInstruction>[]; | 4927 var inputs = <HInstruction>[]; |
5251 if (constructor.isGenerativeConstructor && | 4928 if (constructor.isGenerativeConstructor && |
5252 backend.isNativeOrExtendsNative(constructor.enclosingClass) && | 4929 backend.isNativeOrExtendsNative(constructor.enclosingClass) && |
5253 !backend.isJsInterop(constructor)) { | 4930 !backend.isJsInterop(constructor)) { |
5254 // Native class generative constructors take a pre-constructed object. | 4931 // Native class generative constructors take a pre-constructed object. |
5255 inputs.add(graph.addConstantNull(compiler)); | 4932 inputs.add(graph.addConstantNull(compiler)); |
5256 } | 4933 } |
5257 inputs.addAll(makeStaticArgumentList(callStructure, | 4934 inputs.addAll(makeStaticArgumentList( |
5258 send.arguments, | 4935 callStructure, send.arguments, constructorImplementation)); |
5259 constructorImplementation)); | |
5260 | 4936 |
5261 TypeMask elementType = computeType(constructor); | 4937 TypeMask elementType = computeType(constructor); |
5262 if (isFixedListConstructorCall) { | 4938 if (isFixedListConstructorCall) { |
5263 if (!inputs[0].isNumber(compiler)) { | 4939 if (!inputs[0].isNumber(compiler)) { |
5264 HTypeConversion conversion = new HTypeConversion( | 4940 HTypeConversion conversion = new HTypeConversion( |
5265 null, HTypeConversion.ARGUMENT_TYPE_CHECK, backend.numType, | 4941 null, |
5266 inputs[0], null); | 4942 HTypeConversion.ARGUMENT_TYPE_CHECK, |
| 4943 backend.numType, |
| 4944 inputs[0], |
| 4945 null); |
5267 add(conversion); | 4946 add(conversion); |
5268 inputs[0] = conversion; | 4947 inputs[0] = conversion; |
5269 } | 4948 } |
5270 js.Template code = js.js.parseForeignJS('new Array(#)'); | 4949 js.Template code = js.js.parseForeignJS('new Array(#)'); |
5271 var behavior = new native.NativeBehavior(); | 4950 var behavior = new native.NativeBehavior(); |
5272 behavior.typesReturned.add(expectedType); | 4951 behavior.typesReturned.add(expectedType); |
5273 // The allocation can throw only if the given length is a double or | 4952 // The allocation can throw only if the given length is a double or |
5274 // outside the unsigned 32 bit range. | 4953 // outside the unsigned 32 bit range. |
5275 // TODO(sra): Array allocation should be an instruction so that canThrow | 4954 // TODO(sra): Array allocation should be an instruction so that canThrow |
5276 // can depend on a length type discovered in optimization. | 4955 // can depend on a length type discovered in optimization. |
5277 bool canThrow = true; | 4956 bool canThrow = true; |
5278 if (inputs[0].isInteger(compiler) && inputs[0] is HConstant) { | 4957 if (inputs[0].isInteger(compiler) && inputs[0] is HConstant) { |
5279 var constant = inputs[0]; | 4958 var constant = inputs[0]; |
5280 int value = constant.constant.primitiveValue; | 4959 int value = constant.constant.primitiveValue; |
5281 if (0 <= value && value < 0x100000000) canThrow = false; | 4960 if (0 <= value && value < 0x100000000) canThrow = false; |
5282 } | 4961 } |
5283 HForeignCode foreign = new HForeignCode(code, elementType, inputs, | 4962 HForeignCode foreign = new HForeignCode(code, elementType, inputs, |
5284 nativeBehavior: behavior, | 4963 nativeBehavior: behavior, |
5285 throwBehavior: canThrow | 4964 throwBehavior: canThrow |
5286 ? native.NativeThrowBehavior.MAY | 4965 ? native.NativeThrowBehavior.MAY |
5287 : native.NativeThrowBehavior.NEVER); | 4966 : native.NativeThrowBehavior.NEVER); |
5288 push(foreign); | 4967 push(foreign); |
5289 TypesInferrer inferrer = compiler.typesTask.typesInferrer; | 4968 TypesInferrer inferrer = compiler.typesTask.typesInferrer; |
5290 if (inferrer.isFixedArrayCheckedForGrowable(send)) { | 4969 if (inferrer.isFixedArrayCheckedForGrowable(send)) { |
5291 js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array'); | 4970 js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array'); |
5292 // We set the instruction as [canThrow] to avoid it being dead code. | 4971 // We set the instruction as [canThrow] to avoid it being dead code. |
5293 // We need a finer grained side effect. | 4972 // We need a finer grained side effect. |
5294 add(new HForeignCode(code, backend.nullType, [stack.last], | 4973 add(new HForeignCode(code, backend.nullType, [stack.last], |
5295 throwBehavior: native.NativeThrowBehavior.MAY)); | 4974 throwBehavior: native.NativeThrowBehavior.MAY)); |
5296 } | 4975 } |
5297 } else if (isGrowableListConstructorCall) { | 4976 } else if (isGrowableListConstructorCall) { |
5298 push(buildLiteralList(<HInstruction>[])); | 4977 push(buildLiteralList(<HInstruction>[])); |
5299 stack.last.instructionType = elementType; | 4978 stack.last.instructionType = elementType; |
5300 } else { | 4979 } else { |
5301 SourceInformation sourceInformation = | 4980 SourceInformation sourceInformation = |
5302 sourceInformationBuilder.buildNew(send); | 4981 sourceInformationBuilder.buildNew(send); |
5303 potentiallyAddTypeArguments(inputs, cls, expectedType); | 4982 potentiallyAddTypeArguments(inputs, cls, expectedType); |
5304 addInlinedInstantiation(expectedType); | 4983 addInlinedInstantiation(expectedType); |
5305 pushInvokeStatic(node, constructor, inputs, | 4984 pushInvokeStatic(node, constructor, inputs, |
(...skipping 10 matching lines...) Expand all Loading... |
5316 if (context != null) { | 4995 if (context != null) { |
5317 context.allocatedFixedLists.add(newInstance); | 4996 context.allocatedFixedLists.add(newInstance); |
5318 } | 4997 } |
5319 } | 4998 } |
5320 | 4999 |
5321 // The List constructor forwards to a Dart static method that does | 5000 // The List constructor forwards to a Dart static method that does |
5322 // not know about the type argument. Therefore we special case | 5001 // not know about the type argument. Therefore we special case |
5323 // this constructor to have the setRuntimeTypeInfo called where | 5002 // this constructor to have the setRuntimeTypeInfo called where |
5324 // the 'new' is done. | 5003 // the 'new' is done. |
5325 if (backend.classNeedsRti(coreClasses.listClass) && | 5004 if (backend.classNeedsRti(coreClasses.listClass) && |
5326 (isFixedListConstructorCall || isGrowableListConstructorCall || | 5005 (isFixedListConstructorCall || |
5327 isJSArrayTypedConstructor)) { | 5006 isGrowableListConstructorCall || |
| 5007 isJSArrayTypedConstructor)) { |
5328 newInstance = handleListConstructor(type, send, pop()); | 5008 newInstance = handleListConstructor(type, send, pop()); |
5329 stack.add(newInstance); | 5009 stack.add(newInstance); |
5330 } | 5010 } |
5331 | 5011 |
5332 // Finally, if we called a redirecting factory constructor, check the type. | 5012 // Finally, if we called a redirecting factory constructor, check the type. |
5333 if (isRedirected) { | 5013 if (isRedirected) { |
5334 HInstruction checked = potentiallyCheckOrTrustType(newInstance, type); | 5014 HInstruction checked = potentiallyCheckOrTrustType(newInstance, type); |
5335 if (checked != newInstance) { | 5015 if (checked != newInstance) { |
5336 pop(); | 5016 pop(); |
5337 stack.add(checked); | 5017 stack.add(checked); |
5338 } | 5018 } |
5339 } | 5019 } |
5340 } | 5020 } |
5341 | 5021 |
5342 void potentiallyAddTypeArguments(List<HInstruction> inputs, ClassElement cls, | 5022 void potentiallyAddTypeArguments( |
5343 InterfaceType expectedType, | 5023 List<HInstruction> inputs, ClassElement cls, InterfaceType expectedType, |
5344 {SourceInformation sourceInformation}) { | 5024 {SourceInformation sourceInformation}) { |
5345 if (!backend.classNeedsRti(cls)) return; | 5025 if (!backend.classNeedsRti(cls)) return; |
5346 assert(expectedType.typeArguments.isEmpty || | 5026 assert(expectedType.typeArguments.isEmpty || |
5347 cls.typeVariables.length == expectedType.typeArguments.length); | 5027 cls.typeVariables.length == expectedType.typeArguments.length); |
5348 expectedType.typeArguments.forEach((DartType argument) { | 5028 expectedType.typeArguments.forEach((DartType argument) { |
5349 inputs.add(analyzeTypeArgument( | 5029 inputs.add( |
5350 argument, sourceInformation: sourceInformation)); | 5030 analyzeTypeArgument(argument, sourceInformation: sourceInformation)); |
5351 }); | 5031 }); |
5352 } | 5032 } |
5353 | 5033 |
5354 /// In checked mode checks the [type] of [node] to be well-bounded. The method | 5034 /// In checked mode checks the [type] of [node] to be well-bounded. The method |
5355 /// returns [:true:] if an error can be statically determined. | 5035 /// returns [:true:] if an error can be statically determined. |
5356 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { | 5036 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { |
5357 if (!compiler.options.enableTypeAssertions) return false; | 5037 if (!compiler.options.enableTypeAssertions) return false; |
5358 | 5038 |
5359 Map<DartType, Set<DartType>> seenChecksMap = | 5039 Map<DartType, Set<DartType>> seenChecksMap = |
5360 new Map<DartType, Set<DartType>>(); | 5040 new Map<DartType, Set<DartType>>(); |
5361 bool definitelyFails = false; | 5041 bool definitelyFails = false; |
5362 | 5042 |
5363 addTypeVariableBoundCheck(GenericType instance, | 5043 addTypeVariableBoundCheck(GenericType instance, DartType typeArgument, |
5364 DartType typeArgument, | 5044 TypeVariableType typeVariable, DartType bound) { |
5365 TypeVariableType typeVariable, | |
5366 DartType bound) { | |
5367 if (definitelyFails) return; | 5045 if (definitelyFails) return; |
5368 | 5046 |
5369 int subtypeRelation = compiler.types.computeSubtypeRelation(typeArgument,
bound); | 5047 int subtypeRelation = |
| 5048 compiler.types.computeSubtypeRelation(typeArgument, bound); |
5370 if (subtypeRelation == Types.IS_SUBTYPE) return; | 5049 if (subtypeRelation == Types.IS_SUBTYPE) return; |
5371 | 5050 |
5372 String message = | 5051 String message = "Can't create an instance of malbounded type '$type': " |
5373 "Can't create an instance of malbounded type '$type': " | |
5374 "'${typeArgument}' is not a subtype of bound '${bound}' for " | 5052 "'${typeArgument}' is not a subtype of bound '${bound}' for " |
5375 "type variable '${typeVariable}' of type " | 5053 "type variable '${typeVariable}' of type " |
5376 "${type == instance | 5054 "${type == instance |
5377 ? "'${type.element.thisType}'" | 5055 ? "'${type.element.thisType}'" |
5378 : "'${instance.element.thisType}' on the supertype " | 5056 : "'${instance.element.thisType}' on the supertype " |
5379 "'${instance}' of '${type}'" | 5057 "'${instance}' of '${type}'" |
5380 }."; | 5058 }."; |
5381 if (subtypeRelation == Types.NOT_SUBTYPE) { | 5059 if (subtypeRelation == Types.NOT_SUBTYPE) { |
5382 generateTypeError(node, message); | 5060 generateTypeError(node, message); |
5383 definitelyFails = true; | 5061 definitelyFails = true; |
5384 return; | 5062 return; |
5385 } else if (subtypeRelation == Types.MAYBE_SUBTYPE) { | 5063 } else if (subtypeRelation == Types.MAYBE_SUBTYPE) { |
5386 Set<DartType> seenChecks = | 5064 Set<DartType> seenChecks = |
5387 seenChecksMap.putIfAbsent(typeArgument, () => new Set<DartType>()); | 5065 seenChecksMap.putIfAbsent(typeArgument, () => new Set<DartType>()); |
5388 if (!seenChecks.contains(bound)) { | 5066 if (!seenChecks.contains(bound)) { |
5389 seenChecks.add(bound); | 5067 seenChecks.add(bound); |
5390 assertIsSubtype(node, typeArgument, bound, message); | 5068 assertIsSubtype(node, typeArgument, bound, message); |
5391 } | 5069 } |
5392 } | 5070 } |
5393 } | 5071 } |
5394 | 5072 |
5395 compiler.types.checkTypeVariableBounds(type, addTypeVariableBoundCheck); | 5073 compiler.types.checkTypeVariableBounds(type, addTypeVariableBoundCheck); |
5396 if (definitelyFails) { | 5074 if (definitelyFails) { |
5397 return true; | 5075 return true; |
5398 } | 5076 } |
5399 for (InterfaceType supertype in type.element.allSupertypes) { | 5077 for (InterfaceType supertype in type.element.allSupertypes) { |
5400 DartType instance = type.asInstanceOf(supertype.element); | 5078 DartType instance = type.asInstanceOf(supertype.element); |
5401 compiler.types.checkTypeVariableBounds(instance, | 5079 compiler.types |
5402 addTypeVariableBoundCheck); | 5080 .checkTypeVariableBounds(instance, addTypeVariableBoundCheck); |
5403 if (definitelyFails) { | 5081 if (definitelyFails) { |
5404 return true; | 5082 return true; |
5405 } | 5083 } |
5406 } | 5084 } |
5407 return false; | 5085 return false; |
5408 } | 5086 } |
5409 | 5087 |
5410 visitStaticSend(ast.Send node) { | 5088 visitStaticSend(ast.Send node) { |
5411 internalError(node, "Unexpected visitStaticSend"); | 5089 internalError(node, "Unexpected visitStaticSend"); |
5412 } | 5090 } |
5413 | 5091 |
5414 /// Generate an invocation to the static or top level [function]. | 5092 /// Generate an invocation to the static or top level [function]. |
5415 void generateStaticFunctionInvoke( | 5093 void generateStaticFunctionInvoke( |
5416 ast.Send node, | 5094 ast.Send node, FunctionElement function, CallStructure callStructure) { |
5417 FunctionElement function, | |
5418 CallStructure callStructure) { | |
5419 List<HInstruction> inputs = makeStaticArgumentList( | 5095 List<HInstruction> inputs = makeStaticArgumentList( |
5420 callStructure, | 5096 callStructure, node.arguments, function.implementation); |
5421 node.arguments, | |
5422 function.implementation); | |
5423 | 5097 |
5424 if (function == compiler.identicalFunction) { | 5098 if (function == compiler.identicalFunction) { |
5425 pushWithPosition( | 5099 pushWithPosition( |
5426 new HIdentity(inputs[0], inputs[1], null, backend.boolType), node); | 5100 new HIdentity(inputs[0], inputs[1], null, backend.boolType), node); |
5427 return; | 5101 return; |
5428 } else { | 5102 } else { |
5429 pushInvokeStatic(node, function, inputs, | 5103 pushInvokeStatic(node, function, inputs, |
5430 sourceInformation: sourceInformationBuilder.buildCall( | 5104 sourceInformation: |
5431 node, node.selector)); | 5105 sourceInformationBuilder.buildCall(node, node.selector)); |
5432 } | 5106 } |
5433 } | 5107 } |
5434 | 5108 |
5435 /// Generate an invocation to a static or top level function with the wrong | 5109 /// Generate an invocation to a static or top level function with the wrong |
5436 /// number of arguments. | 5110 /// number of arguments. |
5437 void generateStaticFunctionIncompatibleInvoke(ast.Send node, | 5111 void generateStaticFunctionIncompatibleInvoke( |
5438 Element element) { | 5112 ast.Send node, Element element) { |
5439 generateWrongArgumentCountError(node, element, node.arguments); | 5113 generateWrongArgumentCountError(node, element, node.arguments); |
5440 } | 5114 } |
5441 | 5115 |
5442 @override | 5116 @override |
5443 void visitStaticFieldInvoke( | 5117 void visitStaticFieldInvoke(ast.Send node, FieldElement field, |
5444 ast.Send node, | 5118 ast.NodeList arguments, CallStructure callStructure, _) { |
5445 FieldElement field, | |
5446 ast.NodeList arguments, | |
5447 CallStructure callStructure, | |
5448 _) { | |
5449 generateStaticFieldGet(node, field); | 5119 generateStaticFieldGet(node, field); |
5450 generateCallInvoke( | 5120 generateCallInvoke(node, pop(), |
5451 node, | |
5452 pop(), | |
5453 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5121 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
5454 } | 5122 } |
5455 | 5123 |
5456 @override | 5124 @override |
5457 void visitStaticFunctionInvoke( | 5125 void visitStaticFunctionInvoke(ast.Send node, MethodElement function, |
5458 ast.Send node, | 5126 ast.NodeList arguments, CallStructure callStructure, _) { |
5459 MethodElement function, | |
5460 ast.NodeList arguments, | |
5461 CallStructure callStructure, | |
5462 _) { | |
5463 generateStaticFunctionInvoke(node, function, callStructure); | 5127 generateStaticFunctionInvoke(node, function, callStructure); |
5464 } | 5128 } |
5465 | 5129 |
5466 @override | 5130 @override |
5467 void visitStaticFunctionIncompatibleInvoke( | 5131 void visitStaticFunctionIncompatibleInvoke( |
5468 ast.Send node, | 5132 ast.Send node, |
5469 MethodElement function, | 5133 MethodElement function, |
5470 ast.NodeList arguments, | 5134 ast.NodeList arguments, |
5471 CallStructure callStructure, | 5135 CallStructure callStructure, |
5472 _) { | 5136 _) { |
5473 generateStaticFunctionIncompatibleInvoke(node, function); | 5137 generateStaticFunctionIncompatibleInvoke(node, function); |
5474 } | 5138 } |
5475 | 5139 |
5476 @override | 5140 @override |
5477 void visitStaticGetterInvoke( | 5141 void visitStaticGetterInvoke(ast.Send node, FunctionElement getter, |
5478 ast.Send node, | 5142 ast.NodeList arguments, CallStructure callStructure, _) { |
5479 FunctionElement getter, | |
5480 ast.NodeList arguments, | |
5481 CallStructure callStructure, | |
5482 _) { | |
5483 generateStaticGetterGet(node, getter); | 5143 generateStaticGetterGet(node, getter); |
5484 generateCallInvoke( | 5144 generateCallInvoke(node, pop(), |
5485 node, | |
5486 pop(), | |
5487 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5145 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
5488 } | 5146 } |
5489 | 5147 |
5490 @override | 5148 @override |
5491 void visitTopLevelFieldInvoke( | 5149 void visitTopLevelFieldInvoke(ast.Send node, FieldElement field, |
5492 ast.Send node, | 5150 ast.NodeList arguments, CallStructure callStructure, _) { |
5493 FieldElement field, | |
5494 ast.NodeList arguments, | |
5495 CallStructure callStructure, | |
5496 _) { | |
5497 generateStaticFieldGet(node, field); | 5151 generateStaticFieldGet(node, field); |
5498 generateCallInvoke( | 5152 generateCallInvoke(node, pop(), |
5499 node, | |
5500 pop(), | |
5501 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5153 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
5502 } | 5154 } |
5503 | 5155 |
5504 @override | 5156 @override |
5505 void visitTopLevelFunctionInvoke( | 5157 void visitTopLevelFunctionInvoke(ast.Send node, MethodElement function, |
5506 ast.Send node, | 5158 ast.NodeList arguments, CallStructure callStructure, _) { |
5507 MethodElement function, | |
5508 ast.NodeList arguments, | |
5509 CallStructure callStructure, | |
5510 _) { | |
5511 if (backend.isForeign(function)) { | 5159 if (backend.isForeign(function)) { |
5512 handleForeignSend(node, function); | 5160 handleForeignSend(node, function); |
5513 } else { | 5161 } else { |
5514 generateStaticFunctionInvoke(node, function, callStructure); | 5162 generateStaticFunctionInvoke(node, function, callStructure); |
5515 } | 5163 } |
5516 } | 5164 } |
5517 | 5165 |
5518 @override | 5166 @override |
5519 void visitTopLevelFunctionIncompatibleInvoke( | 5167 void visitTopLevelFunctionIncompatibleInvoke( |
5520 ast.Send node, | 5168 ast.Send node, |
5521 MethodElement function, | 5169 MethodElement function, |
5522 ast.NodeList arguments, | 5170 ast.NodeList arguments, |
5523 CallStructure callStructure, | 5171 CallStructure callStructure, |
5524 _) { | 5172 _) { |
5525 generateStaticFunctionIncompatibleInvoke(node, function); | 5173 generateStaticFunctionIncompatibleInvoke(node, function); |
5526 } | 5174 } |
5527 | 5175 |
5528 @override | 5176 @override |
5529 void visitTopLevelGetterInvoke( | 5177 void visitTopLevelGetterInvoke(ast.Send node, FunctionElement getter, |
5530 ast.Send node, | 5178 ast.NodeList arguments, CallStructure callStructure, _) { |
5531 FunctionElement getter, | |
5532 ast.NodeList arguments, | |
5533 CallStructure callStructure, | |
5534 _) { | |
5535 generateStaticGetterGet(node, getter); | 5179 generateStaticGetterGet(node, getter); |
5536 generateCallInvoke( | 5180 generateCallInvoke(node, pop(), |
5537 node, | |
5538 pop(), | |
5539 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5181 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
5540 } | 5182 } |
5541 | 5183 |
5542 @override | 5184 @override |
5543 void visitTopLevelSetterGet( | 5185 void visitTopLevelSetterGet(ast.Send node, MethodElement setter, _) { |
5544 ast.Send node, | |
5545 MethodElement setter, | |
5546 _) { | |
5547 handleInvalidStaticGet(node, setter); | 5186 handleInvalidStaticGet(node, setter); |
5548 } | 5187 } |
5549 | 5188 |
5550 @override | 5189 @override |
5551 void visitStaticSetterGet( | 5190 void visitStaticSetterGet(ast.Send node, MethodElement setter, _) { |
5552 ast.Send node, | |
5553 MethodElement setter, | |
5554 _) { | |
5555 handleInvalidStaticGet(node, setter); | 5191 handleInvalidStaticGet(node, setter); |
5556 } | 5192 } |
5557 | 5193 |
5558 @override | 5194 @override |
5559 void visitUnresolvedGet( | 5195 void visitUnresolvedGet(ast.Send node, Element element, _) { |
5560 ast.Send node, | |
5561 Element element, | |
5562 _) { | |
5563 generateStaticUnresolvedGet(node, element); | 5196 generateStaticUnresolvedGet(node, element); |
5564 } | 5197 } |
5565 | 5198 |
5566 void handleInvalidStaticInvoke(ast.Send node, Element element) { | 5199 void handleInvalidStaticInvoke(ast.Send node, Element element) { |
5567 generateThrowNoSuchMethod(node, | 5200 generateThrowNoSuchMethod(node, noSuchMethodTargetSymbolString(element), |
5568 noSuchMethodTargetSymbolString(element), | 5201 argumentNodes: node.arguments); |
5569 argumentNodes: node.arguments); | |
5570 } | 5202 } |
5571 | 5203 |
5572 @override | 5204 @override |
5573 void visitStaticSetterInvoke( | 5205 void visitStaticSetterInvoke(ast.Send node, MethodElement setter, |
5574 ast.Send node, | 5206 ast.NodeList arguments, CallStructure callStructure, _) { |
5575 MethodElement setter, | |
5576 ast.NodeList arguments, | |
5577 CallStructure callStructure, | |
5578 _) { | |
5579 handleInvalidStaticInvoke(node, setter); | 5207 handleInvalidStaticInvoke(node, setter); |
5580 } | 5208 } |
5581 | 5209 |
5582 @override | 5210 @override |
5583 void visitTopLevelSetterInvoke( | 5211 void visitTopLevelSetterInvoke(ast.Send node, MethodElement setter, |
5584 ast.Send node, | 5212 ast.NodeList arguments, CallStructure callStructure, _) { |
5585 MethodElement setter, | |
5586 ast.NodeList arguments, | |
5587 CallStructure callStructure, | |
5588 _) { | |
5589 handleInvalidStaticInvoke(node, setter); | 5213 handleInvalidStaticInvoke(node, setter); |
5590 } | 5214 } |
5591 | 5215 |
5592 @override | 5216 @override |
5593 void visitUnresolvedInvoke( | 5217 void visitUnresolvedInvoke(ast.Send node, Element element, |
5594 ast.Send node, | 5218 ast.NodeList arguments, Selector selector, _) { |
5595 Element element, | |
5596 ast.NodeList arguments, | |
5597 Selector selector, | |
5598 _) { | |
5599 if (element is ErroneousElement) { | 5219 if (element is ErroneousElement) { |
5600 // An erroneous element indicates that the function could not be | 5220 // An erroneous element indicates that the function could not be |
5601 // resolved (a warning has been issued). | 5221 // resolved (a warning has been issued). |
5602 handleInvalidStaticInvoke(node, element); | 5222 handleInvalidStaticInvoke(node, element); |
5603 } else { | 5223 } else { |
5604 // TODO(ahe): Do something like [generateWrongArgumentCountError]. | 5224 // TODO(ahe): Do something like [generateWrongArgumentCountError]. |
5605 stack.add(graph.addConstantNull(compiler)); | 5225 stack.add(graph.addConstantNull(compiler)); |
5606 } | 5226 } |
5607 return; | 5227 return; |
5608 } | 5228 } |
5609 | 5229 |
5610 HConstant addConstantString(String string) { | 5230 HConstant addConstantString(String string) { |
5611 ast.DartString dartString = new ast.DartString.literal(string); | 5231 ast.DartString dartString = new ast.DartString.literal(string); |
5612 return graph.addConstantString(dartString, compiler); | 5232 return graph.addConstantString(dartString, compiler); |
5613 } | 5233 } |
5614 | 5234 |
5615 HConstant addConstantStringFromName(js.Name name) { | 5235 HConstant addConstantStringFromName(js.Name name) { |
5616 return graph.addConstantStringFromName(name, compiler); | 5236 return graph.addConstantStringFromName(name, compiler); |
5617 } | 5237 } |
5618 | 5238 |
5619 visitClassTypeLiteralGet( | 5239 visitClassTypeLiteralGet(ast.Send node, ConstantExpression constant, _) { |
5620 ast.Send node, | |
5621 ConstantExpression constant, | |
5622 _) { | |
5623 generateConstantTypeLiteral(node); | 5240 generateConstantTypeLiteral(node); |
5624 } | 5241 } |
5625 | 5242 |
5626 visitClassTypeLiteralInvoke( | 5243 visitClassTypeLiteralInvoke(ast.Send node, ConstantExpression constant, |
5627 ast.Send node, | 5244 ast.NodeList arguments, CallStructure callStructure, _) { |
5628 ConstantExpression constant, | |
5629 ast.NodeList arguments, | |
5630 CallStructure callStructure, | |
5631 _) { | |
5632 generateConstantTypeLiteral(node); | 5245 generateConstantTypeLiteral(node); |
5633 generateTypeLiteralCall(node); | 5246 generateTypeLiteralCall(node); |
5634 } | 5247 } |
5635 | 5248 |
5636 visitTypedefTypeLiteralGet( | 5249 visitTypedefTypeLiteralGet(ast.Send node, ConstantExpression constant, _) { |
5637 ast.Send node, | |
5638 ConstantExpression constant, | |
5639 _) { | |
5640 generateConstantTypeLiteral(node); | 5250 generateConstantTypeLiteral(node); |
5641 } | 5251 } |
5642 | 5252 |
5643 visitTypedefTypeLiteralInvoke( | 5253 visitTypedefTypeLiteralInvoke(ast.Send node, ConstantExpression constant, |
5644 ast.Send node, | 5254 ast.NodeList arguments, CallStructure callStructure, _) { |
5645 ConstantExpression constant, | |
5646 ast.NodeList arguments, | |
5647 CallStructure callStructure, | |
5648 _) { | |
5649 generateConstantTypeLiteral(node); | 5255 generateConstantTypeLiteral(node); |
5650 generateTypeLiteralCall(node); | 5256 generateTypeLiteralCall(node); |
5651 } | 5257 } |
5652 | 5258 |
5653 visitTypeVariableTypeLiteralGet( | 5259 visitTypeVariableTypeLiteralGet( |
5654 ast.Send node, | 5260 ast.Send node, TypeVariableElement element, _) { |
5655 TypeVariableElement element, | |
5656 _) { | |
5657 generateTypeVariableLiteral(node, element.type); | 5261 generateTypeVariableLiteral(node, element.type); |
5658 } | 5262 } |
5659 | 5263 |
5660 visitTypeVariableTypeLiteralInvoke( | 5264 visitTypeVariableTypeLiteralInvoke(ast.Send node, TypeVariableElement element, |
5661 ast.Send node, | 5265 ast.NodeList arguments, CallStructure callStructure, _) { |
5662 TypeVariableElement element, | |
5663 ast.NodeList arguments, | |
5664 CallStructure callStructure, | |
5665 _) { | |
5666 generateTypeVariableLiteral(node, element.type); | 5266 generateTypeVariableLiteral(node, element.type); |
5667 generateTypeLiteralCall(node); | 5267 generateTypeLiteralCall(node); |
5668 } | 5268 } |
5669 | 5269 |
5670 visitDynamicTypeLiteralGet( | 5270 visitDynamicTypeLiteralGet(ast.Send node, ConstantExpression constant, _) { |
5671 ast.Send node, | |
5672 ConstantExpression constant, | |
5673 _) { | |
5674 generateConstantTypeLiteral(node); | 5271 generateConstantTypeLiteral(node); |
5675 } | 5272 } |
5676 | 5273 |
5677 visitDynamicTypeLiteralInvoke( | 5274 visitDynamicTypeLiteralInvoke(ast.Send node, ConstantExpression constant, |
5678 ast.Send node, | 5275 ast.NodeList arguments, CallStructure callStructure, _) { |
5679 ConstantExpression constant, | |
5680 ast.NodeList arguments, | |
5681 CallStructure callStructure, | |
5682 _) { | |
5683 generateConstantTypeLiteral(node); | 5276 generateConstantTypeLiteral(node); |
5684 generateTypeLiteralCall(node); | 5277 generateTypeLiteralCall(node); |
5685 } | 5278 } |
5686 | 5279 |
5687 /// Generate the constant value for a constant type literal. | 5280 /// Generate the constant value for a constant type literal. |
5688 void generateConstantTypeLiteral(ast.Send node) { | 5281 void generateConstantTypeLiteral(ast.Send node) { |
5689 // TODO(karlklose): add type representation | 5282 // TODO(karlklose): add type representation |
5690 if (node.isCall) { | 5283 if (node.isCall) { |
5691 // The node itself is not a constant but we register the selector (the | 5284 // The node itself is not a constant but we register the selector (the |
5692 // identifier that refers to the class/typedef) as a constant. | 5285 // identifier that refers to the class/typedef) as a constant. |
5693 stack.add(addConstant(node.selector)); | 5286 stack.add(addConstant(node.selector)); |
5694 } else { | 5287 } else { |
5695 stack.add(addConstant(node)); | 5288 stack.add(addConstant(node)); |
5696 } | 5289 } |
5697 } | 5290 } |
5698 | 5291 |
5699 /// Generate the literal for [typeVariable] in the current context. | 5292 /// Generate the literal for [typeVariable] in the current context. |
5700 void generateTypeVariableLiteral(ast.Send node, | 5293 void generateTypeVariableLiteral( |
5701 TypeVariableType typeVariable) { | 5294 ast.Send node, TypeVariableType typeVariable) { |
5702 DartType type = localsHandler.substInContext(typeVariable); | 5295 DartType type = localsHandler.substInContext(typeVariable); |
5703 HInstruction value = analyzeTypeArgument(type, | 5296 HInstruction value = analyzeTypeArgument(type, |
5704 sourceInformation: sourceInformationBuilder.buildGet(node)); | 5297 sourceInformation: sourceInformationBuilder.buildGet(node)); |
5705 pushInvokeStatic(node, | 5298 pushInvokeStatic(node, helpers.runtimeTypeToString, [value], |
5706 helpers.runtimeTypeToString, | 5299 typeMask: backend.stringType); |
5707 [value], | 5300 pushInvokeStatic(node, helpers.createRuntimeType, [pop()]); |
5708 typeMask: backend.stringType); | |
5709 pushInvokeStatic(node, | |
5710 helpers.createRuntimeType, | |
5711 [pop()]); | |
5712 } | 5301 } |
5713 | 5302 |
5714 /// Generate a call to a type literal. | 5303 /// Generate a call to a type literal. |
5715 void generateTypeLiteralCall(ast.Send node) { | 5304 void generateTypeLiteralCall(ast.Send node) { |
5716 // This send is of the form 'e(...)', where e is resolved to a type | 5305 // This send is of the form 'e(...)', where e is resolved to a type |
5717 // reference. We create a regular closure call on the result of the type | 5306 // reference. We create a regular closure call on the result of the type |
5718 // reference instead of creating a NoSuchMethodError to avoid pulling it | 5307 // reference instead of creating a NoSuchMethodError to avoid pulling it |
5719 // in if it is not used (e.g., in a try/catch). | 5308 // in if it is not used (e.g., in a try/catch). |
5720 HInstruction target = pop(); | 5309 HInstruction target = pop(); |
5721 generateCallInvoke(node, target, | 5310 generateCallInvoke(node, target, |
5722 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5311 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
5723 } | 5312 } |
5724 | 5313 |
5725 /// Generate a '.call' invocation on [target]. | 5314 /// Generate a '.call' invocation on [target]. |
5726 void generateCallInvoke(ast.Send node, | 5315 void generateCallInvoke( |
5727 HInstruction target, | 5316 ast.Send node, HInstruction target, SourceInformation sourceInformation) { |
5728 SourceInformation sourceInformation) { | |
5729 Selector selector = elements.getSelector(node); | 5317 Selector selector = elements.getSelector(node); |
5730 List<HInstruction> inputs = <HInstruction>[target]; | 5318 List<HInstruction> inputs = <HInstruction>[target]; |
5731 addDynamicSendArgumentsToList(node, inputs); | 5319 addDynamicSendArgumentsToList(node, inputs); |
5732 push(new HInvokeClosure( | 5320 push(new HInvokeClosure( |
5733 new Selector.callClosureFrom(selector), | 5321 new Selector.callClosureFrom(selector), inputs, backend.dynamicType) |
5734 inputs, backend.dynamicType) | 5322 ..sourceInformation = sourceInformation); |
5735 ..sourceInformation = sourceInformation); | |
5736 } | 5323 } |
5737 | 5324 |
5738 visitGetterSend(ast.Send node) { | 5325 visitGetterSend(ast.Send node) { |
5739 internalError(node, "Unexpected visitGetterSend"); | 5326 internalError(node, "Unexpected visitGetterSend"); |
5740 } | 5327 } |
5741 | 5328 |
5742 // TODO(antonm): migrate rest of SsaFromAstMixin to internalError. | 5329 // TODO(antonm): migrate rest of SsaFromAstMixin to internalError. |
5743 internalError(Spannable node, String reason) { | 5330 internalError(Spannable node, String reason) { |
5744 reporter.internalError(node, reason); | 5331 reporter.internalError(node, reason); |
5745 } | 5332 } |
5746 | 5333 |
5747 void generateError(ast.Node node, String message, Element helper) { | 5334 void generateError(ast.Node node, String message, Element helper) { |
5748 HInstruction errorMessage = addConstantString(message); | 5335 HInstruction errorMessage = addConstantString(message); |
5749 pushInvokeStatic(node, helper, [errorMessage]); | 5336 pushInvokeStatic(node, helper, [errorMessage]); |
5750 } | 5337 } |
5751 | 5338 |
5752 void generateRuntimeError(ast.Node node, String message) { | 5339 void generateRuntimeError(ast.Node node, String message) { |
5753 generateError(node, message, helpers.throwRuntimeError); | 5340 generateError(node, message, helpers.throwRuntimeError); |
5754 } | 5341 } |
5755 | 5342 |
5756 void generateTypeError(ast.Node node, String message) { | 5343 void generateTypeError(ast.Node node, String message) { |
5757 generateError(node, message, helpers.throwTypeError); | 5344 generateError(node, message, helpers.throwTypeError); |
5758 } | 5345 } |
5759 | 5346 |
5760 void generateAbstractClassInstantiationError(ast.Node node, String message) { | 5347 void generateAbstractClassInstantiationError(ast.Node node, String message) { |
5761 generateError(node, | 5348 generateError(node, message, helpers.throwAbstractClassInstantiationError); |
5762 message, | |
5763 helpers.throwAbstractClassInstantiationError); | |
5764 } | 5349 } |
5765 | 5350 |
5766 void generateThrowNoSuchMethod(ast.Node diagnosticNode, | 5351 void generateThrowNoSuchMethod(ast.Node diagnosticNode, String methodName, |
5767 String methodName, | 5352 {Link<ast.Node> argumentNodes, |
5768 {Link<ast.Node> argumentNodes, | 5353 List<HInstruction> argumentValues, |
5769 List<HInstruction> argumentValues, | 5354 List<String> existingArguments, |
5770 List<String> existingArguments, | 5355 SourceInformation sourceInformation}) { |
5771 SourceInformation sourceInformation}) { | |
5772 Element helper = helpers.throwNoSuchMethod; | 5356 Element helper = helpers.throwNoSuchMethod; |
5773 ConstantValue receiverConstant = | 5357 ConstantValue receiverConstant = |
5774 constantSystem.createString(new ast.DartString.empty()); | 5358 constantSystem.createString(new ast.DartString.empty()); |
5775 HInstruction receiver = graph.addConstant(receiverConstant, compiler); | 5359 HInstruction receiver = graph.addConstant(receiverConstant, compiler); |
5776 ast.DartString dartString = new ast.DartString.literal(methodName); | 5360 ast.DartString dartString = new ast.DartString.literal(methodName); |
5777 ConstantValue nameConstant = constantSystem.createString(dartString); | 5361 ConstantValue nameConstant = constantSystem.createString(dartString); |
5778 HInstruction name = graph.addConstant(nameConstant, compiler); | 5362 HInstruction name = graph.addConstant(nameConstant, compiler); |
5779 if (argumentValues == null) { | 5363 if (argumentValues == null) { |
5780 argumentValues = <HInstruction>[]; | 5364 argumentValues = <HInstruction>[]; |
5781 argumentNodes.forEach((argumentNode) { | 5365 argumentNodes.forEach((argumentNode) { |
(...skipping 10 matching lines...) Expand all Loading... |
5792 for (String name in existingArguments) { | 5376 for (String name in existingArguments) { |
5793 HInstruction nameConstant = | 5377 HInstruction nameConstant = |
5794 graph.addConstantString(new ast.DartString.literal(name), compiler); | 5378 graph.addConstantString(new ast.DartString.literal(name), compiler); |
5795 existingNames.add(nameConstant); | 5379 existingNames.add(nameConstant); |
5796 } | 5380 } |
5797 existingNamesList = buildLiteralList(existingNames); | 5381 existingNamesList = buildLiteralList(existingNames); |
5798 add(existingNamesList); | 5382 add(existingNamesList); |
5799 } else { | 5383 } else { |
5800 existingNamesList = graph.addConstantNull(compiler); | 5384 existingNamesList = graph.addConstantNull(compiler); |
5801 } | 5385 } |
5802 pushInvokeStatic(diagnosticNode, | 5386 pushInvokeStatic( |
5803 helper, | 5387 diagnosticNode, helper, [receiver, name, arguments, existingNamesList], |
5804 [receiver, name, arguments, existingNamesList], | 5388 sourceInformation: sourceInformation); |
5805 sourceInformation: sourceInformation); | |
5806 } | 5389 } |
5807 | 5390 |
5808 /** | 5391 /** |
5809 * Generate code to throw a [NoSuchMethodError] exception for calling a | 5392 * Generate code to throw a [NoSuchMethodError] exception for calling a |
5810 * method with a wrong number of arguments or mismatching named optional | 5393 * method with a wrong number of arguments or mismatching named optional |
5811 * arguments. | 5394 * arguments. |
5812 */ | 5395 */ |
5813 void generateWrongArgumentCountError(ast.Node diagnosticNode, | 5396 void generateWrongArgumentCountError(ast.Node diagnosticNode, |
5814 FunctionElement function, | 5397 FunctionElement function, Link<ast.Node> argumentNodes) { |
5815 Link<ast.Node> argumentNodes) { | |
5816 List<String> existingArguments = <String>[]; | 5398 List<String> existingArguments = <String>[]; |
5817 FunctionSignature signature = function.functionSignature; | 5399 FunctionSignature signature = function.functionSignature; |
5818 signature.forEachParameter((Element parameter) { | 5400 signature.forEachParameter((Element parameter) { |
5819 existingArguments.add(parameter.name); | 5401 existingArguments.add(parameter.name); |
5820 }); | 5402 }); |
5821 generateThrowNoSuchMethod(diagnosticNode, | 5403 generateThrowNoSuchMethod(diagnosticNode, function.name, |
5822 function.name, | 5404 argumentNodes: argumentNodes, existingArguments: existingArguments); |
5823 argumentNodes: argumentNodes, | |
5824 existingArguments: existingArguments); | |
5825 } | 5405 } |
5826 | 5406 |
5827 @override | 5407 @override |
5828 void bulkHandleNode(ast.Node node, String message, _) { | 5408 void bulkHandleNode(ast.Node node, String message, _) { |
5829 internalError(node, "Unexpected bulk handled node: $node"); | 5409 internalError(node, "Unexpected bulk handled node: $node"); |
5830 } | 5410 } |
5831 | 5411 |
5832 @override | 5412 @override |
5833 void bulkHandleNew(ast.NewExpression node, [_]) { | 5413 void bulkHandleNew(ast.NewExpression node, [_]) { |
5834 Element element = elements[node.send]; | 5414 Element element = elements[node.send]; |
5835 final bool isSymbolConstructor = element == compiler.symbolConstructor; | 5415 final bool isSymbolConstructor = element == compiler.symbolConstructor; |
5836 if (!Elements.isMalformed(element)) { | 5416 if (!Elements.isMalformed(element)) { |
5837 ConstructorElement function = element; | 5417 ConstructorElement function = element; |
5838 element = function.effectiveTarget; | 5418 element = function.effectiveTarget; |
5839 } | 5419 } |
5840 if (Elements.isError(element)) { | 5420 if (Elements.isError(element)) { |
5841 ErroneousElement error = element; | 5421 ErroneousElement error = element; |
5842 if (error.messageKind == MessageKind.CANNOT_FIND_CONSTRUCTOR || | 5422 if (error.messageKind == MessageKind.CANNOT_FIND_CONSTRUCTOR || |
5843 error.messageKind == MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR) { | 5423 error.messageKind == MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR) { |
5844 generateThrowNoSuchMethod( | 5424 generateThrowNoSuchMethod( |
5845 node.send, | 5425 node.send, noSuchMethodTargetSymbolString(error, 'constructor'), |
5846 noSuchMethodTargetSymbolString(error, 'constructor'), | |
5847 argumentNodes: node.send.arguments); | 5426 argumentNodes: node.send.arguments); |
5848 } else { | 5427 } else { |
5849 MessageTemplate template = MessageTemplate.TEMPLATES[error.messageKind]; | 5428 MessageTemplate template = MessageTemplate.TEMPLATES[error.messageKind]; |
5850 Message message = template.message(error.messageArguments); | 5429 Message message = template.message(error.messageArguments); |
5851 generateRuntimeError(node.send, message.toString()); | 5430 generateRuntimeError(node.send, message.toString()); |
5852 } | 5431 } |
5853 } else if (Elements.isMalformed(element)) { | 5432 } else if (Elements.isMalformed(element)) { |
5854 // TODO(ahe): Do something like [generateWrongArgumentCountError]. | 5433 // TODO(ahe): Do something like [generateWrongArgumentCountError]. |
5855 stack.add(graph.addConstantNull(compiler)); | 5434 stack.add(graph.addConstantNull(compiler)); |
5856 } else if (node.isConst) { | 5435 } else if (node.isConst) { |
(...skipping 13 matching lines...) Expand all Loading... |
5870 void errorNonConstantConstructorInvoke( | 5449 void errorNonConstantConstructorInvoke( |
5871 ast.NewExpression node, | 5450 ast.NewExpression node, |
5872 Element element, | 5451 Element element, |
5873 DartType type, | 5452 DartType type, |
5874 ast.NodeList arguments, | 5453 ast.NodeList arguments, |
5875 CallStructure callStructure, | 5454 CallStructure callStructure, |
5876 _) { | 5455 _) { |
5877 bulkHandleNew(node); | 5456 bulkHandleNew(node); |
5878 } | 5457 } |
5879 | 5458 |
5880 void pushInvokeDynamic(ast.Node node, | 5459 void pushInvokeDynamic(ast.Node node, Selector selector, TypeMask mask, |
5881 Selector selector, | 5460 List<HInstruction> arguments, |
5882 TypeMask mask, | 5461 {SourceInformation sourceInformation}) { |
5883 List<HInstruction> arguments, | |
5884 {SourceInformation sourceInformation}) { | |
5885 | |
5886 // We prefer to not inline certain operations on indexables, | 5462 // We prefer to not inline certain operations on indexables, |
5887 // because the constant folder will handle them better and turn | 5463 // because the constant folder will handle them better and turn |
5888 // them into simpler instructions that allow further | 5464 // them into simpler instructions that allow further |
5889 // optimizations. | 5465 // optimizations. |
5890 bool isOptimizableOperationOnIndexable(Selector selector, Element element) { | 5466 bool isOptimizableOperationOnIndexable(Selector selector, Element element) { |
5891 bool isLength = selector.isGetter | 5467 bool isLength = selector.isGetter && selector.name == "length"; |
5892 && selector.name == "length"; | |
5893 if (isLength || selector.isIndex) { | 5468 if (isLength || selector.isIndex) { |
5894 return compiler.world.isSubtypeOf( | 5469 return compiler.world.isSubtypeOf( |
5895 element.enclosingClass.declaration, | 5470 element.enclosingClass.declaration, helpers.jsIndexableClass); |
5896 helpers.jsIndexableClass); | |
5897 } else if (selector.isIndexSet) { | 5471 } else if (selector.isIndexSet) { |
5898 return compiler.world.isSubtypeOf( | 5472 return compiler.world.isSubtypeOf(element.enclosingClass.declaration, |
5899 element.enclosingClass.declaration, | |
5900 helpers.jsMutableIndexableClass); | 5473 helpers.jsMutableIndexableClass); |
5901 } else { | 5474 } else { |
5902 return false; | 5475 return false; |
5903 } | 5476 } |
5904 } | 5477 } |
5905 | 5478 |
5906 bool isOptimizableOperation(Selector selector, Element element) { | 5479 bool isOptimizableOperation(Selector selector, Element element) { |
5907 ClassElement cls = element.enclosingClass; | 5480 ClassElement cls = element.enclosingClass; |
5908 if (isOptimizableOperationOnIndexable(selector, element)) return true; | 5481 if (isOptimizableOperationOnIndexable(selector, element)) return true; |
5909 if (!backend.interceptedClasses.contains(cls)) return false; | 5482 if (!backend.interceptedClasses.contains(cls)) return false; |
(...skipping 23 matching lines...) Expand all Loading... |
5933 HInstruction receiver = arguments[0]; | 5506 HInstruction receiver = arguments[0]; |
5934 List<HInstruction> inputs = <HInstruction>[]; | 5507 List<HInstruction> inputs = <HInstruction>[]; |
5935 bool isIntercepted = backend.isInterceptedSelector(selector); | 5508 bool isIntercepted = backend.isInterceptedSelector(selector); |
5936 if (isIntercepted) { | 5509 if (isIntercepted) { |
5937 inputs.add(invokeInterceptor(receiver)); | 5510 inputs.add(invokeInterceptor(receiver)); |
5938 } | 5511 } |
5939 inputs.addAll(arguments); | 5512 inputs.addAll(arguments); |
5940 TypeMask type = | 5513 TypeMask type = |
5941 TypeMaskFactory.inferredTypeForSelector(selector, mask, compiler); | 5514 TypeMaskFactory.inferredTypeForSelector(selector, mask, compiler); |
5942 if (selector.isGetter) { | 5515 if (selector.isGetter) { |
5943 push( | 5516 push(new HInvokeDynamicGetter(selector, mask, null, inputs, type) |
5944 new HInvokeDynamicGetter(selector, mask, null, inputs, type) | 5517 ..sourceInformation = sourceInformation); |
5945 ..sourceInformation = sourceInformation); | |
5946 } else if (selector.isSetter) { | 5518 } else if (selector.isSetter) { |
5947 push( | 5519 push(new HInvokeDynamicSetter(selector, mask, null, inputs, type) |
5948 new HInvokeDynamicSetter(selector, mask, null, inputs, type) | 5520 ..sourceInformation = sourceInformation); |
5949 ..sourceInformation = sourceInformation); | |
5950 } else { | 5521 } else { |
5951 push( | 5522 push(new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) |
5952 new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) | 5523 ..sourceInformation = sourceInformation); |
5953 ..sourceInformation = sourceInformation); | |
5954 } | 5524 } |
5955 } | 5525 } |
5956 | 5526 |
5957 bool _hasNamedParameters(FunctionElement function) { | 5527 bool _hasNamedParameters(FunctionElement function) { |
5958 FunctionSignature params = function.functionSignature; | 5528 FunctionSignature params = function.functionSignature; |
5959 return params.optionalParameterCount > 0 | 5529 return params.optionalParameterCount > 0 && |
5960 && params.optionalParametersAreNamed; | 5530 params.optionalParametersAreNamed; |
5961 } | 5531 } |
5962 | 5532 |
5963 HForeignCode invokeJsInteropFunction(FunctionElement element, | 5533 HForeignCode invokeJsInteropFunction(FunctionElement element, |
5964 List<HInstruction> arguments, | 5534 List<HInstruction> arguments, SourceInformation sourceInformation) { |
5965 SourceInformation sourceInformation) { | |
5966 assert(backend.isJsInterop(element)); | 5535 assert(backend.isJsInterop(element)); |
5967 nativeEmitter.nativeMethods.add(element); | 5536 nativeEmitter.nativeMethods.add(element); |
5968 String templateString; | 5537 String templateString; |
5969 | 5538 |
5970 if (element.isFactoryConstructor && | 5539 if (element.isFactoryConstructor && |
5971 backend.jsInteropAnalysis.hasAnonymousAnnotation(element.contextClass))
{ | 5540 backend.jsInteropAnalysis |
| 5541 .hasAnonymousAnnotation(element.contextClass)) { |
5972 // Factory constructor that is syntactic sugar for creating a JavaScript | 5542 // Factory constructor that is syntactic sugar for creating a JavaScript |
5973 // object literal. | 5543 // object literal. |
5974 ConstructorElement constructor = element; | 5544 ConstructorElement constructor = element; |
5975 FunctionSignature params = constructor.functionSignature; | 5545 FunctionSignature params = constructor.functionSignature; |
5976 int i = 0; | 5546 int i = 0; |
5977 int positions = 0; | 5547 int positions = 0; |
5978 var filteredArguments = <HInstruction>[]; | 5548 var filteredArguments = <HInstruction>[]; |
5979 var parameterNameMap = new Map<String, js.Expression>(); | 5549 var parameterNameMap = new Map<String, js.Expression>(); |
5980 params.orderedForEachParameter((ParameterElement parameter) { | 5550 params.orderedForEachParameter((ParameterElement parameter) { |
5981 // TODO(jacobr): throw if parameter names do not match names of property | 5551 // TODO(jacobr): throw if parameter names do not match names of property |
5982 // names in the class. | 5552 // names in the class. |
5983 assert (parameter.isNamed); | 5553 assert(parameter.isNamed); |
5984 HInstruction argument = arguments[i]; | 5554 HInstruction argument = arguments[i]; |
5985 if (argument != null) { | 5555 if (argument != null) { |
5986 filteredArguments.add(argument); | 5556 filteredArguments.add(argument); |
5987 parameterNameMap[parameter.name] = | 5557 parameterNameMap[parameter.name] = |
5988 new js.InterpolatedExpression(positions++); | 5558 new js.InterpolatedExpression(positions++); |
5989 } | 5559 } |
5990 i++; | 5560 i++; |
5991 }); | 5561 }); |
5992 var codeTemplate = new js.Template(null, | 5562 var codeTemplate = |
5993 js.objectLiteral(parameterNameMap)); | 5563 new js.Template(null, js.objectLiteral(parameterNameMap)); |
5994 | 5564 |
5995 var nativeBehavior = new native.NativeBehavior() | 5565 var nativeBehavior = new native.NativeBehavior() |
5996 ..codeTemplate = codeTemplate; | 5566 ..codeTemplate = codeTemplate; |
5997 if (compiler.options.trustJSInteropTypeAnnotations) { | 5567 if (compiler.options.trustJSInteropTypeAnnotations) { |
5998 nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType); | 5568 nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType); |
5999 } | 5569 } |
6000 return new HForeignCode( | 5570 return new HForeignCode( |
6001 codeTemplate, | 5571 codeTemplate, backend.dynamicType, filteredArguments, |
6002 backend.dynamicType, filteredArguments, | |
6003 nativeBehavior: nativeBehavior) | 5572 nativeBehavior: nativeBehavior) |
6004 ..sourceInformation = sourceInformation; | 5573 ..sourceInformation = sourceInformation; |
6005 } | 5574 } |
6006 var target = new HForeignCode(js.js.parseForeignJS( | 5575 var target = new HForeignCode( |
6007 "${backend.namer.fixedBackendPath(element)}." | 5576 js.js.parseForeignJS("${backend.namer.fixedBackendPath(element)}." |
6008 "${backend.nativeData.getFixedBackendName(element)}"), | 5577 "${backend.nativeData.getFixedBackendName(element)}"), |
6009 backend.dynamicType, | 5578 backend.dynamicType, |
6010 <HInstruction>[]); | 5579 <HInstruction>[]); |
6011 add(target); | 5580 add(target); |
6012 // Strip off trailing arguments that were not specified. | 5581 // Strip off trailing arguments that were not specified. |
6013 // we could assert that the trailing arguments are all null. | 5582 // we could assert that the trailing arguments are all null. |
6014 // TODO(jacobr): rewrite named arguments to an object literal matching | 5583 // TODO(jacobr): rewrite named arguments to an object literal matching |
6015 // the factory constructor case. | 5584 // the factory constructor case. |
6016 arguments = arguments.where((arg) => arg != null).toList(); | 5585 arguments = arguments.where((arg) => arg != null).toList(); |
6017 var inputs = <HInstruction>[target]..addAll(arguments); | 5586 var inputs = <HInstruction>[target]..addAll(arguments); |
6018 | 5587 |
6019 var nativeBehavior = new native.NativeBehavior() | 5588 var nativeBehavior = new native.NativeBehavior() |
6020 ..sideEffects.setAllSideEffects(); | 5589 ..sideEffects.setAllSideEffects(); |
6021 | 5590 |
6022 DartType type = element.isConstructor ? | 5591 DartType type = element.isConstructor |
6023 element.enclosingClass.thisType : element.type.returnType; | 5592 ? element.enclosingClass.thisType |
| 5593 : element.type.returnType; |
6024 // Native behavior effects here are similar to native/behavior.dart. | 5594 // Native behavior effects here are similar to native/behavior.dart. |
6025 // The return type is dynamic if we don't trust js-interop type | 5595 // The return type is dynamic if we don't trust js-interop type |
6026 // declarations. | 5596 // declarations. |
6027 nativeBehavior.typesReturned.add( | 5597 nativeBehavior.typesReturned.add(compiler |
6028 compiler.options.trustJSInteropTypeAnnotations | 5598 .options.trustJSInteropTypeAnnotations ? type : const DynamicType()); |
6029 ? type : const DynamicType()); | |
6030 | 5599 |
6031 // The allocation effects include the declared type if it is native (which | 5600 // The allocation effects include the declared type if it is native (which |
6032 // includes js interop types). | 5601 // includes js interop types). |
6033 if (type.element != null && backend.isNative(type.element)) { | 5602 if (type.element != null && backend.isNative(type.element)) { |
6034 nativeBehavior.typesInstantiated.add(type); | 5603 nativeBehavior.typesInstantiated.add(type); |
6035 } | 5604 } |
6036 | 5605 |
6037 // It also includes any other JS interop type if we don't trust the | 5606 // It also includes any other JS interop type if we don't trust the |
6038 // annotation or if is declared too broad. | 5607 // annotation or if is declared too broad. |
6039 if (!compiler.options.trustJSInteropTypeAnnotations || type.isObject || | 5608 if (!compiler.options.trustJSInteropTypeAnnotations || |
| 5609 type.isObject || |
6040 type.isDynamic) { | 5610 type.isDynamic) { |
6041 nativeBehavior.typesInstantiated.add( | 5611 nativeBehavior.typesInstantiated |
6042 backend.helpers.jsJavaScriptObjectClass.thisType); | 5612 .add(backend.helpers.jsJavaScriptObjectClass.thisType); |
6043 } | 5613 } |
6044 | 5614 |
6045 String code; | 5615 String code; |
6046 if (element.isGetter) { | 5616 if (element.isGetter) { |
6047 code = "#"; | 5617 code = "#"; |
6048 } else if (element.isSetter) { | 5618 } else if (element.isSetter) { |
6049 code = "# = #"; | 5619 code = "# = #"; |
6050 } else { | 5620 } else { |
6051 var args = new List.filled(arguments.length, '#').join(','); | 5621 var args = new List.filled(arguments.length, '#').join(','); |
6052 code = element.isConstructor ? "new #($args)" : "#($args)"; | 5622 code = element.isConstructor ? "new #($args)" : "#($args)"; |
6053 } | 5623 } |
6054 js.Template codeTemplate = js.js.parseForeignJS(code); | 5624 js.Template codeTemplate = js.js.parseForeignJS(code); |
6055 nativeBehavior.codeTemplate = codeTemplate; | 5625 nativeBehavior.codeTemplate = codeTemplate; |
6056 | 5626 |
6057 return new HForeignCode( | 5627 return new HForeignCode(codeTemplate, backend.dynamicType, inputs, |
6058 codeTemplate, | 5628 nativeBehavior: nativeBehavior)..sourceInformation = sourceInformation; |
6059 backend.dynamicType, inputs, | |
6060 nativeBehavior: nativeBehavior) | |
6061 ..sourceInformation = sourceInformation; | |
6062 } | 5629 } |
6063 | 5630 |
6064 void pushInvokeStatic(ast.Node location, | 5631 void pushInvokeStatic( |
6065 Element element, | 5632 ast.Node location, Element element, List<HInstruction> arguments, |
6066 List<HInstruction> arguments, | 5633 {TypeMask typeMask, |
6067 {TypeMask typeMask, | 5634 InterfaceType instanceType, |
6068 InterfaceType instanceType, | 5635 SourceInformation sourceInformation}) { |
6069 SourceInformation sourceInformation}) { | |
6070 // TODO(johnniwinther): Use [sourceInformation] instead of [location]. | 5636 // TODO(johnniwinther): Use [sourceInformation] instead of [location]. |
6071 if (tryInlineMethod(element, null, null, arguments, location, | 5637 if (tryInlineMethod(element, null, null, arguments, location, |
6072 instanceType: instanceType)) { | 5638 instanceType: instanceType)) { |
6073 return; | 5639 return; |
6074 } | 5640 } |
6075 | 5641 |
6076 if (typeMask == null) { | 5642 if (typeMask == null) { |
6077 typeMask = | 5643 typeMask = |
6078 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); | 5644 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); |
6079 } | 5645 } |
6080 bool targetCanThrow = !compiler.world.getCannotThrow(element); | 5646 bool targetCanThrow = !compiler.world.getCannotThrow(element); |
6081 // TODO(5346): Try to avoid the need for calling [declaration] before | 5647 // TODO(5346): Try to avoid the need for calling [declaration] before |
6082 var instruction; | 5648 var instruction; |
6083 if (backend.isJsInterop(element)) { | 5649 if (backend.isJsInterop(element)) { |
6084 instruction = invokeJsInteropFunction(element, arguments, | 5650 instruction = |
6085 sourceInformation); | 5651 invokeJsInteropFunction(element, arguments, sourceInformation); |
6086 } else { | 5652 } else { |
6087 // creating an [HInvokeStatic]. | 5653 // creating an [HInvokeStatic]. |
6088 instruction = new HInvokeStatic( | 5654 instruction = new HInvokeStatic(element.declaration, arguments, typeMask, |
6089 element.declaration, arguments, typeMask, | |
6090 targetCanThrow: targetCanThrow) | 5655 targetCanThrow: targetCanThrow) |
6091 ..sourceInformation = sourceInformation; | 5656 ..sourceInformation = sourceInformation; |
6092 if (!currentInlinedInstantiations.isEmpty) { | 5657 if (!currentInlinedInstantiations.isEmpty) { |
6093 instruction.instantiatedTypes = new List<DartType>.from( | 5658 instruction.instantiatedTypes = |
6094 currentInlinedInstantiations); | 5659 new List<DartType>.from(currentInlinedInstantiations); |
6095 } | 5660 } |
6096 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element); | 5661 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element); |
6097 } | 5662 } |
6098 if (location == null) { | 5663 if (location == null) { |
6099 push(instruction); | 5664 push(instruction); |
6100 } else { | 5665 } else { |
6101 pushWithPosition(instruction, location); | 5666 pushWithPosition(instruction, location); |
6102 } | 5667 } |
6103 } | 5668 } |
6104 | 5669 |
6105 HInstruction buildInvokeSuper(Selector selector, | 5670 HInstruction buildInvokeSuper( |
6106 Element element, | 5671 Selector selector, Element element, List<HInstruction> arguments, |
6107 List<HInstruction> arguments, | 5672 [SourceInformation sourceInformation]) { |
6108 [SourceInformation sourceInformation]) { | |
6109 HInstruction receiver = localsHandler.readThis(); | 5673 HInstruction receiver = localsHandler.readThis(); |
6110 // TODO(5346): Try to avoid the need for calling [declaration] before | 5674 // TODO(5346): Try to avoid the need for calling [declaration] before |
6111 // creating an [HStatic]. | 5675 // creating an [HStatic]. |
6112 List<HInstruction> inputs = <HInstruction>[]; | 5676 List<HInstruction> inputs = <HInstruction>[]; |
6113 if (backend.isInterceptedSelector(selector) && | 5677 if (backend.isInterceptedSelector(selector) && |
6114 // Fields don't need an interceptor; consider generating HFieldGet/Set | 5678 // Fields don't need an interceptor; consider generating HFieldGet/Set |
6115 // instead. | 5679 // instead. |
6116 element.kind != ElementKind.FIELD) { | 5680 element.kind != ElementKind.FIELD) { |
6117 inputs.add(invokeInterceptor(receiver)); | 5681 inputs.add(invokeInterceptor(receiver)); |
6118 } | 5682 } |
6119 inputs.add(receiver); | 5683 inputs.add(receiver); |
6120 inputs.addAll(arguments); | 5684 inputs.addAll(arguments); |
6121 TypeMask type; | 5685 TypeMask type; |
6122 if (!element.isGetter && selector.isGetter) { | 5686 if (!element.isGetter && selector.isGetter) { |
6123 type = TypeMaskFactory.inferredTypeForElement(element, compiler); | 5687 type = TypeMaskFactory.inferredTypeForElement(element, compiler); |
6124 } else { | 5688 } else { |
6125 type = TypeMaskFactory.inferredReturnTypeForElement(element, compiler); | 5689 type = TypeMaskFactory.inferredReturnTypeForElement(element, compiler); |
6126 } | 5690 } |
6127 HInstruction instruction = new HInvokeSuper( | 5691 HInstruction instruction = new HInvokeSuper(element, currentNonClosureClass, |
6128 element, | 5692 selector, inputs, type, sourceInformation, |
6129 currentNonClosureClass, | |
6130 selector, | |
6131 inputs, | |
6132 type, | |
6133 sourceInformation, | |
6134 isSetter: selector.isSetter || selector.isIndexSet); | 5693 isSetter: selector.isSetter || selector.isIndexSet); |
6135 instruction.sideEffects = | 5694 instruction.sideEffects = |
6136 compiler.world.getSideEffectsOfSelector(selector, null); | 5695 compiler.world.getSideEffectsOfSelector(selector, null); |
6137 return instruction; | 5696 return instruction; |
6138 } | 5697 } |
6139 | 5698 |
6140 void handleComplexOperatorSend(ast.SendSet node, | 5699 void handleComplexOperatorSend( |
6141 HInstruction receiver, | 5700 ast.SendSet node, HInstruction receiver, Link<ast.Node> arguments) { |
6142 Link<ast.Node> arguments) { | |
6143 HInstruction rhs; | 5701 HInstruction rhs; |
6144 if (node.isPrefix || node.isPostfix) { | 5702 if (node.isPrefix || node.isPostfix) { |
6145 rhs = graph.addConstantInt(1, compiler); | 5703 rhs = graph.addConstantInt(1, compiler); |
6146 } else { | 5704 } else { |
6147 visit(arguments.head); | 5705 visit(arguments.head); |
6148 assert(arguments.tail.isEmpty); | 5706 assert(arguments.tail.isEmpty); |
6149 rhs = pop(); | 5707 rhs = pop(); |
6150 } | 5708 } |
6151 visitBinarySend( | 5709 visitBinarySend( |
6152 receiver, | 5710 receiver, |
6153 rhs, | 5711 rhs, |
6154 elements.getOperatorSelectorInComplexSendSet(node), | 5712 elements.getOperatorSelectorInComplexSendSet(node), |
6155 elements.getOperatorTypeMaskInComplexSendSet(node), | 5713 elements.getOperatorTypeMaskInComplexSendSet(node), |
6156 node, | 5714 node, |
6157 sourceInformation: | 5715 sourceInformation: |
6158 sourceInformationBuilder.buildGeneric(node.assignmentOperator)); | 5716 sourceInformationBuilder.buildGeneric(node.assignmentOperator)); |
6159 } | 5717 } |
6160 | 5718 |
6161 void handleSuperSendSet(ast.SendSet node) { | 5719 void handleSuperSendSet(ast.SendSet node) { |
6162 Element element = elements[node]; | 5720 Element element = elements[node]; |
6163 List<HInstruction> setterInputs = <HInstruction>[]; | 5721 List<HInstruction> setterInputs = <HInstruction>[]; |
6164 void generateSuperSendSet() { | 5722 void generateSuperSendSet() { |
6165 Selector setterSelector = elements.getSelector(node); | 5723 Selector setterSelector = elements.getSelector(node); |
6166 if (Elements.isUnresolved(element) | 5724 if (Elements.isUnresolved(element) || |
6167 || !setterSelector.applies(element, compiler.world)) { | 5725 !setterSelector.applies(element, compiler.world)) { |
6168 generateSuperNoSuchMethodSend( | 5726 generateSuperNoSuchMethodSend(node, setterSelector, setterInputs); |
6169 node, setterSelector, setterInputs); | |
6170 pop(); | 5727 pop(); |
6171 } else { | 5728 } else { |
6172 add(buildInvokeSuper(setterSelector, element, setterInputs)); | 5729 add(buildInvokeSuper(setterSelector, element, setterInputs)); |
6173 } | 5730 } |
6174 } | 5731 } |
6175 if (identical(node.assignmentOperator.source, '=')) { | 5732 if (identical(node.assignmentOperator.source, '=')) { |
6176 addDynamicSendArgumentsToList(node, setterInputs); | 5733 addDynamicSendArgumentsToList(node, setterInputs); |
6177 generateSuperSendSet(); | 5734 generateSuperSendSet(); |
6178 stack.add(setterInputs.last); | 5735 stack.add(setterInputs.last); |
6179 } else { | 5736 } else { |
6180 Element getter = elements[node.selector]; | 5737 Element getter = elements[node.selector]; |
6181 List<HInstruction> getterInputs = <HInstruction>[]; | 5738 List<HInstruction> getterInputs = <HInstruction>[]; |
6182 Link<ast.Node> arguments = node.arguments; | 5739 Link<ast.Node> arguments = node.arguments; |
6183 if (node.isIndex) { | 5740 if (node.isIndex) { |
6184 // If node is of the form [:super.foo[0] += 2:], the send has | 5741 // If node is of the form [:super.foo[0] += 2:], the send has |
6185 // two arguments: the index and the left hand side. We get | 5742 // two arguments: the index and the left hand side. We get |
6186 // the index and add it as input of the getter and the | 5743 // the index and add it as input of the getter and the |
6187 // setter. | 5744 // setter. |
6188 visit(arguments.head); | 5745 visit(arguments.head); |
6189 arguments = arguments.tail; | 5746 arguments = arguments.tail; |
6190 HInstruction index = pop(); | 5747 HInstruction index = pop(); |
6191 getterInputs.add(index); | 5748 getterInputs.add(index); |
6192 setterInputs.add(index); | 5749 setterInputs.add(index); |
6193 } | 5750 } |
6194 HInstruction getterInstruction; | 5751 HInstruction getterInstruction; |
6195 Selector getterSelector = | 5752 Selector getterSelector = |
6196 elements.getGetterSelectorInComplexSendSet(node); | 5753 elements.getGetterSelectorInComplexSendSet(node); |
6197 if (Elements.isUnresolved(getter)) { | 5754 if (Elements.isUnresolved(getter)) { |
6198 generateSuperNoSuchMethodSend( | 5755 generateSuperNoSuchMethodSend(node, getterSelector, getterInputs); |
6199 node, | |
6200 getterSelector, | |
6201 getterInputs); | |
6202 getterInstruction = pop(); | 5756 getterInstruction = pop(); |
6203 } else { | 5757 } else { |
6204 getterInstruction = buildInvokeSuper( | 5758 getterInstruction = |
6205 getterSelector, getter, getterInputs); | 5759 buildInvokeSuper(getterSelector, getter, getterInputs); |
6206 add(getterInstruction); | 5760 add(getterInstruction); |
6207 } | 5761 } |
6208 | 5762 |
6209 if (node.isIfNullAssignment) { | 5763 if (node.isIfNullAssignment) { |
6210 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5764 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
6211 brancher.handleIfNull(() => stack.add(getterInstruction), | 5765 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
6212 () { | 5766 addDynamicSendArgumentsToList(node, setterInputs); |
6213 addDynamicSendArgumentsToList(node, setterInputs); | 5767 generateSuperSendSet(); |
6214 generateSuperSendSet(); | 5768 stack.add(setterInputs.last); |
6215 stack.add(setterInputs.last); | 5769 }); |
6216 }); | |
6217 } else { | 5770 } else { |
6218 handleComplexOperatorSend(node, getterInstruction, arguments); | 5771 handleComplexOperatorSend(node, getterInstruction, arguments); |
6219 setterInputs.add(pop()); | 5772 setterInputs.add(pop()); |
6220 generateSuperSendSet(); | 5773 generateSuperSendSet(); |
6221 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); | 5774 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); |
6222 } | 5775 } |
6223 } | 5776 } |
6224 } | 5777 } |
6225 | 5778 |
6226 @override | 5779 @override |
6227 void handleSuperCompounds( | 5780 void handleSuperCompounds( |
6228 ast.SendSet node, | 5781 ast.SendSet node, |
6229 Element getter, | 5782 Element getter, |
6230 CompoundGetter getterKind, | 5783 CompoundGetter getterKind, |
6231 Element setter, | 5784 Element setter, |
6232 CompoundSetter setterKind, | 5785 CompoundSetter setterKind, |
6233 CompoundRhs rhs, | 5786 CompoundRhs rhs, |
6234 _) { | 5787 _) { |
6235 handleSuperSendSet(node); | 5788 handleSuperSendSet(node); |
6236 } | 5789 } |
6237 | 5790 |
6238 @override | 5791 @override |
6239 void visitFinalSuperFieldSet( | 5792 void visitFinalSuperFieldSet( |
6240 ast.SendSet node, | 5793 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
6241 FieldElement field, | |
6242 ast.Node rhs, | |
6243 _) { | |
6244 handleSuperSendSet(node); | 5794 handleSuperSendSet(node); |
6245 } | 5795 } |
6246 | 5796 |
6247 @override | 5797 @override |
6248 void visitSuperFieldSet( | 5798 void visitSuperFieldSet( |
6249 ast.SendSet node, | 5799 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
6250 FieldElement field, | |
6251 ast.Node rhs, | |
6252 _) { | |
6253 handleSuperSendSet(node); | 5800 handleSuperSendSet(node); |
6254 } | 5801 } |
6255 | 5802 |
6256 @override | 5803 @override |
6257 void visitSuperGetterSet( | 5804 void visitSuperGetterSet( |
6258 ast.SendSet node, | 5805 ast.SendSet node, FunctionElement getter, ast.Node rhs, _) { |
6259 FunctionElement getter, | |
6260 ast.Node rhs, | |
6261 _) { | |
6262 handleSuperSendSet(node); | 5806 handleSuperSendSet(node); |
6263 } | 5807 } |
6264 | 5808 |
6265 @override | 5809 @override |
6266 void visitSuperIndexSet( | 5810 void visitSuperIndexSet(ast.SendSet node, FunctionElement function, |
6267 ast.SendSet node, | 5811 ast.Node index, ast.Node rhs, _) { |
6268 FunctionElement function, | |
6269 ast.Node index, | |
6270 ast.Node rhs, | |
6271 _) { | |
6272 handleSuperSendSet(node); | 5812 handleSuperSendSet(node); |
6273 } | 5813 } |
6274 | 5814 |
6275 @override | 5815 @override |
6276 void visitSuperMethodSet( | 5816 void visitSuperMethodSet( |
6277 ast.Send node, | 5817 ast.Send node, MethodElement method, ast.Node rhs, _) { |
6278 MethodElement method, | |
6279 ast.Node rhs, | |
6280 _) { | |
6281 handleSuperSendSet(node); | 5818 handleSuperSendSet(node); |
6282 } | 5819 } |
6283 | 5820 |
6284 @override | 5821 @override |
6285 void visitSuperSetterSet( | 5822 void visitSuperSetterSet( |
6286 ast.SendSet node, | 5823 ast.SendSet node, FunctionElement setter, ast.Node rhs, _) { |
6287 FunctionElement setter, | |
6288 ast.Node rhs, | |
6289 _) { | |
6290 handleSuperSendSet(node); | 5824 handleSuperSendSet(node); |
6291 } | 5825 } |
6292 | 5826 |
6293 @override | 5827 @override |
6294 void visitUnresolvedSuperIndexSet( | 5828 void visitUnresolvedSuperIndexSet( |
6295 ast.Send node, | 5829 ast.Send node, Element element, ast.Node index, ast.Node rhs, _) { |
6296 Element element, | |
6297 ast.Node index, | |
6298 ast.Node rhs, | |
6299 _) { | |
6300 handleSuperSendSet(node); | 5830 handleSuperSendSet(node); |
6301 } | 5831 } |
6302 | 5832 |
6303 @override | 5833 @override |
6304 void visitSuperIndexPrefix( | 5834 void visitSuperIndexPrefix( |
6305 ast.Send node, | 5835 ast.Send node, |
6306 MethodElement indexFunction, | 5836 MethodElement indexFunction, |
6307 MethodElement indexSetFunction, | 5837 MethodElement indexSetFunction, |
6308 ast.Node index, | 5838 ast.Node index, |
6309 IncDecOperator operator, | 5839 IncDecOperator operator, |
6310 _) { | 5840 _) { |
6311 handleSuperSendSet(node); | 5841 handleSuperSendSet(node); |
6312 } | 5842 } |
6313 | 5843 |
6314 @override | 5844 @override |
6315 void visitSuperIndexPostfix( | 5845 void visitSuperIndexPostfix( |
6316 ast.Send node, | 5846 ast.Send node, |
6317 MethodElement indexFunction, | 5847 MethodElement indexFunction, |
6318 MethodElement indexSetFunction, | 5848 MethodElement indexSetFunction, |
6319 ast.Node index, | 5849 ast.Node index, |
6320 IncDecOperator operator, | 5850 IncDecOperator operator, |
6321 _) { | 5851 _) { |
6322 handleSuperSendSet(node); | 5852 handleSuperSendSet(node); |
6323 } | 5853 } |
6324 | 5854 |
6325 @override | 5855 @override |
6326 void visitUnresolvedSuperGetterIndexPrefix( | 5856 void visitUnresolvedSuperGetterIndexPrefix(ast.Send node, Element element, |
6327 ast.Send node, | 5857 MethodElement setter, ast.Node index, IncDecOperator operator, _) { |
6328 Element element, | |
6329 MethodElement setter, | |
6330 ast.Node index, | |
6331 IncDecOperator operator, | |
6332 _) { | |
6333 handleSuperSendSet(node); | 5858 handleSuperSendSet(node); |
6334 } | 5859 } |
6335 | 5860 |
6336 @override | 5861 @override |
6337 void visitUnresolvedSuperGetterIndexPostfix( | 5862 void visitUnresolvedSuperGetterIndexPostfix(ast.Send node, Element element, |
6338 ast.Send node, | 5863 MethodElement setter, ast.Node index, IncDecOperator operator, _) { |
6339 Element element, | |
6340 MethodElement setter, | |
6341 ast.Node index, | |
6342 IncDecOperator operator, | |
6343 _) { | |
6344 handleSuperSendSet(node); | 5864 handleSuperSendSet(node); |
6345 } | 5865 } |
6346 | 5866 |
6347 @override | 5867 @override |
6348 void visitUnresolvedSuperSetterIndexPrefix( | 5868 void visitUnresolvedSuperSetterIndexPrefix( |
6349 ast.Send node, | 5869 ast.Send node, |
6350 MethodElement indexFunction, | 5870 MethodElement indexFunction, |
6351 Element element, | 5871 Element element, |
6352 ast.Node index, | 5872 ast.Node index, |
6353 IncDecOperator operator, | 5873 IncDecOperator operator, |
6354 _) { | 5874 _) { |
6355 handleSuperSendSet(node); | 5875 handleSuperSendSet(node); |
6356 } | 5876 } |
6357 | 5877 |
6358 @override | 5878 @override |
6359 void visitUnresolvedSuperSetterIndexPostfix( | 5879 void visitUnresolvedSuperSetterIndexPostfix( |
6360 ast.Send node, | 5880 ast.Send node, |
6361 MethodElement indexFunction, | 5881 MethodElement indexFunction, |
6362 Element element, | 5882 Element element, |
6363 ast.Node index, | 5883 ast.Node index, |
6364 IncDecOperator operator, | 5884 IncDecOperator operator, |
6365 _) { | 5885 _) { |
6366 handleSuperSendSet(node); | 5886 handleSuperSendSet(node); |
6367 } | 5887 } |
6368 | 5888 |
6369 @override | 5889 @override |
6370 void visitUnresolvedSuperIndexPrefix( | 5890 void visitUnresolvedSuperIndexPrefix(ast.Send node, Element element, |
6371 ast.Send node, | 5891 ast.Node index, IncDecOperator operator, _) { |
6372 Element element, | |
6373 ast.Node index, | |
6374 IncDecOperator operator, | |
6375 _) { | |
6376 handleSuperSendSet(node); | 5892 handleSuperSendSet(node); |
6377 } | 5893 } |
6378 | 5894 |
6379 @override | 5895 @override |
6380 void visitUnresolvedSuperIndexPostfix( | 5896 void visitUnresolvedSuperIndexPostfix(ast.Send node, Element element, |
6381 ast.Send node, | 5897 ast.Node index, IncDecOperator operator, _) { |
6382 Element element, | |
6383 ast.Node index, | |
6384 IncDecOperator operator, | |
6385 _) { | |
6386 handleSuperSendSet(node); | 5898 handleSuperSendSet(node); |
6387 } | 5899 } |
6388 | 5900 |
6389 @override | 5901 @override |
6390 void visitSuperCompoundIndexSet( | 5902 void visitSuperCompoundIndexSet( |
6391 ast.SendSet node, | 5903 ast.SendSet node, |
6392 MethodElement getter, | 5904 MethodElement getter, |
6393 MethodElement setter, | 5905 MethodElement setter, |
6394 ast.Node index, | 5906 ast.Node index, |
6395 AssignmentOperator operator, | 5907 AssignmentOperator operator, |
(...skipping 20 matching lines...) Expand all Loading... |
6416 MethodElement getter, | 5928 MethodElement getter, |
6417 Element element, | 5929 Element element, |
6418 ast.Node index, | 5930 ast.Node index, |
6419 AssignmentOperator operator, | 5931 AssignmentOperator operator, |
6420 ast.Node rhs, | 5932 ast.Node rhs, |
6421 _) { | 5933 _) { |
6422 handleSuperSendSet(node); | 5934 handleSuperSendSet(node); |
6423 } | 5935 } |
6424 | 5936 |
6425 @override | 5937 @override |
6426 void visitUnresolvedSuperCompoundIndexSet( | 5938 void visitUnresolvedSuperCompoundIndexSet(ast.Send node, Element element, |
6427 ast.Send node, | 5939 ast.Node index, AssignmentOperator operator, ast.Node rhs, _) { |
6428 Element element, | |
6429 ast.Node index, | |
6430 AssignmentOperator operator, | |
6431 ast.Node rhs, | |
6432 _) { | |
6433 handleSuperSendSet(node); | 5940 handleSuperSendSet(node); |
6434 } | 5941 } |
6435 | 5942 |
6436 @override | 5943 @override |
6437 void visitSuperFieldCompound( | 5944 void visitSuperFieldCompound(ast.Send node, FieldElement field, |
6438 ast.Send node, | 5945 AssignmentOperator operator, ast.Node rhs, _) { |
6439 FieldElement field, | |
6440 AssignmentOperator operator, | |
6441 ast.Node rhs, | |
6442 _) { | |
6443 handleSuperSendSet(node); | 5946 handleSuperSendSet(node); |
6444 } | 5947 } |
6445 | 5948 |
6446 @override | 5949 @override |
6447 void visitFinalSuperFieldCompound( | 5950 void visitFinalSuperFieldCompound(ast.Send node, FieldElement field, |
6448 ast.Send node, | 5951 AssignmentOperator operator, ast.Node rhs, _) { |
6449 FieldElement field, | |
6450 AssignmentOperator operator, | |
6451 ast.Node rhs, | |
6452 _) { | |
6453 handleSuperSendSet(node); | 5952 handleSuperSendSet(node); |
6454 } | 5953 } |
6455 | 5954 |
6456 @override | 5955 @override |
6457 void visitFinalSuperFieldPrefix( | 5956 void visitFinalSuperFieldPrefix( |
6458 ast.Send node, | 5957 ast.Send node, FieldElement field, IncDecOperator operator, _) { |
6459 FieldElement field, | |
6460 IncDecOperator operator, | |
6461 _) { | |
6462 handleSuperSendSet(node); | 5958 handleSuperSendSet(node); |
6463 } | 5959 } |
6464 | 5960 |
6465 @override | 5961 @override |
6466 void visitUnresolvedSuperPrefix( | 5962 void visitUnresolvedSuperPrefix( |
6467 ast.Send node, | 5963 ast.Send node, Element element, IncDecOperator operator, _) { |
6468 Element element, | |
6469 IncDecOperator operator, | |
6470 _) { | |
6471 handleSuperSendSet(node); | 5964 handleSuperSendSet(node); |
6472 } | 5965 } |
6473 | 5966 |
6474 @override | 5967 @override |
6475 void visitUnresolvedSuperPostfix( | 5968 void visitUnresolvedSuperPostfix( |
6476 ast.Send node, | 5969 ast.Send node, Element element, IncDecOperator operator, _) { |
6477 Element element, | |
6478 IncDecOperator operator, | |
6479 _) { | |
6480 handleSuperSendSet(node); | 5970 handleSuperSendSet(node); |
6481 } | 5971 } |
6482 | 5972 |
6483 @override | 5973 @override |
6484 void visitUnresolvedSuperCompound( | 5974 void visitUnresolvedSuperCompound(ast.Send node, Element element, |
6485 ast.Send node, | 5975 AssignmentOperator operator, ast.Node rhs, _) { |
6486 Element element, | |
6487 AssignmentOperator operator, | |
6488 ast.Node rhs, | |
6489 _) { | |
6490 handleSuperSendSet(node); | 5976 handleSuperSendSet(node); |
6491 } | 5977 } |
6492 | 5978 |
6493 @override | 5979 @override |
6494 void visitFinalSuperFieldPostfix( | 5980 void visitFinalSuperFieldPostfix( |
6495 ast.Send node, | 5981 ast.Send node, FieldElement field, IncDecOperator operator, _) { |
6496 FieldElement field, | |
6497 IncDecOperator operator, | |
6498 _) { | |
6499 handleSuperSendSet(node); | 5982 handleSuperSendSet(node); |
6500 } | 5983 } |
6501 | 5984 |
6502 @override | 5985 @override |
6503 void visitSuperFieldFieldCompound( | 5986 void visitSuperFieldFieldCompound(ast.Send node, FieldElement readField, |
6504 ast.Send node, | 5987 FieldElement writtenField, AssignmentOperator operator, ast.Node rhs, _) { |
6505 FieldElement readField, | |
6506 FieldElement writtenField, | |
6507 AssignmentOperator operator, | |
6508 ast.Node rhs, | |
6509 _) { | |
6510 handleSuperSendSet(node); | 5988 handleSuperSendSet(node); |
6511 } | 5989 } |
6512 | 5990 |
6513 @override | 5991 @override |
6514 void visitSuperGetterSetterCompound( | 5992 void visitSuperGetterSetterCompound(ast.Send node, FunctionElement getter, |
6515 ast.Send node, | 5993 FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
6516 FunctionElement getter, | |
6517 FunctionElement setter, | |
6518 AssignmentOperator operator, | |
6519 ast.Node rhs, | |
6520 _) { | |
6521 handleSuperSendSet(node); | 5994 handleSuperSendSet(node); |
6522 } | 5995 } |
6523 | 5996 |
6524 @override | 5997 @override |
6525 void visitSuperMethodSetterCompound( | 5998 void visitSuperMethodSetterCompound(ast.Send node, FunctionElement method, |
6526 ast.Send node, | 5999 FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
6527 FunctionElement method, | |
6528 FunctionElement setter, | |
6529 AssignmentOperator operator, | |
6530 ast.Node rhs, | |
6531 _) { | |
6532 handleSuperSendSet(node); | 6000 handleSuperSendSet(node); |
6533 } | 6001 } |
6534 | 6002 |
6535 @override | 6003 @override |
6536 void visitSuperMethodCompound( | 6004 void visitSuperMethodCompound(ast.Send node, FunctionElement method, |
6537 ast.Send node, | 6005 AssignmentOperator operator, ast.Node rhs, _) { |
6538 FunctionElement method, | |
6539 AssignmentOperator operator, | |
6540 ast.Node rhs, | |
6541 _) { | |
6542 handleSuperSendSet(node); | 6006 handleSuperSendSet(node); |
6543 } | 6007 } |
6544 | 6008 |
6545 @override | 6009 @override |
6546 void visitUnresolvedSuperGetterCompound( | 6010 void visitUnresolvedSuperGetterCompound(ast.Send node, Element element, |
6547 ast.Send node, | 6011 MethodElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
6548 Element element, | |
6549 MethodElement setter, | |
6550 AssignmentOperator operator, | |
6551 ast.Node rhs, | |
6552 _) { | |
6553 handleSuperSendSet(node); | 6012 handleSuperSendSet(node); |
6554 } | 6013 } |
6555 | 6014 |
6556 @override | 6015 @override |
6557 void visitUnresolvedSuperSetterCompound( | 6016 void visitUnresolvedSuperSetterCompound(ast.Send node, MethodElement getter, |
6558 ast.Send node, | 6017 Element element, AssignmentOperator operator, ast.Node rhs, _) { |
6559 MethodElement getter, | |
6560 Element element, | |
6561 AssignmentOperator operator, | |
6562 ast.Node rhs, | |
6563 _) { | |
6564 handleSuperSendSet(node); | 6018 handleSuperSendSet(node); |
6565 } | 6019 } |
6566 | 6020 |
6567 @override | 6021 @override |
6568 void visitSuperFieldSetterCompound( | 6022 void visitSuperFieldSetterCompound(ast.Send node, FieldElement field, |
6569 ast.Send node, | 6023 FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
6570 FieldElement field, | |
6571 FunctionElement setter, | |
6572 AssignmentOperator operator, | |
6573 ast.Node rhs, | |
6574 _) { | |
6575 handleSuperSendSet(node); | 6024 handleSuperSendSet(node); |
6576 } | 6025 } |
6577 | 6026 |
6578 @override | 6027 @override |
6579 void visitSuperGetterFieldCompound( | 6028 void visitSuperGetterFieldCompound(ast.Send node, FunctionElement getter, |
6580 ast.Send node, | 6029 FieldElement field, AssignmentOperator operator, ast.Node rhs, _) { |
6581 FunctionElement getter, | |
6582 FieldElement field, | |
6583 AssignmentOperator operator, | |
6584 ast.Node rhs, | |
6585 _) { | |
6586 handleSuperSendSet(node); | 6030 handleSuperSendSet(node); |
6587 } | 6031 } |
6588 | 6032 |
6589 @override | 6033 @override |
6590 void visitIndexSet( | 6034 void visitIndexSet( |
6591 ast.SendSet node, | 6035 ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, _) { |
6592 ast.Node receiver, | |
6593 ast.Node index, | |
6594 ast.Node rhs, | |
6595 _) { | |
6596 generateDynamicSend(node); | 6036 generateDynamicSend(node); |
6597 } | 6037 } |
6598 | 6038 |
6599 @override | 6039 @override |
6600 void visitCompoundIndexSet( | 6040 void visitCompoundIndexSet(ast.SendSet node, ast.Node receiver, |
6601 ast.SendSet node, | 6041 ast.Node index, AssignmentOperator operator, ast.Node rhs, _) { |
6602 ast.Node receiver, | |
6603 ast.Node index, | |
6604 AssignmentOperator operator, | |
6605 ast.Node rhs, | |
6606 _) { | |
6607 generateIsDeferredLoadedCheckOfSend(node); | 6042 generateIsDeferredLoadedCheckOfSend(node); |
6608 handleIndexSendSet(node); | 6043 handleIndexSendSet(node); |
6609 } | 6044 } |
6610 | 6045 |
6611 @override | 6046 @override |
6612 void visitIndexPrefix( | 6047 void visitIndexPrefix(ast.Send node, ast.Node receiver, ast.Node index, |
6613 ast.Send node, | 6048 IncDecOperator operator, _) { |
6614 ast.Node receiver, | |
6615 ast.Node index, | |
6616 IncDecOperator operator, | |
6617 _) { | |
6618 generateIsDeferredLoadedCheckOfSend(node); | 6049 generateIsDeferredLoadedCheckOfSend(node); |
6619 handleIndexSendSet(node); | 6050 handleIndexSendSet(node); |
6620 } | 6051 } |
6621 | 6052 |
6622 @override | 6053 @override |
6623 void visitIndexPostfix( | 6054 void visitIndexPostfix(ast.Send node, ast.Node receiver, ast.Node index, |
6624 ast.Send node, | 6055 IncDecOperator operator, _) { |
6625 ast.Node receiver, | |
6626 ast.Node index, | |
6627 IncDecOperator operator, | |
6628 _) { | |
6629 generateIsDeferredLoadedCheckOfSend(node); | 6056 generateIsDeferredLoadedCheckOfSend(node); |
6630 handleIndexSendSet(node); | 6057 handleIndexSendSet(node); |
6631 } | 6058 } |
6632 | 6059 |
6633 void handleIndexSendSet(ast.SendSet node) { | 6060 void handleIndexSendSet(ast.SendSet node) { |
6634 ast.Operator op = node.assignmentOperator; | 6061 ast.Operator op = node.assignmentOperator; |
6635 if ("=" == op.source) { | 6062 if ("=" == op.source) { |
6636 internalError(node, "Unexpected index set."); | 6063 internalError(node, "Unexpected index set."); |
6637 } else { | 6064 } else { |
6638 visit(node.receiver); | 6065 visit(node.receiver); |
6639 HInstruction receiver = pop(); | 6066 HInstruction receiver = pop(); |
6640 Link<ast.Node> arguments = node.arguments; | 6067 Link<ast.Node> arguments = node.arguments; |
6641 HInstruction index; | 6068 HInstruction index; |
6642 if (node.isIndex) { | 6069 if (node.isIndex) { |
6643 visit(arguments.head); | 6070 visit(arguments.head); |
6644 arguments = arguments.tail; | 6071 arguments = arguments.tail; |
6645 index = pop(); | 6072 index = pop(); |
6646 } | 6073 } |
6647 | 6074 |
6648 pushInvokeDynamic( | 6075 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), |
6649 node, | 6076 elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]); |
6650 elements.getGetterSelectorInComplexSendSet(node), | |
6651 elements.getGetterTypeMaskInComplexSendSet(node), | |
6652 [receiver, index]); | |
6653 HInstruction getterInstruction = pop(); | 6077 HInstruction getterInstruction = pop(); |
6654 if (node.isIfNullAssignment) { | 6078 if (node.isIfNullAssignment) { |
6655 // Compile x[i] ??= e as: | 6079 // Compile x[i] ??= e as: |
6656 // t1 = x[i] | 6080 // t1 = x[i] |
6657 // if (t1 == null) | 6081 // if (t1 == null) |
6658 // t1 = x[i] = e; | 6082 // t1 = x[i] = e; |
6659 // result = t1 | 6083 // result = t1 |
6660 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6084 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
6661 brancher.handleIfNull(() => stack.add(getterInstruction), | 6085 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
6662 () { | 6086 visit(arguments.head); |
6663 visit(arguments.head); | 6087 HInstruction value = pop(); |
6664 HInstruction value = pop(); | 6088 pushInvokeDynamic(node, elements.getSelector(node), |
6665 pushInvokeDynamic( | 6089 elements.getTypeMask(node), [receiver, index, value]); |
6666 node, | 6090 pop(); |
6667 elements.getSelector(node), | 6091 stack.add(value); |
6668 elements.getTypeMask(node), | 6092 }); |
6669 [receiver, index, value]); | |
6670 pop(); | |
6671 stack.add(value); | |
6672 }); | |
6673 } else { | 6093 } else { |
6674 handleComplexOperatorSend(node, getterInstruction, arguments); | 6094 handleComplexOperatorSend(node, getterInstruction, arguments); |
6675 HInstruction value = pop(); | 6095 HInstruction value = pop(); |
6676 pushInvokeDynamic( | 6096 pushInvokeDynamic(node, elements.getSelector(node), |
6677 node, | 6097 elements.getTypeMask(node), [receiver, index, value]); |
6678 elements.getSelector(node), | |
6679 elements.getTypeMask(node), | |
6680 [receiver, index, value]); | |
6681 pop(); | 6098 pop(); |
6682 if (node.isPostfix) { | 6099 if (node.isPostfix) { |
6683 stack.add(getterInstruction); | 6100 stack.add(getterInstruction); |
6684 } else { | 6101 } else { |
6685 stack.add(value); | 6102 stack.add(value); |
6686 } | 6103 } |
6687 } | 6104 } |
6688 } | 6105 } |
6689 } | 6106 } |
6690 | 6107 |
6691 @override | 6108 @override |
6692 void visitThisPropertySet( | 6109 void visitThisPropertySet(ast.SendSet node, Name name, ast.Node rhs, _) { |
6693 ast.SendSet node, | |
6694 Name name, | |
6695 ast.Node rhs, | |
6696 _) { | |
6697 generateInstanceSetterWithCompiledReceiver( | 6110 generateInstanceSetterWithCompiledReceiver( |
6698 node, | 6111 node, localsHandler.readThis(), visitAndPop(rhs)); |
6699 localsHandler.readThis(), | |
6700 visitAndPop(rhs)); | |
6701 } | 6112 } |
6702 | 6113 |
6703 @override | 6114 @override |
6704 void visitDynamicPropertySet( | 6115 void visitDynamicPropertySet( |
6705 ast.SendSet node, | 6116 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { |
6706 ast.Node receiver, | |
6707 Name name, | |
6708 ast.Node rhs, | |
6709 _) { | |
6710 generateInstanceSetterWithCompiledReceiver( | 6117 generateInstanceSetterWithCompiledReceiver( |
6711 node, | 6118 node, generateInstanceSendReceiver(node), visitAndPop(rhs)); |
6712 generateInstanceSendReceiver(node), | |
6713 visitAndPop(rhs)); | |
6714 } | 6119 } |
6715 | 6120 |
6716 @override | 6121 @override |
6717 void visitIfNotNullDynamicPropertySet( | 6122 void visitIfNotNullDynamicPropertySet( |
6718 ast.SendSet node, | 6123 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { |
6719 ast.Node receiver, | |
6720 Name name, | |
6721 ast.Node rhs, | |
6722 _) { | |
6723 // compile e?.x = e2 to: | 6124 // compile e?.x = e2 to: |
6724 // | 6125 // |
6725 // t1 = e | 6126 // t1 = e |
6726 // if (t1 == null) | 6127 // if (t1 == null) |
6727 // result = t1 // same as result = null | 6128 // result = t1 // same as result = null |
6728 // else | 6129 // else |
6729 // result = e.x = e2 | 6130 // result = e.x = e2 |
6730 HInstruction receiverInstruction; | 6131 HInstruction receiverInstruction; |
6731 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6132 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
6732 brancher.handleConditional( | 6133 brancher.handleConditional( |
6733 () { | 6134 () { |
6734 receiverInstruction = generateInstanceSendReceiver(node); | 6135 receiverInstruction = generateInstanceSendReceiver(node); |
6735 pushCheckNull(receiverInstruction); | 6136 pushCheckNull(receiverInstruction); |
6736 }, | 6137 }, |
6737 () => stack.add(receiverInstruction), | 6138 () => stack.add(receiverInstruction), |
6738 () { | 6139 () { |
6739 generateInstanceSetterWithCompiledReceiver( | 6140 generateInstanceSetterWithCompiledReceiver( |
6740 node, | 6141 node, receiverInstruction, visitAndPop(rhs)); |
6741 receiverInstruction, | |
6742 visitAndPop(rhs)); | |
6743 }); | 6142 }); |
6744 } | 6143 } |
6745 | 6144 |
6746 @override | 6145 @override |
6747 void visitParameterSet( | 6146 void visitParameterSet( |
6748 ast.SendSet node, | 6147 ast.SendSet node, ParameterElement parameter, ast.Node rhs, _) { |
6749 ParameterElement parameter, | |
6750 ast.Node rhs, | |
6751 _) { | |
6752 generateNonInstanceSetter(node, parameter, visitAndPop(rhs)); | 6148 generateNonInstanceSetter(node, parameter, visitAndPop(rhs)); |
6753 } | 6149 } |
6754 | 6150 |
6755 @override | 6151 @override |
6756 void visitFinalParameterSet( | 6152 void visitFinalParameterSet( |
6757 ast.SendSet node, | 6153 ast.SendSet node, ParameterElement parameter, ast.Node rhs, _) { |
6758 ParameterElement parameter, | |
6759 ast.Node rhs, | |
6760 _) { | |
6761 generateNoSuchSetter(node, parameter, visitAndPop(rhs)); | 6154 generateNoSuchSetter(node, parameter, visitAndPop(rhs)); |
6762 } | 6155 } |
6763 | 6156 |
6764 @override | 6157 @override |
6765 void visitLocalVariableSet( | 6158 void visitLocalVariableSet( |
6766 ast.SendSet node, | 6159 ast.SendSet node, LocalVariableElement variable, ast.Node rhs, _) { |
6767 LocalVariableElement variable, | |
6768 ast.Node rhs, | |
6769 _) { | |
6770 generateNonInstanceSetter(node, variable, visitAndPop(rhs)); | 6160 generateNonInstanceSetter(node, variable, visitAndPop(rhs)); |
6771 } | 6161 } |
6772 | 6162 |
6773 @override | 6163 @override |
6774 void visitFinalLocalVariableSet( | 6164 void visitFinalLocalVariableSet( |
6775 ast.SendSet node, | 6165 ast.SendSet node, LocalVariableElement variable, ast.Node rhs, _) { |
6776 LocalVariableElement variable, | |
6777 ast.Node rhs, | |
6778 _) { | |
6779 generateNoSuchSetter(node, variable, visitAndPop(rhs)); | 6166 generateNoSuchSetter(node, variable, visitAndPop(rhs)); |
6780 } | 6167 } |
6781 | 6168 |
6782 @override | 6169 @override |
6783 void visitLocalFunctionSet( | 6170 void visitLocalFunctionSet( |
6784 ast.SendSet node, | 6171 ast.SendSet node, LocalFunctionElement function, ast.Node rhs, _) { |
6785 LocalFunctionElement function, | |
6786 ast.Node rhs, | |
6787 _) { | |
6788 generateNoSuchSetter(node, function, visitAndPop(rhs)); | 6172 generateNoSuchSetter(node, function, visitAndPop(rhs)); |
6789 } | 6173 } |
6790 | 6174 |
6791 @override | 6175 @override |
6792 void visitTopLevelFieldSet( | 6176 void visitTopLevelFieldSet( |
6793 ast.SendSet node, | 6177 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
6794 FieldElement field, | |
6795 ast.Node rhs, | |
6796 _) { | |
6797 generateIsDeferredLoadedCheckOfSend(node); | 6178 generateIsDeferredLoadedCheckOfSend(node); |
6798 generateNonInstanceSetter(node, field, visitAndPop(rhs)); | 6179 generateNonInstanceSetter(node, field, visitAndPop(rhs)); |
6799 } | 6180 } |
6800 | 6181 |
6801 @override | 6182 @override |
6802 void visitFinalTopLevelFieldSet( | 6183 void visitFinalTopLevelFieldSet( |
6803 ast.SendSet node, | 6184 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
6804 FieldElement field, | |
6805 ast.Node rhs, | |
6806 _) { | |
6807 generateIsDeferredLoadedCheckOfSend(node); | 6185 generateIsDeferredLoadedCheckOfSend(node); |
6808 generateNoSuchSetter(node, field, visitAndPop(rhs)); | 6186 generateNoSuchSetter(node, field, visitAndPop(rhs)); |
6809 } | 6187 } |
6810 | 6188 |
6811 @override | 6189 @override |
6812 void visitTopLevelGetterSet( | 6190 void visitTopLevelGetterSet( |
6813 ast.SendSet node, | 6191 ast.SendSet node, GetterElement getter, ast.Node rhs, _) { |
6814 GetterElement getter, | |
6815 ast.Node rhs, | |
6816 _) { | |
6817 generateIsDeferredLoadedCheckOfSend(node); | 6192 generateIsDeferredLoadedCheckOfSend(node); |
6818 generateNoSuchSetter(node, getter, visitAndPop(rhs)); | 6193 generateNoSuchSetter(node, getter, visitAndPop(rhs)); |
6819 } | 6194 } |
6820 | 6195 |
6821 @override | 6196 @override |
6822 void visitTopLevelSetterSet( | 6197 void visitTopLevelSetterSet( |
6823 ast.SendSet node, | 6198 ast.SendSet node, SetterElement setter, ast.Node rhs, _) { |
6824 SetterElement setter, | |
6825 ast.Node rhs, | |
6826 _) { | |
6827 generateIsDeferredLoadedCheckOfSend(node); | 6199 generateIsDeferredLoadedCheckOfSend(node); |
6828 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); | 6200 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); |
6829 } | 6201 } |
6830 | 6202 |
6831 @override | 6203 @override |
6832 void visitTopLevelFunctionSet( | 6204 void visitTopLevelFunctionSet( |
6833 ast.SendSet node, | 6205 ast.SendSet node, MethodElement function, ast.Node rhs, _) { |
6834 MethodElement function, | |
6835 ast.Node rhs, | |
6836 _) { | |
6837 generateIsDeferredLoadedCheckOfSend(node); | 6206 generateIsDeferredLoadedCheckOfSend(node); |
6838 generateNoSuchSetter(node, function, visitAndPop(rhs)); | 6207 generateNoSuchSetter(node, function, visitAndPop(rhs)); |
6839 } | 6208 } |
6840 | 6209 |
6841 @override | 6210 @override |
6842 void visitStaticFieldSet( | 6211 void visitStaticFieldSet( |
6843 ast.SendSet node, | 6212 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
6844 FieldElement field, | |
6845 ast.Node rhs, | |
6846 _) { | |
6847 generateIsDeferredLoadedCheckOfSend(node); | 6213 generateIsDeferredLoadedCheckOfSend(node); |
6848 generateNonInstanceSetter(node, field, visitAndPop(rhs)); | 6214 generateNonInstanceSetter(node, field, visitAndPop(rhs)); |
6849 } | 6215 } |
6850 | 6216 |
6851 @override | 6217 @override |
6852 void visitFinalStaticFieldSet( | 6218 void visitFinalStaticFieldSet( |
6853 ast.SendSet node, | 6219 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
6854 FieldElement field, | |
6855 ast.Node rhs, | |
6856 _) { | |
6857 generateIsDeferredLoadedCheckOfSend(node); | 6220 generateIsDeferredLoadedCheckOfSend(node); |
6858 generateNoSuchSetter(node, field, visitAndPop(rhs)); | 6221 generateNoSuchSetter(node, field, visitAndPop(rhs)); |
6859 } | 6222 } |
6860 | 6223 |
6861 @override | 6224 @override |
6862 void visitStaticGetterSet( | 6225 void visitStaticGetterSet( |
6863 ast.SendSet node, | 6226 ast.SendSet node, GetterElement getter, ast.Node rhs, _) { |
6864 GetterElement getter, | |
6865 ast.Node rhs, | |
6866 _) { | |
6867 generateIsDeferredLoadedCheckOfSend(node); | 6227 generateIsDeferredLoadedCheckOfSend(node); |
6868 generateNoSuchSetter(node, getter, visitAndPop(rhs)); | 6228 generateNoSuchSetter(node, getter, visitAndPop(rhs)); |
6869 } | 6229 } |
6870 | 6230 |
6871 @override | 6231 @override |
6872 void visitStaticSetterSet( | 6232 void visitStaticSetterSet( |
6873 ast.SendSet node, | 6233 ast.SendSet node, SetterElement setter, ast.Node rhs, _) { |
6874 SetterElement setter, | |
6875 ast.Node rhs, | |
6876 _) { | |
6877 generateIsDeferredLoadedCheckOfSend(node); | 6234 generateIsDeferredLoadedCheckOfSend(node); |
6878 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); | 6235 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); |
6879 } | 6236 } |
6880 | 6237 |
6881 @override | 6238 @override |
6882 void visitStaticFunctionSet( | 6239 void visitStaticFunctionSet( |
6883 ast.SendSet node, | 6240 ast.SendSet node, MethodElement function, ast.Node rhs, _) { |
6884 MethodElement function, | |
6885 ast.Node rhs, | |
6886 _) { | |
6887 generateIsDeferredLoadedCheckOfSend(node); | 6241 generateIsDeferredLoadedCheckOfSend(node); |
6888 generateNoSuchSetter(node, function, visitAndPop(rhs)); | 6242 generateNoSuchSetter(node, function, visitAndPop(rhs)); |
6889 } | 6243 } |
6890 | 6244 |
6891 @override | 6245 @override |
6892 void visitUnresolvedSet( | 6246 void visitUnresolvedSet(ast.SendSet node, Element element, ast.Node rhs, _) { |
6893 ast.SendSet node, | |
6894 Element element, | |
6895 ast.Node rhs, | |
6896 _) { | |
6897 generateIsDeferredLoadedCheckOfSend(node); | 6247 generateIsDeferredLoadedCheckOfSend(node); |
6898 generateNonInstanceSetter(node, element, visitAndPop(rhs)); | 6248 generateNonInstanceSetter(node, element, visitAndPop(rhs)); |
6899 } | 6249 } |
6900 | 6250 |
6901 @override | 6251 @override |
6902 void visitClassTypeLiteralSet( | 6252 void visitClassTypeLiteralSet( |
6903 ast.SendSet node, | 6253 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) { |
6904 TypeConstantExpression constant, | |
6905 ast.Node rhs, | |
6906 _) { | |
6907 generateThrowNoSuchMethod(node, constant.type.name, | 6254 generateThrowNoSuchMethod(node, constant.type.name, |
6908 argumentNodes: node.arguments); | 6255 argumentNodes: node.arguments); |
6909 } | 6256 } |
6910 | 6257 |
6911 @override | 6258 @override |
6912 void visitTypedefTypeLiteralSet( | 6259 void visitTypedefTypeLiteralSet( |
6913 ast.SendSet node, | 6260 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) { |
6914 TypeConstantExpression constant, | |
6915 ast.Node rhs, | |
6916 _) { | |
6917 generateThrowNoSuchMethod(node, constant.type.name, | 6261 generateThrowNoSuchMethod(node, constant.type.name, |
6918 argumentNodes: node.arguments); | 6262 argumentNodes: node.arguments); |
6919 } | 6263 } |
6920 | 6264 |
6921 @override | 6265 @override |
6922 void visitDynamicTypeLiteralSet( | 6266 void visitDynamicTypeLiteralSet( |
6923 ast.SendSet node, | 6267 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) { |
6924 TypeConstantExpression constant, | |
6925 ast.Node rhs, | |
6926 _) { | |
6927 generateThrowNoSuchMethod(node, constant.type.name, | 6268 generateThrowNoSuchMethod(node, constant.type.name, |
6928 argumentNodes: node.arguments); | 6269 argumentNodes: node.arguments); |
6929 } | 6270 } |
6930 | 6271 |
6931 @override | 6272 @override |
6932 void visitTypeVariableTypeLiteralSet( | 6273 void visitTypeVariableTypeLiteralSet( |
6933 ast.SendSet node, | 6274 ast.SendSet node, TypeVariableElement element, ast.Node rhs, _) { |
6934 TypeVariableElement element, | |
6935 ast.Node rhs, | |
6936 _) { | |
6937 generateThrowNoSuchMethod(node, element.name, | 6275 generateThrowNoSuchMethod(node, element.name, |
6938 argumentNodes: node.arguments); | 6276 argumentNodes: node.arguments); |
6939 } | 6277 } |
6940 | 6278 |
6941 void handleCompoundSendSet(ast.SendSet node) { | 6279 void handleCompoundSendSet(ast.SendSet node) { |
6942 Element element = elements[node]; | 6280 Element element = elements[node]; |
6943 Element getter = elements[node.selector]; | 6281 Element getter = elements[node.selector]; |
6944 | 6282 |
6945 if (!Elements.isUnresolved(getter) && getter.impliesType) { | 6283 if (!Elements.isUnresolved(getter) && getter.impliesType) { |
6946 if (node.isIfNullAssignment) { | 6284 if (node.isIfNullAssignment) { |
6947 // C ??= x is compiled just as C. | 6285 // C ??= x is compiled just as C. |
6948 stack.add(addConstant(node.selector)); | 6286 stack.add(addConstant(node.selector)); |
6949 } else { | 6287 } else { |
6950 ast.Identifier selector = node.selector; | 6288 ast.Identifier selector = node.selector; |
6951 generateThrowNoSuchMethod(node, selector.source, | 6289 generateThrowNoSuchMethod(node, selector.source, |
6952 argumentNodes: node.arguments); | 6290 argumentNodes: node.arguments); |
6953 } | 6291 } |
6954 return; | 6292 return; |
6955 } | 6293 } |
6956 | 6294 |
6957 if (Elements.isInstanceSend(node, elements)) { | 6295 if (Elements.isInstanceSend(node, elements)) { |
6958 void generateAssignment(HInstruction receiver) { | 6296 void generateAssignment(HInstruction receiver) { |
6959 // desugars `e.x op= e2` to `e.x = e.x op e2` | 6297 // desugars `e.x op= e2` to `e.x = e.x op e2` |
6960 generateInstanceGetterWithCompiledReceiver( | 6298 generateInstanceGetterWithCompiledReceiver( |
6961 node, | 6299 node, |
6962 elements.getGetterSelectorInComplexSendSet(node), | 6300 elements.getGetterSelectorInComplexSendSet(node), |
6963 elements.getGetterTypeMaskInComplexSendSet(node), | 6301 elements.getGetterTypeMaskInComplexSendSet(node), |
6964 receiver); | 6302 receiver); |
6965 HInstruction getterInstruction = pop(); | 6303 HInstruction getterInstruction = pop(); |
6966 if (node.isIfNullAssignment) { | 6304 if (node.isIfNullAssignment) { |
6967 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6305 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
6968 brancher.handleIfNull(() => stack.add(getterInstruction), | 6306 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
6969 () { | 6307 visit(node.arguments.head); |
6970 visit(node.arguments.head); | 6308 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); |
6971 generateInstanceSetterWithCompiledReceiver( | 6309 }); |
6972 node, receiver, pop()); | |
6973 }); | |
6974 } else { | 6310 } else { |
6975 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 6311 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
6976 HInstruction value = pop(); | 6312 HInstruction value = pop(); |
6977 generateInstanceSetterWithCompiledReceiver(node, receiver, value); | 6313 generateInstanceSetterWithCompiledReceiver(node, receiver, value); |
6978 } | 6314 } |
6979 if (node.isPostfix) { | 6315 if (node.isPostfix) { |
6980 pop(); | 6316 pop(); |
6981 stack.add(getterInstruction); | 6317 stack.add(getterInstruction); |
6982 } | 6318 } |
6983 } | 6319 } |
6984 if (node.isConditional) { | 6320 if (node.isConditional) { |
6985 // generate `e?.x op= e2` as: | 6321 // generate `e?.x op= e2` as: |
6986 // t1 = e | 6322 // t1 = e |
6987 // t1 == null ? t1 : (t1.x = t1.x op e2); | 6323 // t1 == null ? t1 : (t1.x = t1.x op e2); |
6988 HInstruction receiver; | 6324 HInstruction receiver; |
6989 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6325 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
6990 brancher.handleConditional( | 6326 brancher.handleConditional(() { |
6991 () { | 6327 receiver = generateInstanceSendReceiver(node); |
6992 receiver = generateInstanceSendReceiver(node); | 6328 pushCheckNull(receiver); |
6993 pushCheckNull(receiver); | 6329 }, () => stack.add(receiver), () => generateAssignment(receiver)); |
6994 }, | |
6995 () => stack.add(receiver), | |
6996 () => generateAssignment(receiver)); | |
6997 } else { | 6330 } else { |
6998 generateAssignment(generateInstanceSendReceiver(node)); | 6331 generateAssignment(generateInstanceSendReceiver(node)); |
6999 } | 6332 } |
7000 return; | 6333 return; |
7001 } | 6334 } |
7002 | 6335 |
7003 if (getter.isMalformed) { | 6336 if (getter.isMalformed) { |
7004 generateStaticUnresolvedGet(node, getter); | 6337 generateStaticUnresolvedGet(node, getter); |
7005 } else if (getter.isField) { | 6338 } else if (getter.isField) { |
7006 generateStaticFieldGet(node, getter); | 6339 generateStaticFieldGet(node, getter); |
7007 } else if (getter.isGetter) { | 6340 } else if (getter.isGetter) { |
7008 generateStaticGetterGet(node, getter); | 6341 generateStaticGetterGet(node, getter); |
7009 } else if (getter.isFunction) { | 6342 } else if (getter.isFunction) { |
7010 generateStaticFunctionGet(node, getter); | 6343 generateStaticFunctionGet(node, getter); |
7011 } else if (getter.isLocal) { | 6344 } else if (getter.isLocal) { |
7012 handleLocalGet(node, getter); | 6345 handleLocalGet(node, getter); |
7013 } else { | 6346 } else { |
7014 internalError(node, "Unexpected getter: $getter"); | 6347 internalError(node, "Unexpected getter: $getter"); |
7015 } | 6348 } |
7016 HInstruction getterInstruction = pop(); | 6349 HInstruction getterInstruction = pop(); |
7017 if (node.isIfNullAssignment) { | 6350 if (node.isIfNullAssignment) { |
7018 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6351 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
7019 brancher.handleIfNull(() => stack.add(getterInstruction), | 6352 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
7020 () { | 6353 visit(node.arguments.head); |
7021 visit(node.arguments.head); | 6354 generateNonInstanceSetter(node, element, pop()); |
7022 generateNonInstanceSetter(node, element, pop()); | 6355 }); |
7023 }); | |
7024 } else { | 6356 } else { |
7025 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 6357 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
7026 HInstruction value = pop(); | 6358 HInstruction value = pop(); |
7027 generateNonInstanceSetter(node, element, value); | 6359 generateNonInstanceSetter(node, element, value); |
7028 } | 6360 } |
7029 if (node.isPostfix) { | 6361 if (node.isPostfix) { |
7030 pop(); | 6362 pop(); |
7031 stack.add(getterInstruction); | 6363 stack.add(getterInstruction); |
7032 } | 6364 } |
7033 } | 6365 } |
7034 | 6366 |
7035 @override | 6367 @override |
7036 void handleDynamicCompounds( | 6368 void handleDynamicCompounds( |
7037 ast.Send node, | 6369 ast.Send node, ast.Node receiver, Name name, CompoundRhs rhs, _) { |
7038 ast.Node receiver, | |
7039 Name name, | |
7040 CompoundRhs rhs, | |
7041 _) { | |
7042 handleCompoundSendSet(node); | 6370 handleCompoundSendSet(node); |
7043 } | 6371 } |
7044 | 6372 |
7045 @override | 6373 @override |
7046 void handleLocalCompounds( | 6374 void handleLocalCompounds( |
7047 ast.SendSet node, | 6375 ast.SendSet node, LocalElement local, CompoundRhs rhs, _, |
7048 LocalElement local, | |
7049 CompoundRhs rhs, | |
7050 _, | |
7051 {bool isSetterValid}) { | 6376 {bool isSetterValid}) { |
7052 handleCompoundSendSet(node); | 6377 handleCompoundSendSet(node); |
7053 } | 6378 } |
7054 | 6379 |
7055 @override | 6380 @override |
7056 void handleStaticCompounds( | 6381 void handleStaticCompounds( |
7057 ast.SendSet node, | 6382 ast.SendSet node, |
7058 Element getter, | 6383 Element getter, |
7059 CompoundGetter getterKind, | 6384 CompoundGetter getterKind, |
7060 Element setter, | 6385 Element setter, |
7061 CompoundSetter setterKind, | 6386 CompoundSetter setterKind, |
7062 CompoundRhs rhs, | 6387 CompoundRhs rhs, |
7063 _) { | 6388 _) { |
7064 handleCompoundSendSet(node); | 6389 handleCompoundSendSet(node); |
7065 } | 6390 } |
7066 | 6391 |
7067 @override | 6392 @override |
7068 handleDynamicSetIfNulls( | 6393 handleDynamicSetIfNulls( |
7069 ast.Send node, | 6394 ast.Send node, ast.Node receiver, Name name, ast.Node rhs, arg) { |
7070 ast.Node receiver, | |
7071 Name name, | |
7072 ast.Node rhs, | |
7073 arg) { | |
7074 handleCompoundSendSet(node); | 6395 handleCompoundSendSet(node); |
7075 } | 6396 } |
7076 | 6397 |
7077 @override | 6398 @override |
7078 handleLocalSetIfNulls( | 6399 handleLocalSetIfNulls(ast.SendSet node, LocalElement local, ast.Node rhs, arg, |
7079 ast.SendSet node, | |
7080 LocalElement local, | |
7081 ast.Node rhs, | |
7082 arg, | |
7083 {bool isSetterValid}) { | 6400 {bool isSetterValid}) { |
7084 handleCompoundSendSet(node); | 6401 handleCompoundSendSet(node); |
7085 } | 6402 } |
7086 | 6403 |
7087 @override | 6404 @override |
7088 handleStaticSetIfNulls( | 6405 handleStaticSetIfNulls( |
7089 ast.SendSet node, | 6406 ast.SendSet node, |
7090 Element getter, | 6407 Element getter, |
7091 CompoundGetter getterKind, | 6408 CompoundGetter getterKind, |
7092 Element setter, | 6409 Element setter, |
7093 CompoundSetter setterKind, | 6410 CompoundSetter setterKind, |
7094 ast.Node rhs, | 6411 ast.Node rhs, |
7095 arg) { | 6412 arg) { |
7096 handleCompoundSendSet(node); | 6413 handleCompoundSendSet(node); |
7097 } | 6414 } |
7098 | 6415 |
7099 @override | 6416 @override |
7100 handleSuperSetIfNulls( | 6417 handleSuperSetIfNulls( |
7101 ast.SendSet node, | 6418 ast.SendSet node, |
7102 Element getter, | 6419 Element getter, |
7103 CompoundGetter getterKind, | 6420 CompoundGetter getterKind, |
7104 Element setter, | 6421 Element setter, |
7105 CompoundSetter setterKind, | 6422 CompoundSetter setterKind, |
7106 ast.Node rhs, | 6423 ast.Node rhs, |
7107 arg) { | 6424 arg) { |
7108 handleSuperSendSet(node); | 6425 handleSuperSendSet(node); |
7109 } | 6426 } |
7110 | 6427 |
7111 @override | 6428 @override |
7112 handleSuperIndexSetIfNull( | 6429 handleSuperIndexSetIfNull(ast.SendSet node, Element indexFunction, |
7113 ast.SendSet node, | 6430 Element indexSetFunction, ast.Node index, ast.Node rhs, arg, |
7114 Element indexFunction, | 6431 {bool isGetterValid, bool isSetterValid}) { |
7115 Element indexSetFunction, | |
7116 ast.Node index, | |
7117 ast.Node rhs, | |
7118 arg, | |
7119 {bool isGetterValid, | |
7120 bool isSetterValid}) { | |
7121 handleCompoundSendSet(node); | 6432 handleCompoundSendSet(node); |
7122 } | 6433 } |
7123 | 6434 |
7124 @override | 6435 @override |
7125 visitIndexSetIfNull( | 6436 visitIndexSetIfNull( |
7126 ast.SendSet node, | 6437 ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, arg, |
7127 ast.Node receiver, | 6438 {bool isGetterValid, bool isSetterValid}) { |
7128 ast.Node index, | |
7129 ast.Node rhs, | |
7130 arg, | |
7131 {bool isGetterValid, | |
7132 bool isSetterValid}) { | |
7133 generateIsDeferredLoadedCheckOfSend(node); | 6439 generateIsDeferredLoadedCheckOfSend(node); |
7134 handleIndexSendSet(node); | 6440 handleIndexSendSet(node); |
7135 } | 6441 } |
7136 | 6442 |
7137 @override | 6443 @override |
7138 handleTypeLiteralConstantSetIfNulls( | 6444 handleTypeLiteralConstantSetIfNulls( |
7139 ast.SendSet node, | 6445 ast.SendSet node, ConstantExpression constant, ast.Node rhs, arg) { |
7140 ConstantExpression constant, | |
7141 ast.Node rhs, | |
7142 arg) { | |
7143 // The type variable is never `null`. | 6446 // The type variable is never `null`. |
7144 generateConstantTypeLiteral(node); | 6447 generateConstantTypeLiteral(node); |
7145 } | 6448 } |
7146 | 6449 |
7147 @override | 6450 @override |
7148 visitTypeVariableTypeLiteralSetIfNull( | 6451 visitTypeVariableTypeLiteralSetIfNull( |
7149 ast.Send node, | 6452 ast.Send node, TypeVariableElement element, ast.Node rhs, arg) { |
7150 TypeVariableElement element, | |
7151 ast.Node rhs, | |
7152 arg) { | |
7153 // The type variable is never `null`. | 6453 // The type variable is never `null`. |
7154 generateTypeVariableLiteral(node, element.type); | 6454 generateTypeVariableLiteral(node, element.type); |
7155 } | 6455 } |
7156 | 6456 |
7157 void visitLiteralInt(ast.LiteralInt node) { | 6457 void visitLiteralInt(ast.LiteralInt node) { |
7158 stack.add(graph.addConstantInt(node.value, compiler)); | 6458 stack.add(graph.addConstantInt(node.value, compiler)); |
7159 } | 6459 } |
7160 | 6460 |
7161 void visitLiteralDouble(ast.LiteralDouble node) { | 6461 void visitLiteralDouble(ast.LiteralDouble node) { |
7162 stack.add(graph.addConstantDouble(node.value, compiler)); | 6462 stack.add(graph.addConstantDouble(node.value, compiler)); |
(...skipping 24 matching lines...) Expand all Loading... |
7187 } | 6487 } |
7188 | 6488 |
7189 void visitLiteralNull(ast.LiteralNull node) { | 6489 void visitLiteralNull(ast.LiteralNull node) { |
7190 stack.add(graph.addConstantNull(compiler)); | 6490 stack.add(graph.addConstantNull(compiler)); |
7191 } | 6491 } |
7192 | 6492 |
7193 visitNodeList(ast.NodeList node) { | 6493 visitNodeList(ast.NodeList node) { |
7194 for (Link<ast.Node> link = node.nodes; !link.isEmpty; link = link.tail) { | 6494 for (Link<ast.Node> link = node.nodes; !link.isEmpty; link = link.tail) { |
7195 if (isAborted()) { | 6495 if (isAborted()) { |
7196 reporter.reportHintMessage( | 6496 reporter.reportHintMessage( |
7197 link.head, | 6497 link.head, MessageKind.GENERIC, {'text': 'dead code'}); |
7198 MessageKind.GENERIC, | |
7199 {'text': 'dead code'}); | |
7200 } else { | 6498 } else { |
7201 visit(link.head); | 6499 visit(link.head); |
7202 } | 6500 } |
7203 } | 6501 } |
7204 } | 6502 } |
7205 | 6503 |
7206 void visitParenthesizedExpression(ast.ParenthesizedExpression node) { | 6504 void visitParenthesizedExpression(ast.ParenthesizedExpression node) { |
7207 visit(node.expression); | 6505 visit(node.expression); |
7208 } | 6506 } |
7209 | 6507 |
7210 visitOperator(ast.Operator node) { | 6508 visitOperator(ast.Operator node) { |
7211 // Operators are intercepted in their surrounding Send nodes. | 6509 // Operators are intercepted in their surrounding Send nodes. |
7212 reporter.internalError(node, | 6510 reporter.internalError( |
7213 'SsaBuilder.visitOperator should not be called.'); | 6511 node, 'SsaBuilder.visitOperator should not be called.'); |
7214 } | 6512 } |
7215 | 6513 |
7216 visitCascade(ast.Cascade node) { | 6514 visitCascade(ast.Cascade node) { |
7217 visit(node.expression); | 6515 visit(node.expression); |
7218 // Remove the result and reveal the duplicated receiver on the stack. | 6516 // Remove the result and reveal the duplicated receiver on the stack. |
7219 pop(); | 6517 pop(); |
7220 } | 6518 } |
7221 | 6519 |
7222 visitCascadeReceiver(ast.CascadeReceiver node) { | 6520 visitCascadeReceiver(ast.CascadeReceiver node) { |
7223 visit(node.expression); | 6521 visit(node.expression); |
7224 dup(); | 6522 dup(); |
7225 } | 6523 } |
7226 | 6524 |
7227 void handleInTryStatement() { | 6525 void handleInTryStatement() { |
7228 if (!inTryStatement) return; | 6526 if (!inTryStatement) return; |
7229 HBasicBlock block = close(new HExitTry()); | 6527 HBasicBlock block = close(new HExitTry()); |
7230 HBasicBlock newBlock = graph.addNewBlock(); | 6528 HBasicBlock newBlock = graph.addNewBlock(); |
7231 block.addSuccessor(newBlock); | 6529 block.addSuccessor(newBlock); |
7232 open(newBlock); | 6530 open(newBlock); |
7233 } | 6531 } |
7234 | 6532 |
7235 visitRethrow(ast.Rethrow node) { | 6533 visitRethrow(ast.Rethrow node) { |
7236 HInstruction exception = rethrowableException; | 6534 HInstruction exception = rethrowableException; |
7237 if (exception == null) { | 6535 if (exception == null) { |
7238 exception = graph.addConstantNull(compiler); | 6536 exception = graph.addConstantNull(compiler); |
7239 reporter.internalError(node, | 6537 reporter.internalError(node, 'rethrowableException should not be null.'); |
7240 'rethrowableException should not be null.'); | |
7241 } | 6538 } |
7242 handleInTryStatement(); | 6539 handleInTryStatement(); |
7243 closeAndGotoExit( | 6540 closeAndGotoExit(new HThrow( |
7244 new HThrow(exception, | 6541 exception, sourceInformationBuilder.buildThrow(node), |
7245 sourceInformationBuilder.buildThrow(node), | 6542 isRethrow: true)); |
7246 isRethrow: true)); | |
7247 } | 6543 } |
7248 | 6544 |
7249 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) { | 6545 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) { |
7250 ConstructorElement targetConstructor = | 6546 ConstructorElement targetConstructor = |
7251 elements.getRedirectingTargetConstructor(node).implementation; | 6547 elements.getRedirectingTargetConstructor(node).implementation; |
7252 ConstructorElement redirectingConstructor = sourceElement.implementation; | 6548 ConstructorElement redirectingConstructor = sourceElement.implementation; |
7253 List<HInstruction> inputs = <HInstruction>[]; | 6549 List<HInstruction> inputs = <HInstruction>[]; |
7254 FunctionSignature targetSignature = targetConstructor.functionSignature; | 6550 FunctionSignature targetSignature = targetConstructor.functionSignature; |
7255 FunctionSignature redirectingSignature = | 6551 FunctionSignature redirectingSignature = |
7256 redirectingConstructor.functionSignature; | 6552 redirectingConstructor.functionSignature; |
7257 | 6553 |
7258 List<Element> targetRequireds = targetSignature.requiredParameters; | 6554 List<Element> targetRequireds = targetSignature.requiredParameters; |
7259 List<Element> redirectingRequireds | 6555 List<Element> redirectingRequireds = |
7260 = redirectingSignature.requiredParameters; | 6556 redirectingSignature.requiredParameters; |
7261 | 6557 |
7262 List<Element> targetOptionals = | 6558 List<Element> targetOptionals = targetSignature.orderedOptionalParameters; |
7263 targetSignature.orderedOptionalParameters; | |
7264 List<Element> redirectingOptionals = | 6559 List<Element> redirectingOptionals = |
7265 redirectingSignature.orderedOptionalParameters; | 6560 redirectingSignature.orderedOptionalParameters; |
7266 | 6561 |
7267 // TODO(25579): This code can do the wrong thing redirecting constructor and | 6562 // TODO(25579): This code can do the wrong thing redirecting constructor and |
7268 // the target do not correspond. It is correct if there is no | 6563 // the target do not correspond. It is correct if there is no |
7269 // warning. Ideally the redirecting constructor and the target would be the | 6564 // warning. Ideally the redirecting constructor and the target would be the |
7270 // same function. | 6565 // same function. |
7271 | 6566 |
7272 void loadLocal(ParameterElement parameter) { | 6567 void loadLocal(ParameterElement parameter) { |
7273 inputs.add(localsHandler.readLocal(parameter)); | 6568 inputs.add(localsHandler.readLocal(parameter)); |
7274 } | 6569 } |
7275 void loadPosition(int position, ParameterElement optionalParameter) { | 6570 void loadPosition(int position, ParameterElement optionalParameter) { |
7276 if (position < redirectingRequireds.length) { | 6571 if (position < redirectingRequireds.length) { |
7277 loadLocal(redirectingRequireds[position]); | 6572 loadLocal(redirectingRequireds[position]); |
7278 } else if (position < redirectingSignature.parameterCount && | 6573 } else if (position < redirectingSignature.parameterCount && |
7279 !redirectingSignature.optionalParametersAreNamed) { | 6574 !redirectingSignature.optionalParametersAreNamed) { |
7280 loadLocal(redirectingOptionals[position - redirectingRequireds.length]); | 6575 loadLocal(redirectingOptionals[position - redirectingRequireds.length]); |
7281 } else if (optionalParameter != null) { | 6576 } else if (optionalParameter != null) { |
7282 inputs.add(handleConstantForOptionalParameter(optionalParameter)); | 6577 inputs.add(handleConstantForOptionalParameter(optionalParameter)); |
7283 } else { | 6578 } else { |
7284 // Wrong. | 6579 // Wrong. |
7285 inputs.add(graph.addConstantNull(compiler)); | 6580 inputs.add(graph.addConstantNull(compiler)); |
7286 } | 6581 } |
7287 } | 6582 } |
7288 | 6583 |
7289 int position = 0; | 6584 int position = 0; |
7290 | 6585 |
7291 for (ParameterElement targetParameter in targetRequireds) { | 6586 for (ParameterElement targetParameter in targetRequireds) { |
7292 loadPosition(position++, null); | 6587 loadPosition(position++, null); |
7293 } | 6588 } |
7294 | 6589 |
7295 if (targetOptionals.isNotEmpty) { | 6590 if (targetOptionals.isNotEmpty) { |
7296 if (targetSignature.optionalParametersAreNamed) { | 6591 if (targetSignature.optionalParametersAreNamed) { |
7297 for (ParameterElement parameter in targetOptionals) { | 6592 for (ParameterElement parameter in targetOptionals) { |
7298 ParameterElement redirectingParameter = | 6593 ParameterElement redirectingParameter = redirectingOptionals |
7299 redirectingOptionals.firstWhere( | 6594 .firstWhere((p) => p.name == parameter.name, orElse: () => null); |
7300 (p) => p.name == parameter.name, | |
7301 orElse: () => null); | |
7302 if (redirectingParameter == null) { | 6595 if (redirectingParameter == null) { |
7303 inputs.add(handleConstantForOptionalParameter(parameter)); | 6596 inputs.add(handleConstantForOptionalParameter(parameter)); |
7304 } else { | 6597 } else { |
7305 inputs.add(localsHandler.readLocal(redirectingParameter)); | 6598 inputs.add(localsHandler.readLocal(redirectingParameter)); |
7306 } | 6599 } |
7307 } | 6600 } |
7308 } else { | 6601 } else { |
7309 for (ParameterElement parameter in targetOptionals) { | 6602 for (ParameterElement parameter in targetOptionals) { |
7310 loadPosition(position++, parameter); | 6603 loadPosition(position++, parameter); |
7311 } | 6604 } |
(...skipping 16 matching lines...) Expand all Loading... |
7328 } | 6621 } |
7329 | 6622 |
7330 /// Returns true if the [type] is a valid return type for an asynchronous | 6623 /// Returns true if the [type] is a valid return type for an asynchronous |
7331 /// function. | 6624 /// function. |
7332 /// | 6625 /// |
7333 /// Asynchronous functions return a `Future`, and a valid return is thus | 6626 /// Asynchronous functions return a `Future`, and a valid return is thus |
7334 /// either dynamic, Object, or Future. | 6627 /// either dynamic, Object, or Future. |
7335 /// | 6628 /// |
7336 /// We do not accept the internal Future implementation class. | 6629 /// We do not accept the internal Future implementation class. |
7337 bool isValidAsyncReturnType(DartType type) { | 6630 bool isValidAsyncReturnType(DartType type) { |
7338 assert (isBuildingAsyncFunction); | 6631 assert(isBuildingAsyncFunction); |
7339 // TODO(sigurdm): In an internal library a function could be declared: | 6632 // TODO(sigurdm): In an internal library a function could be declared: |
7340 // | 6633 // |
7341 // _FutureImpl foo async => 1; | 6634 // _FutureImpl foo async => 1; |
7342 // | 6635 // |
7343 // This should be valid (because the actual value returned from an async | 6636 // This should be valid (because the actual value returned from an async |
7344 // function is a `_FutureImpl`), but currently false is returned in this | 6637 // function is a `_FutureImpl`), but currently false is returned in this |
7345 // case. | 6638 // case. |
7346 return type.isDynamic || | 6639 return type.isDynamic || |
7347 type.isObject || | 6640 type.isObject || |
7348 (type is InterfaceType && | 6641 (type is InterfaceType && type.element == coreClasses.futureClass); |
7349 type.element == coreClasses.futureClass); | |
7350 } | 6642 } |
7351 | 6643 |
7352 visitReturn(ast.Return node) { | 6644 visitReturn(ast.Return node) { |
7353 if (identical(node.beginToken.stringValue, 'native')) { | 6645 if (identical(node.beginToken.stringValue, 'native')) { |
7354 native.handleSsaNative(this, node.expression); | 6646 native.handleSsaNative(this, node.expression); |
7355 return; | 6647 return; |
7356 } | 6648 } |
7357 HInstruction value; | 6649 HInstruction value; |
7358 if (node.expression == null) { | 6650 if (node.expression == null) { |
7359 value = graph.addConstantNull(compiler); | 6651 value = graph.addConstantNull(compiler); |
7360 } else { | 6652 } else { |
7361 visit(node.expression); | 6653 visit(node.expression); |
7362 value = pop(); | 6654 value = pop(); |
7363 if (isBuildingAsyncFunction) { | 6655 if (isBuildingAsyncFunction) { |
7364 if (compiler.options.enableTypeAssertions && | 6656 if (compiler.options.enableTypeAssertions && |
7365 !isValidAsyncReturnType(returnType)) { | 6657 !isValidAsyncReturnType(returnType)) { |
7366 String message = | 6658 String message = "Async function returned a Future, " |
7367 "Async function returned a Future, " | 6659 "was declared to return a $returnType."; |
7368 "was declared to return a $returnType."; | |
7369 generateTypeError(node, message); | 6660 generateTypeError(node, message); |
7370 pop(); | 6661 pop(); |
7371 return; | 6662 return; |
7372 } | 6663 } |
7373 } else { | 6664 } else { |
7374 value = potentiallyCheckOrTrustType(value, returnType); | 6665 value = potentiallyCheckOrTrustType(value, returnType); |
7375 } | 6666 } |
7376 } | 6667 } |
7377 | 6668 |
7378 handleInTryStatement(); | 6669 handleInTryStatement(); |
(...skipping 13 matching lines...) Expand all Loading... |
7392 visitYield(ast.Yield node) { | 6683 visitYield(ast.Yield node) { |
7393 visit(node.expression); | 6684 visit(node.expression); |
7394 HInstruction yielded = pop(); | 6685 HInstruction yielded = pop(); |
7395 add(new HYield(yielded, node.hasStar)); | 6686 add(new HYield(yielded, node.hasStar)); |
7396 } | 6687 } |
7397 | 6688 |
7398 visitAwait(ast.Await node) { | 6689 visitAwait(ast.Await node) { |
7399 visit(node.expression); | 6690 visit(node.expression); |
7400 HInstruction awaited = pop(); | 6691 HInstruction awaited = pop(); |
7401 // TODO(herhut): Improve this type. | 6692 // TODO(herhut): Improve this type. |
7402 push(new HAwait(awaited, new TypeMask.subclass( | 6693 push(new HAwait(awaited, |
7403 coreClasses.objectClass, compiler.world))); | 6694 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
7404 } | 6695 } |
7405 | 6696 |
7406 visitTypeAnnotation(ast.TypeAnnotation node) { | 6697 visitTypeAnnotation(ast.TypeAnnotation node) { |
7407 reporter.internalError(node, | 6698 reporter.internalError(node, 'Visiting type annotation in SSA builder.'); |
7408 'Visiting type annotation in SSA builder.'); | |
7409 } | 6699 } |
7410 | 6700 |
7411 visitVariableDefinitions(ast.VariableDefinitions node) { | 6701 visitVariableDefinitions(ast.VariableDefinitions node) { |
7412 assert(isReachable); | 6702 assert(isReachable); |
7413 for (Link<ast.Node> link = node.definitions.nodes; | 6703 for (Link<ast.Node> link = node.definitions.nodes; |
7414 !link.isEmpty; | 6704 !link.isEmpty; |
7415 link = link.tail) { | 6705 link = link.tail) { |
7416 ast.Node definition = link.head; | 6706 ast.Node definition = link.head; |
7417 LocalElement local = elements[definition]; | 6707 LocalElement local = elements[definition]; |
7418 if (definition is ast.Identifier) { | 6708 if (definition is ast.Identifier) { |
7419 HInstruction initialValue = graph.addConstantNull(compiler); | 6709 HInstruction initialValue = graph.addConstantNull(compiler); |
7420 localsHandler.updateLocal(local, initialValue); | 6710 localsHandler.updateLocal(local, initialValue); |
7421 } else { | 6711 } else { |
7422 ast.SendSet node = definition; | 6712 ast.SendSet node = definition; |
7423 generateNonInstanceSetter( | 6713 generateNonInstanceSetter( |
7424 node, local, visitAndPop(node.arguments.first)); | 6714 node, local, visitAndPop(node.arguments.first)); |
7425 pop(); // Discard value. | 6715 pop(); // Discard value. |
7426 } | 6716 } |
7427 } | 6717 } |
7428 } | 6718 } |
7429 | 6719 |
7430 HInstruction setRtiIfNeeded(HInstruction object, ast.Node node) { | 6720 HInstruction setRtiIfNeeded(HInstruction object, ast.Node node) { |
7431 InterfaceType type = localsHandler.substInContext(elements.getType(node)); | 6721 InterfaceType type = localsHandler.substInContext(elements.getType(node)); |
7432 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { | 6722 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { |
7433 return object; | 6723 return object; |
7434 } | 6724 } |
7435 List<HInstruction> arguments = <HInstruction>[]; | 6725 List<HInstruction> arguments = <HInstruction>[]; |
7436 for (DartType argument in type.typeArguments) { | 6726 for (DartType argument in type.typeArguments) { |
7437 arguments.add(analyzeTypeArgument(argument)); | 6727 arguments.add(analyzeTypeArgument(argument)); |
7438 } | 6728 } |
7439 // TODO(15489): Register at codegen. | 6729 // TODO(15489): Register at codegen. |
7440 registry?.registerInstantiation(type); | 6730 registry?.registerInstantiation(type); |
7441 return callSetRuntimeTypeInfo(type.element, arguments, object); | 6731 return callSetRuntimeTypeInfo(type.element, arguments, object); |
7442 } | 6732 } |
7443 | 6733 |
7444 visitLiteralList(ast.LiteralList node) { | 6734 visitLiteralList(ast.LiteralList node) { |
7445 HInstruction instruction; | 6735 HInstruction instruction; |
7446 | 6736 |
7447 if (node.isConst) { | 6737 if (node.isConst) { |
7448 instruction = addConstant(node); | 6738 instruction = addConstant(node); |
7449 } else { | 6739 } else { |
7450 List<HInstruction> inputs = <HInstruction>[]; | 6740 List<HInstruction> inputs = <HInstruction>[]; |
7451 for (Link<ast.Node> link = node.elements.nodes; | 6741 for (Link<ast.Node> link = node.elements.nodes; |
7452 !link.isEmpty; | 6742 !link.isEmpty; |
7453 link = link.tail) { | 6743 link = link.tail) { |
7454 visit(link.head); | 6744 visit(link.head); |
7455 inputs.add(pop()); | 6745 inputs.add(pop()); |
7456 } | 6746 } |
7457 instruction = buildLiteralList(inputs); | 6747 instruction = buildLiteralList(inputs); |
7458 add(instruction); | 6748 add(instruction); |
7459 instruction = setRtiIfNeeded(instruction, node); | 6749 instruction = setRtiIfNeeded(instruction, node); |
7460 } | 6750 } |
7461 | 6751 |
7462 TypeMask type = | 6752 TypeMask type = |
7463 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); | 6753 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); |
7464 if (!type.containsAll(compiler.world)) instruction.instructionType = type; | 6754 if (!type.containsAll(compiler.world)) instruction.instructionType = type; |
7465 stack.add(instruction); | 6755 stack.add(instruction); |
7466 } | 6756 } |
7467 | 6757 |
7468 visitConditional(ast.Conditional node) { | 6758 visitConditional(ast.Conditional node) { |
7469 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6759 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
7470 brancher.handleConditional(() => visit(node.condition), | 6760 brancher.handleConditional(() => visit(node.condition), |
7471 () => visit(node.thenExpression), | 6761 () => visit(node.thenExpression), () => visit(node.elseExpression)); |
7472 () => visit(node.elseExpression)); | |
7473 } | 6762 } |
7474 | 6763 |
7475 visitStringInterpolation(ast.StringInterpolation node) { | 6764 visitStringInterpolation(ast.StringInterpolation node) { |
7476 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); | 6765 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); |
7477 stringBuilder.visit(node); | 6766 stringBuilder.visit(node); |
7478 stack.add(stringBuilder.result); | 6767 stack.add(stringBuilder.result); |
7479 } | 6768 } |
7480 | 6769 |
7481 visitStringInterpolationPart(ast.StringInterpolationPart node) { | 6770 visitStringInterpolationPart(ast.StringInterpolationPart node) { |
7482 // The parts are iterated in visitStringInterpolation. | 6771 // The parts are iterated in visitStringInterpolation. |
7483 reporter.internalError(node, | 6772 reporter.internalError( |
7484 'SsaBuilder.visitStringInterpolation should not be called.'); | 6773 node, 'SsaBuilder.visitStringInterpolation should not be called.'); |
7485 } | 6774 } |
7486 | 6775 |
7487 visitEmptyStatement(ast.EmptyStatement node) { | 6776 visitEmptyStatement(ast.EmptyStatement node) { |
7488 // Do nothing, empty statement. | 6777 // Do nothing, empty statement. |
7489 } | 6778 } |
7490 | 6779 |
7491 visitModifiers(ast.Modifiers node) { | 6780 visitModifiers(ast.Modifiers node) { |
7492 compiler.unimplemented(node, 'SsaFromAstMixin.visitModifiers.'); | 6781 compiler.unimplemented(node, 'SsaFromAstMixin.visitModifiers.'); |
7493 } | 6782 } |
7494 | 6783 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7544 } | 6833 } |
7545 return new JumpHandler(this, element); | 6834 return new JumpHandler(this, element); |
7546 } | 6835 } |
7547 | 6836 |
7548 visitAsyncForIn(ast.AsyncForIn node) { | 6837 visitAsyncForIn(ast.AsyncForIn node) { |
7549 // The async-for is implemented with a StreamIterator. | 6838 // The async-for is implemented with a StreamIterator. |
7550 HInstruction streamIterator; | 6839 HInstruction streamIterator; |
7551 | 6840 |
7552 visit(node.expression); | 6841 visit(node.expression); |
7553 HInstruction expression = pop(); | 6842 HInstruction expression = pop(); |
7554 pushInvokeStatic(node, | 6843 pushInvokeStatic(node, helpers.streamIteratorConstructor, |
7555 helpers.streamIteratorConstructor, | 6844 [expression, graph.addConstantNull(compiler)]); |
7556 [expression, graph.addConstantNull(compiler)]); | |
7557 streamIterator = pop(); | 6845 streamIterator = pop(); |
7558 | 6846 |
7559 void buildInitializer() {} | 6847 void buildInitializer() {} |
7560 | 6848 |
7561 HInstruction buildCondition() { | 6849 HInstruction buildCondition() { |
7562 Selector selector = Selectors.moveNext; | 6850 Selector selector = Selectors.moveNext; |
7563 TypeMask mask = elements.getMoveNextTypeMask(node); | 6851 TypeMask mask = elements.getMoveNextTypeMask(node); |
7564 pushInvokeDynamic(node, selector, mask, [streamIterator]); | 6852 pushInvokeDynamic(node, selector, mask, [streamIterator]); |
7565 HInstruction future = pop(); | 6853 HInstruction future = pop(); |
7566 push(new HAwait(future, | 6854 push(new HAwait(future, |
7567 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); | 6855 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
7568 return popBoolified(); | 6856 return popBoolified(); |
7569 } | 6857 } |
7570 void buildBody() { | 6858 void buildBody() { |
7571 Selector call = Selectors.current; | 6859 Selector call = Selectors.current; |
7572 TypeMask callMask = elements.getCurrentTypeMask(node); | 6860 TypeMask callMask = elements.getCurrentTypeMask(node); |
7573 pushInvokeDynamic(node, call, callMask, [streamIterator]); | 6861 pushInvokeDynamic(node, call, callMask, [streamIterator]); |
7574 | 6862 |
7575 ast.Node identifier = node.declaredIdentifier; | 6863 ast.Node identifier = node.declaredIdentifier; |
7576 Element variable = elements.getForInVariable(node); | 6864 Element variable = elements.getForInVariable(node); |
7577 Selector selector = elements.getSelector(identifier); | 6865 Selector selector = elements.getSelector(identifier); |
7578 TypeMask mask = elements.getTypeMask(identifier); | 6866 TypeMask mask = elements.getTypeMask(identifier); |
7579 | 6867 |
7580 HInstruction value = pop(); | 6868 HInstruction value = pop(); |
7581 if (identifier.asSend() != null | 6869 if (identifier.asSend() != null && |
7582 && Elements.isInstanceSend(identifier, elements)) { | 6870 Elements.isInstanceSend(identifier, elements)) { |
7583 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6871 HInstruction receiver = generateInstanceSendReceiver(identifier); |
7584 assert(receiver != null); | 6872 assert(receiver != null); |
7585 generateInstanceSetterWithCompiledReceiver( | 6873 generateInstanceSetterWithCompiledReceiver(null, receiver, value, |
7586 null, | 6874 selector: selector, mask: mask, location: identifier); |
7587 receiver, | |
7588 value, | |
7589 selector: selector, | |
7590 mask: mask, | |
7591 location: identifier); | |
7592 } else { | 6875 } else { |
7593 generateNonInstanceSetter( | 6876 generateNonInstanceSetter(null, variable, value, location: identifier); |
7594 null, variable, value, location: identifier); | |
7595 } | 6877 } |
7596 pop(); // Pop the value pushed by the setter call. | 6878 pop(); // Pop the value pushed by the setter call. |
7597 | 6879 |
7598 visit(node.body); | 6880 visit(node.body); |
7599 } | 6881 } |
7600 | 6882 |
7601 void buildUpdate() {}; | 6883 void buildUpdate() {} |
| 6884 ; |
7602 | 6885 |
7603 buildProtectedByFinally(() { | 6886 buildProtectedByFinally(() { |
7604 handleLoop(node, | 6887 handleLoop( |
7605 buildInitializer, | 6888 node, buildInitializer, buildCondition, buildUpdate, buildBody); |
7606 buildCondition, | |
7607 buildUpdate, | |
7608 buildBody); | |
7609 }, () { | 6889 }, () { |
7610 pushInvokeDynamic(node, | 6890 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); |
7611 Selectors.cancel, | 6891 push(new HAwait(pop(), |
7612 null, | 6892 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
7613 [streamIterator]); | |
7614 push(new HAwait(pop(), new TypeMask.subclass( | |
7615 coreClasses.objectClass, compiler.world))); | |
7616 pop(); | 6893 pop(); |
7617 }); | 6894 }); |
7618 } | 6895 } |
7619 | 6896 |
7620 visitSyncForIn(ast.SyncForIn node) { | 6897 visitSyncForIn(ast.SyncForIn node) { |
7621 // The 'get iterator' selector for this node has the inferred receiver type. | 6898 // The 'get iterator' selector for this node has the inferred receiver type. |
7622 // If the receiver supports JavaScript indexing we generate an indexing loop | 6899 // If the receiver supports JavaScript indexing we generate an indexing loop |
7623 // instead of allocating an iterator object. | 6900 // instead of allocating an iterator object. |
7624 | 6901 |
7625 // This scheme recognizes for-in on direct lists. It does not recognize all | 6902 // This scheme recognizes for-in on direct lists. It does not recognize all |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7682 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { | 6959 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
7683 ast.Node identifier = node.declaredIdentifier; | 6960 ast.Node identifier = node.declaredIdentifier; |
7684 Element variable = elements.getForInVariable(node); | 6961 Element variable = elements.getForInVariable(node); |
7685 Selector selector = elements.getSelector(identifier); | 6962 Selector selector = elements.getSelector(identifier); |
7686 TypeMask mask = elements.getTypeMask(identifier); | 6963 TypeMask mask = elements.getTypeMask(identifier); |
7687 | 6964 |
7688 if (identifier.asSend() != null && | 6965 if (identifier.asSend() != null && |
7689 Elements.isInstanceSend(identifier, elements)) { | 6966 Elements.isInstanceSend(identifier, elements)) { |
7690 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6967 HInstruction receiver = generateInstanceSendReceiver(identifier); |
7691 assert(receiver != null); | 6968 assert(receiver != null); |
7692 generateInstanceSetterWithCompiledReceiver( | 6969 generateInstanceSetterWithCompiledReceiver(null, receiver, value, |
7693 null, | 6970 selector: selector, mask: mask, location: identifier); |
7694 receiver, | |
7695 value, | |
7696 selector: selector, | |
7697 mask: mask, | |
7698 location: identifier); | |
7699 } else { | 6971 } else { |
7700 generateNonInstanceSetter(null, variable, value, location: identifier); | 6972 generateNonInstanceSetter(null, variable, value, location: identifier); |
7701 } | 6973 } |
7702 pop(); // Discard the value pushed by the setter call. | 6974 pop(); // Discard the value pushed by the setter call. |
7703 } | 6975 } |
7704 | 6976 |
7705 buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) { | 6977 buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) { |
7706 // Generate a structure equivalent to: | 6978 // Generate a structure equivalent to: |
7707 // | 6979 // |
7708 // int end = a.length; | 6980 // int end = a.length; |
7709 // for (int i = 0; | 6981 // for (int i = 0; |
7710 // i < a.length; | 6982 // i < a.length; |
7711 // checkConcurrentModificationError(a.length == end, a), ++i) { | 6983 // checkConcurrentModificationError(a.length == end, a), ++i) { |
7712 // <declaredIdentifier> = a[i]; | 6984 // <declaredIdentifier> = a[i]; |
7713 // <body> | 6985 // <body> |
7714 // } | 6986 // } |
7715 Element loopVariable = elements.getForInVariable(node); | 6987 Element loopVariable = elements.getForInVariable(node); |
7716 SyntheticLocal indexVariable = new SyntheticLocal('_i', loopVariable); | 6988 SyntheticLocal indexVariable = new SyntheticLocal('_i', loopVariable); |
7717 TypeMask boolType = backend.boolType; | 6989 TypeMask boolType = backend.boolType; |
7718 | 6990 |
7719 // These variables are shared by initializer, condition, body and update. | 6991 // These variables are shared by initializer, condition, body and update. |
7720 HInstruction array; // Set in buildInitializer. | 6992 HInstruction array; // Set in buildInitializer. |
7721 bool isFixed; // Set in buildInitializer. | 6993 bool isFixed; // Set in buildInitializer. |
7722 HInstruction originalLength = null; // Set for growable lists. | 6994 HInstruction originalLength = null; // Set for growable lists. |
7723 | 6995 |
7724 HInstruction buildGetLength() { | 6996 HInstruction buildGetLength() { |
7725 Element lengthElement = helpers.jsIndexableLength; | 6997 Element lengthElement = helpers.jsIndexableLength; |
7726 HFieldGet result = new HFieldGet( | 6998 HFieldGet result = new HFieldGet( |
7727 lengthElement, array, backend.positiveIntType, | 6999 lengthElement, array, backend.positiveIntType, |
7728 isAssignable: !isFixed); | 7000 isAssignable: !isFixed); |
7729 add(result); | 7001 add(result); |
7730 return result; | 7002 return result; |
7731 } | 7003 } |
7732 | 7004 |
7733 void buildConcurrentModificationErrorCheck() { | 7005 void buildConcurrentModificationErrorCheck() { |
7734 if (originalLength == null) return; | 7006 if (originalLength == null) return; |
7735 // The static call checkConcurrentModificationError() is expanded in | 7007 // The static call checkConcurrentModificationError() is expanded in |
7736 // codegen to: | 7008 // codegen to: |
7737 // | 7009 // |
7738 // array.length == _end || throwConcurrentModificationError(array) | 7010 // array.length == _end || throwConcurrentModificationError(array) |
7739 // | 7011 // |
7740 HInstruction length = buildGetLength(); | 7012 HInstruction length = buildGetLength(); |
7741 push(new HIdentity(length, originalLength, null, boolType)); | 7013 push(new HIdentity(length, originalLength, null, boolType)); |
7742 pushInvokeStatic(node, | 7014 pushInvokeStatic( |
7743 helpers.checkConcurrentModificationError, | 7015 node, helpers.checkConcurrentModificationError, [pop(), array]); |
7744 [pop(), array]); | |
7745 pop(); | 7016 pop(); |
7746 } | 7017 } |
7747 | 7018 |
7748 void buildInitializer() { | 7019 void buildInitializer() { |
7749 visit(node.expression); | 7020 visit(node.expression); |
7750 array = pop(); | 7021 array = pop(); |
7751 isFixed = isFixedLength(array.instructionType, compiler); | 7022 isFixed = isFixedLength(array.instructionType, compiler); |
7752 localsHandler.updateLocal(indexVariable, | 7023 localsHandler.updateLocal( |
7753 graph.addConstantInt(0, compiler)); | 7024 indexVariable, graph.addConstantInt(0, compiler)); |
7754 originalLength = buildGetLength(); | 7025 originalLength = buildGetLength(); |
7755 } | 7026 } |
7756 | 7027 |
7757 HInstruction buildCondition() { | 7028 HInstruction buildCondition() { |
7758 HInstruction index = localsHandler.readLocal(indexVariable); | 7029 HInstruction index = localsHandler.readLocal(indexVariable); |
7759 HInstruction length = buildGetLength(); | 7030 HInstruction length = buildGetLength(); |
7760 HInstruction compare = new HLess(index, length, null, boolType); | 7031 HInstruction compare = new HLess(index, length, null, boolType); |
7761 add(compare); | 7032 add(compare); |
7762 return compare; | 7033 return compare; |
7763 } | 7034 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7803 | 7074 |
7804 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 7075 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
7805 } | 7076 } |
7806 | 7077 |
7807 visitLabel(ast.Label node) { | 7078 visitLabel(ast.Label node) { |
7808 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); | 7079 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); |
7809 } | 7080 } |
7810 | 7081 |
7811 visitLabeledStatement(ast.LabeledStatement node) { | 7082 visitLabeledStatement(ast.LabeledStatement node) { |
7812 ast.Statement body = node.statement; | 7083 ast.Statement body = node.statement; |
7813 if (body is ast.Loop | 7084 if (body is ast.Loop || |
7814 || body is ast.SwitchStatement | 7085 body is ast.SwitchStatement || |
7815 || Elements.isUnusedLabel(node, elements)) { | 7086 Elements.isUnusedLabel(node, elements)) { |
7816 // Loops and switches handle their own labels. | 7087 // Loops and switches handle their own labels. |
7817 visit(body); | 7088 visit(body); |
7818 return; | 7089 return; |
7819 } | 7090 } |
7820 JumpTarget targetElement = elements.getTargetDefinition(body); | 7091 JumpTarget targetElement = elements.getTargetDefinition(body); |
7821 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); | 7092 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); |
7822 assert(targetElement.isBreakTarget); | 7093 assert(targetElement.isBreakTarget); |
7823 JumpHandler handler = new JumpHandler(this, targetElement); | 7094 JumpHandler handler = new JumpHandler(this, targetElement); |
7824 // Introduce a new basic block. | 7095 // Introduce a new basic block. |
7825 HBasicBlock entryBlock = openNewBlock(); | 7096 HBasicBlock entryBlock = openNewBlock(); |
(...skipping 10 matching lines...) Expand all Loading... |
7836 if (!isAborted()) { | 7107 if (!isAborted()) { |
7837 goto(current, joinBlock); | 7108 goto(current, joinBlock); |
7838 breakHandlers.add(localsHandler); | 7109 breakHandlers.add(localsHandler); |
7839 } | 7110 } |
7840 open(joinBlock); | 7111 open(joinBlock); |
7841 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); | 7112 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); |
7842 | 7113 |
7843 if (hasBreak) { | 7114 if (hasBreak) { |
7844 // There was at least one reachable break, so the label is needed. | 7115 // There was at least one reachable break, so the label is needed. |
7845 entryBlock.setBlockFlow( | 7116 entryBlock.setBlockFlow( |
7846 new HLabeledBlockInformation(new HSubGraphBlockInformation(bodyGraph), | 7117 new HLabeledBlockInformation( |
7847 handler.labels()), | 7118 new HSubGraphBlockInformation(bodyGraph), handler.labels()), |
7848 joinBlock); | 7119 joinBlock); |
7849 } | 7120 } |
7850 handler.close(); | 7121 handler.close(); |
7851 } | 7122 } |
7852 | 7123 |
7853 visitLiteralMap(ast.LiteralMap node) { | 7124 visitLiteralMap(ast.LiteralMap node) { |
7854 if (node.isConst) { | 7125 if (node.isConst) { |
7855 stack.add(addConstant(node)); | 7126 stack.add(addConstant(node)); |
7856 return; | 7127 return; |
7857 } | 7128 } |
7858 List<HInstruction> listInputs = <HInstruction>[]; | 7129 List<HInstruction> listInputs = <HInstruction>[]; |
7859 for (Link<ast.Node> link = node.entries.nodes; | 7130 for (Link<ast.Node> link = node.entries.nodes; |
7860 !link.isEmpty; | 7131 !link.isEmpty; |
7861 link = link.tail) { | 7132 link = link.tail) { |
7862 visit(link.head); | 7133 visit(link.head); |
7863 listInputs.add(pop()); | 7134 listInputs.add(pop()); |
7864 listInputs.add(pop()); | 7135 listInputs.add(pop()); |
7865 } | 7136 } |
7866 | 7137 |
7867 Element constructor; | 7138 Element constructor; |
7868 List<HInstruction> inputs = <HInstruction>[]; | 7139 List<HInstruction> inputs = <HInstruction>[]; |
7869 | 7140 |
7870 if (listInputs.isEmpty) { | 7141 if (listInputs.isEmpty) { |
7871 constructor = helpers.mapLiteralConstructorEmpty; | 7142 constructor = helpers.mapLiteralConstructorEmpty; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7910 // If rti is needed and the map literal has no type parameters, | 7181 // If rti is needed and the map literal has no type parameters, |
7911 // 'constructor' is a static function that forwards the call to the factory | 7182 // 'constructor' is a static function that forwards the call to the factory |
7912 // constructor without type parameters. | 7183 // constructor without type parameters. |
7913 assert(constructor is ConstructorElement || constructor is FunctionElement); | 7184 assert(constructor is ConstructorElement || constructor is FunctionElement); |
7914 | 7185 |
7915 // The instruction type will always be a subtype of the mapLiteralClass, but | 7186 // The instruction type will always be a subtype of the mapLiteralClass, but |
7916 // type inference might discover a more specific type, or find nothing (in | 7187 // type inference might discover a more specific type, or find nothing (in |
7917 // dart2js unit tests). | 7188 // dart2js unit tests). |
7918 TypeMask mapType = | 7189 TypeMask mapType = |
7919 new TypeMask.nonNullSubtype(helpers.mapLiteralClass, compiler.world); | 7190 new TypeMask.nonNullSubtype(helpers.mapLiteralClass, compiler.world); |
7920 TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement( | 7191 TypeMask returnTypeMask = |
7921 constructor, compiler); | 7192 TypeMaskFactory.inferredReturnTypeForElement(constructor, compiler); |
7922 TypeMask instructionType = | 7193 TypeMask instructionType = |
7923 mapType.intersection(returnTypeMask, compiler.world); | 7194 mapType.intersection(returnTypeMask, compiler.world); |
7924 | 7195 |
7925 addInlinedInstantiation(expectedType); | 7196 addInlinedInstantiation(expectedType); |
7926 pushInvokeStatic(node, constructor, inputs, | 7197 pushInvokeStatic(node, constructor, inputs, |
7927 typeMask: instructionType, instanceType: expectedType); | 7198 typeMask: instructionType, instanceType: expectedType); |
7928 removeInlinedInstantiation(expectedType); | 7199 removeInlinedInstantiation(expectedType); |
7929 } | 7200 } |
7930 | 7201 |
7931 visitLiteralMapEntry(ast.LiteralMapEntry node) { | 7202 visitLiteralMapEntry(ast.LiteralMapEntry node) { |
7932 visit(node.value); | 7203 visit(node.value); |
7933 visit(node.key); | 7204 visit(node.key); |
7934 } | 7205 } |
7935 | 7206 |
7936 visitNamedArgument(ast.NamedArgument node) { | 7207 visitNamedArgument(ast.NamedArgument node) { |
7937 visit(node.expression); | 7208 visit(node.expression); |
7938 } | 7209 } |
7939 | 7210 |
7940 Map<ast.CaseMatch, ConstantValue> buildSwitchCaseConstants( | 7211 Map<ast.CaseMatch, ConstantValue> buildSwitchCaseConstants( |
7941 ast.SwitchStatement node) { | 7212 ast.SwitchStatement node) { |
7942 | |
7943 Map<ast.CaseMatch, ConstantValue> constants = | 7213 Map<ast.CaseMatch, ConstantValue> constants = |
7944 new Map<ast.CaseMatch, ConstantValue>(); | 7214 new Map<ast.CaseMatch, ConstantValue>(); |
7945 for (ast.SwitchCase switchCase in node.cases) { | 7215 for (ast.SwitchCase switchCase in node.cases) { |
7946 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 7216 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
7947 if (labelOrCase is ast.CaseMatch) { | 7217 if (labelOrCase is ast.CaseMatch) { |
7948 ast.CaseMatch match = labelOrCase; | 7218 ast.CaseMatch match = labelOrCase; |
7949 ConstantValue constant = getConstantForNode(match.expression); | 7219 ConstantValue constant = getConstantForNode(match.expression); |
7950 constants[labelOrCase] = constant; | 7220 constants[labelOrCase] = constant; |
7951 } | 7221 } |
7952 } | 7222 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7986 buildSimpleSwitchStatement(node, constants); | 7256 buildSimpleSwitchStatement(node, constants); |
7987 } else { | 7257 } else { |
7988 buildComplexSwitchStatement(node, constants, caseIndex, hasDefault); | 7258 buildComplexSwitchStatement(node, constants, caseIndex, hasDefault); |
7989 } | 7259 } |
7990 } | 7260 } |
7991 | 7261 |
7992 /** | 7262 /** |
7993 * Builds a simple switch statement which does not handle uses of continue | 7263 * Builds a simple switch statement which does not handle uses of continue |
7994 * statements to labeled switch cases. | 7264 * statements to labeled switch cases. |
7995 */ | 7265 */ |
7996 void buildSimpleSwitchStatement(ast.SwitchStatement node, | 7266 void buildSimpleSwitchStatement( |
7997 Map<ast.CaseMatch, ConstantValue> constants) { | 7267 ast.SwitchStatement node, Map<ast.CaseMatch, ConstantValue> constants) { |
7998 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); | 7268 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); |
7999 HInstruction buildExpression() { | 7269 HInstruction buildExpression() { |
8000 visit(node.expression); | 7270 visit(node.expression); |
8001 return pop(); | 7271 return pop(); |
8002 } | 7272 } |
8003 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 7273 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
8004 List<ConstantValue> constantList = <ConstantValue>[]; | 7274 List<ConstantValue> constantList = <ConstantValue>[]; |
8005 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 7275 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
8006 if (labelOrCase is ast.CaseMatch) { | 7276 if (labelOrCase is ast.CaseMatch) { |
8007 constantList.add(constants[labelOrCase]); | 7277 constantList.add(constants[labelOrCase]); |
8008 } | 7278 } |
8009 } | 7279 } |
8010 return constantList; | 7280 return constantList; |
8011 } | 7281 } |
8012 bool isDefaultCase(ast.SwitchCase switchCase) { | 7282 bool isDefaultCase(ast.SwitchCase switchCase) { |
8013 return switchCase.isDefaultCase; | 7283 return switchCase.isDefaultCase; |
8014 } | 7284 } |
8015 void buildSwitchCase(ast.SwitchCase node) { | 7285 void buildSwitchCase(ast.SwitchCase node) { |
8016 visit(node.statements); | 7286 visit(node.statements); |
8017 } | 7287 } |
8018 handleSwitch(node, | 7288 handleSwitch(node, jumpHandler, buildExpression, node.cases, getConstants, |
8019 jumpHandler, | 7289 isDefaultCase, buildSwitchCase); |
8020 buildExpression, | |
8021 node.cases, | |
8022 getConstants, | |
8023 isDefaultCase, | |
8024 buildSwitchCase); | |
8025 jumpHandler.close(); | 7290 jumpHandler.close(); |
8026 } | 7291 } |
8027 | 7292 |
8028 /** | 7293 /** |
8029 * Builds a switch statement that can handle arbitrary uses of continue | 7294 * Builds a switch statement that can handle arbitrary uses of continue |
8030 * statements to labeled switch cases. | 7295 * statements to labeled switch cases. |
8031 */ | 7296 */ |
8032 void buildComplexSwitchStatement(ast.SwitchStatement node, | 7297 void buildComplexSwitchStatement( |
8033 Map<ast.CaseMatch, ConstantValue> constants, | 7298 ast.SwitchStatement node, |
8034 Map<ast.SwitchCase, int> caseIndex, | 7299 Map<ast.CaseMatch, ConstantValue> constants, |
8035 bool hasDefault) { | 7300 Map<ast.SwitchCase, int> caseIndex, |
| 7301 bool hasDefault) { |
8036 // If the switch statement has switch cases targeted by continue | 7302 // If the switch statement has switch cases targeted by continue |
8037 // statements we create the following encoding: | 7303 // statements we create the following encoding: |
8038 // | 7304 // |
8039 // switch (e) { | 7305 // switch (e) { |
8040 // l_1: case e0: s_1; break; | 7306 // l_1: case e0: s_1; break; |
8041 // l_2: case e1: s_2; continue l_i; | 7307 // l_2: case e1: s_2; continue l_i; |
8042 // ... | 7308 // ... |
8043 // l_n: default: s_n; continue l_j; | 7309 // l_n: default: s_n; continue l_j; |
8044 // } | 7310 // } |
8045 // | 7311 // |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8097 int index = caseIndex[switchCase]; | 7363 int index = caseIndex[switchCase]; |
8098 HInstruction value = graph.addConstantInt(index, compiler); | 7364 HInstruction value = graph.addConstantInt(index, compiler); |
8099 localsHandler.updateLocal(switchTarget, value); | 7365 localsHandler.updateLocal(switchTarget, value); |
8100 } else { | 7366 } else { |
8101 // Generate synthetic default case 'target = null; break;'. | 7367 // Generate synthetic default case 'target = null; break;'. |
8102 HInstruction value = graph.addConstantNull(compiler); | 7368 HInstruction value = graph.addConstantNull(compiler); |
8103 localsHandler.updateLocal(switchTarget, value); | 7369 localsHandler.updateLocal(switchTarget, value); |
8104 } | 7370 } |
8105 jumpTargets[switchTarget].generateBreak(); | 7371 jumpTargets[switchTarget].generateBreak(); |
8106 } | 7372 } |
8107 handleSwitch(node, | 7373 handleSwitch(node, jumpHandler, buildExpression, switchCases, getConstants, |
8108 jumpHandler, | 7374 isDefaultCase, buildSwitchCase); |
8109 buildExpression, | |
8110 switchCases, | |
8111 getConstants, | |
8112 isDefaultCase, | |
8113 buildSwitchCase); | |
8114 jumpHandler.close(); | 7375 jumpHandler.close(); |
8115 | 7376 |
8116 HInstruction buildCondition() => | 7377 HInstruction buildCondition() => graph.addConstantBool(true, compiler); |
8117 graph.addConstantBool(true, compiler); | |
8118 | 7378 |
8119 void buildSwitch() { | 7379 void buildSwitch() { |
8120 HInstruction buildExpression() { | 7380 HInstruction buildExpression() { |
8121 return localsHandler.readLocal(switchTarget); | 7381 return localsHandler.readLocal(switchTarget); |
8122 } | 7382 } |
8123 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 7383 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
8124 return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])]; | 7384 return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])]; |
8125 } | 7385 } |
8126 void buildSwitchCase(ast.SwitchCase switchCase) { | 7386 void buildSwitchCase(ast.SwitchCase switchCase) { |
8127 visit(switchCase.statements); | 7387 visit(switchCase.statements); |
8128 if (!isAborted()) { | 7388 if (!isAborted()) { |
8129 // Ensure that we break the loop if the case falls through. (This | 7389 // Ensure that we break the loop if the case falls through. (This |
8130 // is only possible for the last case.) | 7390 // is only possible for the last case.) |
8131 jumpTargets[switchTarget].generateBreak(); | 7391 jumpTargets[switchTarget].generateBreak(); |
8132 } | 7392 } |
8133 } | 7393 } |
8134 // Pass a [NullJumpHandler] because the target for the contained break | 7394 // Pass a [NullJumpHandler] because the target for the contained break |
8135 // is not the generated switch statement but instead the loop generated | 7395 // is not the generated switch statement but instead the loop generated |
8136 // in the call to [handleLoop] below. | 7396 // in the call to [handleLoop] below. |
8137 handleSwitch(node, | 7397 handleSwitch( |
8138 new NullJumpHandler(reporter), | 7398 node, |
8139 buildExpression, node.cases, getConstants, | 7399 new NullJumpHandler(reporter), |
8140 (_) => false, // No case is default. | 7400 buildExpression, |
8141 buildSwitchCase); | 7401 node.cases, |
| 7402 getConstants, |
| 7403 (_) => false, // No case is default. |
| 7404 buildSwitchCase); |
8142 } | 7405 } |
8143 | 7406 |
8144 void buildLoop() { | 7407 void buildLoop() { |
8145 handleLoop(node, | 7408 handleLoop(node, () {}, buildCondition, () {}, buildSwitch); |
8146 () {}, | |
8147 buildCondition, | |
8148 () {}, | |
8149 buildSwitch); | |
8150 } | 7409 } |
8151 | 7410 |
8152 if (hasDefault) { | 7411 if (hasDefault) { |
8153 buildLoop(); | 7412 buildLoop(); |
8154 } else { | 7413 } else { |
8155 // If the switch statement has no default case, surround the loop with | 7414 // If the switch statement has no default case, surround the loop with |
8156 // a test of the target. | 7415 // a test of the target. |
8157 void buildCondition() { | 7416 void buildCondition() { |
8158 js.Template code = js.js.parseForeignJS('#'); | 7417 js.Template code = js.js.parseForeignJS('#'); |
8159 push(new HForeignCode( | 7418 push(new HForeignCode( |
8160 code, | 7419 code, backend.boolType, [localsHandler.readLocal(switchTarget)], |
8161 backend.boolType, | |
8162 [localsHandler.readLocal(switchTarget)], | |
8163 nativeBehavior: native.NativeBehavior.PURE)); | 7420 nativeBehavior: native.NativeBehavior.PURE)); |
8164 } | 7421 } |
8165 handleIf(node, | 7422 handleIf(node, |
8166 visitCondition: buildCondition, | 7423 visitCondition: buildCondition, |
8167 visitThen: buildLoop, | 7424 visitThen: buildLoop, |
8168 visitElse: () => {}); | 7425 visitElse: () => {}); |
8169 } | 7426 } |
8170 } | 7427 } |
8171 | 7428 |
8172 /** | 7429 /** |
8173 * Creates a switch statement. | 7430 * Creates a switch statement. |
8174 * | 7431 * |
8175 * [jumpHandler] is the [JumpHandler] for the created switch statement. | 7432 * [jumpHandler] is the [JumpHandler] for the created switch statement. |
8176 * [buildExpression] creates the switch expression. | 7433 * [buildExpression] creates the switch expression. |
8177 * [switchCases] must be either an [Iterable] of [ast.SwitchCase] nodes or | 7434 * [switchCases] must be either an [Iterable] of [ast.SwitchCase] nodes or |
8178 * a [Link] or a [ast.NodeList] of [ast.SwitchCase] nodes. | 7435 * a [Link] or a [ast.NodeList] of [ast.SwitchCase] nodes. |
8179 * [getConstants] returns the set of constants for a switch case. | 7436 * [getConstants] returns the set of constants for a switch case. |
8180 * [isDefaultCase] returns [:true:] if the provided switch case should be | 7437 * [isDefaultCase] returns [:true:] if the provided switch case should be |
8181 * considered default for the created switch statement. | 7438 * considered default for the created switch statement. |
8182 * [buildSwitchCase] creates the statements for the switch case. | 7439 * [buildSwitchCase] creates the statements for the switch case. |
8183 */ | 7440 */ |
8184 void handleSwitch( | 7441 void handleSwitch( |
8185 ast.Node errorNode, | 7442 ast.Node errorNode, |
8186 JumpHandler jumpHandler, | 7443 JumpHandler jumpHandler, |
8187 HInstruction buildExpression(), | 7444 HInstruction buildExpression(), |
8188 var switchCases, | 7445 var switchCases, |
8189 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase), | 7446 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase), |
8190 bool isDefaultCase(ast.SwitchCase switchCase), | 7447 bool isDefaultCase(ast.SwitchCase switchCase), |
8191 void buildSwitchCase(ast.SwitchCase switchCase)) { | 7448 void buildSwitchCase(ast.SwitchCase switchCase)) { |
8192 | |
8193 HBasicBlock expressionStart = openNewBlock(); | 7449 HBasicBlock expressionStart = openNewBlock(); |
8194 HInstruction expression = buildExpression(); | 7450 HInstruction expression = buildExpression(); |
8195 if (switchCases.isEmpty) { | 7451 if (switchCases.isEmpty) { |
8196 return; | 7452 return; |
8197 } | 7453 } |
8198 | 7454 |
8199 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); | 7455 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); |
8200 HBasicBlock expressionEnd = close(switchInstruction); | 7456 HBasicBlock expressionEnd = close(switchInstruction); |
8201 LocalsHandler savedLocals = localsHandler; | 7457 LocalsHandler savedLocals = localsHandler; |
8202 | 7458 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8248 // If we never jump to the join block, [caseHandlers] will stay empty, and | 7504 // If we never jump to the join block, [caseHandlers] will stay empty, and |
8249 // the join block is never added to the graph. | 7505 // the join block is never added to the graph. |
8250 HBasicBlock joinBlock = new HBasicBlock(); | 7506 HBasicBlock joinBlock = new HBasicBlock(); |
8251 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; | 7507 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; |
8252 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | 7508 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { |
8253 instruction.block.addSuccessor(joinBlock); | 7509 instruction.block.addSuccessor(joinBlock); |
8254 caseHandlers.add(locals); | 7510 caseHandlers.add(locals); |
8255 }); | 7511 }); |
8256 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) { | 7512 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) { |
8257 assert(invariant(errorNode, false, | 7513 assert(invariant(errorNode, false, |
8258 message: 'Continue cannot target a switch.')); | 7514 message: 'Continue cannot target a switch.')); |
8259 }); | 7515 }); |
8260 if (!isAborted()) { | 7516 if (!isAborted()) { |
8261 current.close(new HGoto()); | 7517 current.close(new HGoto()); |
8262 lastOpenedBlock.addSuccessor(joinBlock); | 7518 lastOpenedBlock.addSuccessor(joinBlock); |
8263 caseHandlers.add(localsHandler); | 7519 caseHandlers.add(localsHandler); |
8264 } | 7520 } |
8265 if (!hasDefault) { | 7521 if (!hasDefault) { |
8266 // Always create a default case, to avoid a critical edge in the | 7522 // Always create a default case, to avoid a critical edge in the |
8267 // graph. | 7523 // graph. |
8268 HBasicBlock defaultCase = addNewBlock(); | 7524 HBasicBlock defaultCase = addNewBlock(); |
8269 expressionEnd.addSuccessor(defaultCase); | 7525 expressionEnd.addSuccessor(defaultCase); |
8270 open(defaultCase); | 7526 open(defaultCase); |
8271 close(new HGoto()); | 7527 close(new HGoto()); |
8272 defaultCase.addSuccessor(joinBlock); | 7528 defaultCase.addSuccessor(joinBlock); |
8273 caseHandlers.add(savedLocals); | 7529 caseHandlers.add(savedLocals); |
8274 statements.add(new HSubGraphBlockInformation(new SubGraph( | 7530 statements.add(new HSubGraphBlockInformation( |
8275 defaultCase, defaultCase))); | 7531 new SubGraph(defaultCase, defaultCase))); |
8276 } | 7532 } |
8277 assert(caseHandlers.length == joinBlock.predecessors.length); | 7533 assert(caseHandlers.length == joinBlock.predecessors.length); |
8278 if (caseHandlers.length != 0) { | 7534 if (caseHandlers.length != 0) { |
8279 graph.addBlock(joinBlock); | 7535 graph.addBlock(joinBlock); |
8280 open(joinBlock); | 7536 open(joinBlock); |
8281 if (caseHandlers.length == 1) { | 7537 if (caseHandlers.length == 1) { |
8282 localsHandler = caseHandlers[0]; | 7538 localsHandler = caseHandlers[0]; |
8283 } else { | 7539 } else { |
8284 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock); | 7540 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock); |
8285 } | 7541 } |
8286 } else { | 7542 } else { |
8287 // The joinblock is not used. | 7543 // The joinblock is not used. |
8288 joinBlock = null; | 7544 joinBlock = null; |
8289 } | 7545 } |
8290 | 7546 |
8291 HSubExpressionBlockInformation expressionInfo = | 7547 HSubExpressionBlockInformation expressionInfo = |
8292 new HSubExpressionBlockInformation(new SubExpression(expressionStart, | 7548 new HSubExpressionBlockInformation( |
8293 expressionEnd)); | 7549 new SubExpression(expressionStart, expressionEnd)); |
8294 expressionStart.setBlockFlow( | 7550 expressionStart.setBlockFlow( |
8295 new HSwitchBlockInformation(expressionInfo, | 7551 new HSwitchBlockInformation(expressionInfo, statements, |
8296 statements, | 7552 jumpHandler.target, jumpHandler.labels()), |
8297 jumpHandler.target, | |
8298 jumpHandler.labels()), | |
8299 joinBlock); | 7553 joinBlock); |
8300 | 7554 |
8301 jumpHandler.close(); | 7555 jumpHandler.close(); |
8302 } | 7556 } |
8303 | 7557 |
8304 visitSwitchCase(ast.SwitchCase node) { | 7558 visitSwitchCase(ast.SwitchCase node) { |
8305 reporter.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); | 7559 reporter.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); |
8306 } | 7560 } |
8307 | 7561 |
8308 visitCaseMatch(ast.CaseMatch node) { | 7562 visitCaseMatch(ast.CaseMatch node) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8389 addExitTrySuccessor(startFinallyBlock); | 7643 addExitTrySuccessor(startFinallyBlock); |
8390 | 7644 |
8391 // Use the locals handler not altered by the catch and finally | 7645 // Use the locals handler not altered by the catch and finally |
8392 // blocks. | 7646 // blocks. |
8393 // TODO(sigurdm): We can probably do this, because try-variables are boxed. | 7647 // TODO(sigurdm): We can probably do this, because try-variables are boxed. |
8394 // Need to verify. | 7648 // Need to verify. |
8395 localsHandler = savedLocals; | 7649 localsHandler = savedLocals; |
8396 open(exitBlock); | 7650 open(exitBlock); |
8397 enterBlock.setBlockFlow( | 7651 enterBlock.setBlockFlow( |
8398 new HTryBlockInformation( | 7652 new HTryBlockInformation( |
8399 wrapStatementGraph(bodyGraph), | 7653 wrapStatementGraph(bodyGraph), |
8400 null, // No catch-variable. | 7654 null, // No catch-variable. |
8401 null, // No catchGraph. | 7655 null, // No catchGraph. |
8402 wrapStatementGraph(finallyGraph)), | 7656 wrapStatementGraph(finallyGraph)), |
8403 exitBlock); | 7657 exitBlock); |
8404 inTryStatement = oldInTryStatement; | 7658 inTryStatement = oldInTryStatement; |
8405 } | 7659 } |
8406 | 7660 |
8407 visitTryStatement(ast.TryStatement node) { | 7661 visitTryStatement(ast.TryStatement node) { |
8408 // Save the current locals. The catch block and the finally block | 7662 // Save the current locals. The catch block and the finally block |
8409 // must not reuse the existing locals handler. None of the variables | 7663 // must not reuse the existing locals handler. None of the variables |
8410 // that have been defined in the body-block will be used, but for | 7664 // that have been defined in the body-block will be used, but for |
8411 // loops we will add (unnecessary) phis that will reference the body | 7665 // loops we will add (unnecessary) phis that will reference the body |
8412 // variables. This makes it look as if the variables were used | 7666 // variables. This makes it look as if the variables were used |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8482 } | 7736 } |
8483 } | 7737 } |
8484 } | 7738 } |
8485 | 7739 |
8486 void visitThen() { | 7740 void visitThen() { |
8487 ast.CatchBlock catchBlock = link.head; | 7741 ast.CatchBlock catchBlock = link.head; |
8488 link = link.tail; | 7742 link = link.tail; |
8489 if (catchBlock.exception != null) { | 7743 if (catchBlock.exception != null) { |
8490 LocalVariableElement exceptionVariable = | 7744 LocalVariableElement exceptionVariable = |
8491 elements[catchBlock.exception]; | 7745 elements[catchBlock.exception]; |
8492 localsHandler.updateLocal(exceptionVariable, | 7746 localsHandler.updateLocal(exceptionVariable, unwrappedException); |
8493 unwrappedException); | |
8494 } | 7747 } |
8495 ast.Node trace = catchBlock.trace; | 7748 ast.Node trace = catchBlock.trace; |
8496 if (trace != null) { | 7749 if (trace != null) { |
8497 pushInvokeStatic(trace, helpers.traceFromException, [exception]); | 7750 pushInvokeStatic(trace, helpers.traceFromException, [exception]); |
8498 HInstruction traceInstruction = pop(); | 7751 HInstruction traceInstruction = pop(); |
8499 LocalVariableElement traceVariable = elements[trace]; | 7752 LocalVariableElement traceVariable = elements[trace]; |
8500 localsHandler.updateLocal(traceVariable, traceInstruction); | 7753 localsHandler.updateLocal(traceVariable, traceInstruction); |
8501 } | 7754 } |
8502 visit(catchBlock); | 7755 visit(catchBlock); |
8503 } | 7756 } |
8504 | 7757 |
8505 void visitElse() { | 7758 void visitElse() { |
8506 if (link.isEmpty) { | 7759 if (link.isEmpty) { |
8507 closeAndGotoExit( | 7760 closeAndGotoExit(new HThrow(exception, exception.sourceInformation, |
8508 new HThrow(exception, | 7761 isRethrow: true)); |
8509 exception.sourceInformation, | |
8510 isRethrow: true)); | |
8511 } else { | 7762 } else { |
8512 ast.CatchBlock newBlock = link.head; | 7763 ast.CatchBlock newBlock = link.head; |
8513 handleIf(node, | 7764 handleIf(node, visitCondition: () { |
8514 visitCondition: () { pushCondition(newBlock); }, | 7765 pushCondition(newBlock); |
8515 visitThen: visitThen, | 7766 }, visitThen: visitThen, visitElse: visitElse); |
8516 visitElse: visitElse); | |
8517 } | 7767 } |
8518 } | 7768 } |
8519 | 7769 |
8520 ast.CatchBlock firstBlock = link.head; | 7770 ast.CatchBlock firstBlock = link.head; |
8521 handleIf(node, | 7771 handleIf(node, visitCondition: () { |
8522 visitCondition: () { pushCondition(firstBlock); }, | 7772 pushCondition(firstBlock); |
8523 visitThen: visitThen, | 7773 }, visitThen: visitThen, visitElse: visitElse); |
8524 visitElse: visitElse); | |
8525 if (!isAborted()) endCatchBlock = close(new HGoto()); | 7774 if (!isAborted()) endCatchBlock = close(new HGoto()); |
8526 | 7775 |
8527 rethrowableException = oldRethrowableException; | 7776 rethrowableException = oldRethrowableException; |
8528 tryInstruction.catchBlock = startCatchBlock; | 7777 tryInstruction.catchBlock = startCatchBlock; |
8529 catchGraph = new SubGraph(startCatchBlock, lastOpenedBlock); | 7778 catchGraph = new SubGraph(startCatchBlock, lastOpenedBlock); |
8530 } | 7779 } |
8531 | 7780 |
8532 SubGraph finallyGraph = null; | 7781 SubGraph finallyGraph = null; |
8533 if (node.finallyBlock != null) { | 7782 if (node.finallyBlock != null) { |
8534 localsHandler = new LocalsHandler.from(savedLocals); | 7783 localsHandler = new LocalsHandler.from(savedLocals); |
8535 startFinallyBlock = graph.addNewBlock(); | 7784 startFinallyBlock = graph.addNewBlock(); |
8536 open(startFinallyBlock); | 7785 open(startFinallyBlock); |
8537 visit(node.finallyBlock); | 7786 visit(node.finallyBlock); |
8538 if (!isAborted()) endFinallyBlock = close(new HGoto()); | 7787 if (!isAborted()) endFinallyBlock = close(new HGoto()); |
8539 tryInstruction.finallyBlock = startFinallyBlock; | 7788 tryInstruction.finallyBlock = startFinallyBlock; |
8540 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); | 7789 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); |
8541 } | 7790 } |
8542 | 7791 |
8543 HBasicBlock exitBlock = graph.addNewBlock(); | 7792 HBasicBlock exitBlock = graph.addNewBlock(); |
8544 | 7793 |
8545 addOptionalSuccessor(b1, b2) { if (b2 != null) b1.addSuccessor(b2); } | 7794 addOptionalSuccessor(b1, b2) { |
| 7795 if (b2 != null) b1.addSuccessor(b2); |
| 7796 } |
8546 addExitTrySuccessor(successor) { | 7797 addExitTrySuccessor(successor) { |
8547 if (successor == null) return; | 7798 if (successor == null) return; |
8548 // Iterate over all blocks created inside this try/catch, and | 7799 // Iterate over all blocks created inside this try/catch, and |
8549 // attach successor information to blocks that end with | 7800 // attach successor information to blocks that end with |
8550 // [HExitTry]. | 7801 // [HExitTry]. |
8551 for (int i = startTryBlock.id; i < successor.id; i++) { | 7802 for (int i = startTryBlock.id; i < successor.id; i++) { |
8552 HBasicBlock block = graph.blocks[i]; | 7803 HBasicBlock block = graph.blocks[i]; |
8553 var last = block.last; | 7804 var last = block.last; |
8554 if (last is HExitTry) { | 7805 if (last is HExitTry) { |
8555 block.addSuccessor(successor); | 7806 block.addSuccessor(successor); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8589 // we explicitely mark this block a predecessor of the catch | 7840 // we explicitely mark this block a predecessor of the catch |
8590 // block and the finally block. | 7841 // block and the finally block. |
8591 addExitTrySuccessor(startCatchBlock); | 7842 addExitTrySuccessor(startCatchBlock); |
8592 addExitTrySuccessor(startFinallyBlock); | 7843 addExitTrySuccessor(startFinallyBlock); |
8593 | 7844 |
8594 // Use the locals handler not altered by the catch and finally | 7845 // Use the locals handler not altered by the catch and finally |
8595 // blocks. | 7846 // blocks. |
8596 localsHandler = savedLocals; | 7847 localsHandler = savedLocals; |
8597 open(exitBlock); | 7848 open(exitBlock); |
8598 enterBlock.setBlockFlow( | 7849 enterBlock.setBlockFlow( |
8599 new HTryBlockInformation( | 7850 new HTryBlockInformation(wrapStatementGraph(bodyGraph), exception, |
8600 wrapStatementGraph(bodyGraph), | 7851 wrapStatementGraph(catchGraph), wrapStatementGraph(finallyGraph)), |
8601 exception, | |
8602 wrapStatementGraph(catchGraph), | |
8603 wrapStatementGraph(finallyGraph)), | |
8604 exitBlock); | 7852 exitBlock); |
8605 inTryStatement = oldInTryStatement; | 7853 inTryStatement = oldInTryStatement; |
8606 } | 7854 } |
8607 | 7855 |
8608 visitCatchBlock(ast.CatchBlock node) { | 7856 visitCatchBlock(ast.CatchBlock node) { |
8609 visit(node.block); | 7857 visit(node.block); |
8610 } | 7858 } |
8611 | 7859 |
8612 visitTypedef(ast.Typedef node) { | 7860 visitTypedef(ast.Typedef node) { |
8613 compiler.unimplemented(node, 'SsaFromAstMixin.visitTypedef.'); | 7861 compiler.unimplemented(node, 'SsaFromAstMixin.visitTypedef.'); |
8614 } | 7862 } |
8615 | 7863 |
8616 visitTypeVariable(ast.TypeVariable node) { | 7864 visitTypeVariable(ast.TypeVariable node) { |
8617 reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); | 7865 reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); |
8618 } | 7866 } |
8619 | 7867 |
8620 /** | 7868 /** |
8621 * This method is invoked before inlining the body of [function] into this | 7869 * This method is invoked before inlining the body of [function] into this |
8622 * [SsaBuilder]. | 7870 * [SsaBuilder]. |
8623 */ | 7871 */ |
8624 void enterInlinedMethod(FunctionElement function, | 7872 void enterInlinedMethod(FunctionElement function, ast.Node _, |
8625 ast.Node _, | 7873 List<HInstruction> compiledArguments, |
8626 List<HInstruction> compiledArguments, | 7874 {InterfaceType instanceType}) { |
8627 {InterfaceType instanceType}) { | |
8628 AstInliningState state = new AstInliningState( | 7875 AstInliningState state = new AstInliningState( |
8629 function, returnLocal, returnType, elements, stack, localsHandler, | 7876 function, |
| 7877 returnLocal, |
| 7878 returnType, |
| 7879 elements, |
| 7880 stack, |
| 7881 localsHandler, |
8630 inTryStatement, | 7882 inTryStatement, |
8631 allInlinedFunctionsCalledOnce && isFunctionCalledOnce(function)); | 7883 allInlinedFunctionsCalledOnce && isFunctionCalledOnce(function)); |
8632 inliningStack.add(state); | 7884 inliningStack.add(state); |
8633 | 7885 |
8634 // Setting up the state of the (AST) builder is performed even when the | 7886 // Setting up the state of the (AST) builder is performed even when the |
8635 // inlined function is in IR, because the irInliner uses the [returnElement] | 7887 // inlined function is in IR, because the irInliner uses the [returnElement] |
8636 // of the AST builder. | 7888 // of the AST builder. |
8637 setupStateForInlining( | 7889 setupStateForInlining(function, compiledArguments, |
8638 function, compiledArguments, instanceType: instanceType); | 7890 instanceType: instanceType); |
8639 } | 7891 } |
8640 | 7892 |
8641 void leaveInlinedMethod() { | 7893 void leaveInlinedMethod() { |
8642 HInstruction result = localsHandler.readLocal(returnLocal); | 7894 HInstruction result = localsHandler.readLocal(returnLocal); |
8643 AstInliningState state = inliningStack.removeLast(); | 7895 AstInliningState state = inliningStack.removeLast(); |
8644 restoreState(state); | 7896 restoreState(state); |
8645 stack.add(result); | 7897 stack.add(result); |
8646 } | 7898 } |
8647 | 7899 |
8648 void doInline(FunctionElement function) { | 7900 void doInline(FunctionElement function) { |
8649 visitInlinedFunction(function); | 7901 visitInlinedFunction(function); |
8650 } | 7902 } |
8651 | 7903 |
8652 void emitReturn(HInstruction value, ast.Node node) { | 7904 void emitReturn(HInstruction value, ast.Node node) { |
8653 if (inliningStack.isEmpty) { | 7905 if (inliningStack.isEmpty) { |
8654 closeAndGotoExit(new HReturn(value, | 7906 closeAndGotoExit( |
8655 sourceInformationBuilder.buildReturn(node))); | 7907 new HReturn(value, sourceInformationBuilder.buildReturn(node))); |
8656 } else { | 7908 } else { |
8657 localsHandler.updateLocal(returnLocal, value); | 7909 localsHandler.updateLocal(returnLocal, value); |
8658 } | 7910 } |
8659 } | 7911 } |
8660 | 7912 |
8661 @override | 7913 @override |
8662 void handleTypeLiteralConstantCompounds( | 7914 void handleTypeLiteralConstantCompounds( |
8663 ast.SendSet node, | 7915 ast.SendSet node, ConstantExpression constant, CompoundRhs rhs, _) { |
8664 ConstantExpression constant, | |
8665 CompoundRhs rhs, | |
8666 _) { | |
8667 handleTypeLiteralCompound(node); | 7916 handleTypeLiteralCompound(node); |
8668 } | 7917 } |
8669 | 7918 |
8670 @override | 7919 @override |
8671 void handleTypeVariableTypeLiteralCompounds( | 7920 void handleTypeVariableTypeLiteralCompounds( |
8672 ast.SendSet node, | 7921 ast.SendSet node, TypeVariableElement typeVariable, CompoundRhs rhs, _) { |
8673 TypeVariableElement typeVariable, | |
8674 CompoundRhs rhs, | |
8675 _) { | |
8676 handleTypeLiteralCompound(node); | 7922 handleTypeLiteralCompound(node); |
8677 } | 7923 } |
8678 | 7924 |
8679 void handleTypeLiteralCompound(ast.SendSet node) { | 7925 void handleTypeLiteralCompound(ast.SendSet node) { |
8680 generateIsDeferredLoadedCheckOfSend(node); | 7926 generateIsDeferredLoadedCheckOfSend(node); |
8681 ast.Identifier selector = node.selector; | 7927 ast.Identifier selector = node.selector; |
8682 generateThrowNoSuchMethod(node, selector.source, | 7928 generateThrowNoSuchMethod(node, selector.source, |
8683 argumentNodes: node.arguments); | 7929 argumentNodes: node.arguments); |
8684 } | 7930 } |
8685 | 7931 |
8686 @override | 7932 @override |
8687 void visitConstantGet( | 7933 void visitConstantGet(ast.Send node, ConstantExpression constant, _) { |
8688 ast.Send node, | |
8689 ConstantExpression constant, | |
8690 _) { | |
8691 visitNode(node); | 7934 visitNode(node); |
8692 } | 7935 } |
8693 | 7936 |
8694 @override | 7937 @override |
8695 void visitConstantInvoke( | 7938 void visitConstantInvoke(ast.Send node, ConstantExpression constant, |
8696 ast.Send node, | 7939 ast.NodeList arguments, CallStructure callStreucture, _) { |
8697 ConstantExpression constant, | |
8698 ast.NodeList arguments, | |
8699 CallStructure callStreucture, | |
8700 _) { | |
8701 visitNode(node); | 7940 visitNode(node); |
8702 } | 7941 } |
8703 | 7942 |
8704 @override | 7943 @override |
8705 void errorUndefinedBinaryExpression( | 7944 void errorUndefinedBinaryExpression( |
8706 ast.Send node, | 7945 ast.Send node, ast.Node left, ast.Operator operator, ast.Node right, _) { |
8707 ast.Node left, | |
8708 ast.Operator operator, | |
8709 ast.Node right, | |
8710 _) { | |
8711 visitNode(node); | 7946 visitNode(node); |
8712 } | 7947 } |
8713 | 7948 |
8714 @override | 7949 @override |
8715 void errorUndefinedUnaryExpression( | 7950 void errorUndefinedUnaryExpression( |
8716 ast.Send node, | 7951 ast.Send node, ast.Operator operator, ast.Node expression, _) { |
8717 ast.Operator operator, | |
8718 ast.Node expression, | |
8719 _) { | |
8720 visitNode(node); | 7952 visitNode(node); |
8721 } | 7953 } |
8722 | 7954 |
8723 @override | 7955 @override |
8724 void bulkHandleError(ast.Node node, ErroneousElement error, _) { | 7956 void bulkHandleError(ast.Node node, ErroneousElement error, _) { |
8725 // TODO(johnniwinther): Use an uncatchable error when supported. | 7957 // TODO(johnniwinther): Use an uncatchable error when supported. |
8726 generateRuntimeError(node, error.message); | 7958 generateRuntimeError(node, error.message); |
8727 } | 7959 } |
8728 } | 7960 } |
8729 | 7961 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8767 append(stringify(node, expression)); | 7999 append(stringify(node, expression)); |
8768 return; | 8000 return; |
8769 } | 8001 } |
8770 | 8002 |
8771 // If the `toString` method is guaranteed to return a string we can call it | 8003 // If the `toString` method is guaranteed to return a string we can call it |
8772 // directly. | 8004 // directly. |
8773 Selector selector = Selectors.toString_; | 8005 Selector selector = Selectors.toString_; |
8774 TypeMask type = TypeMaskFactory.inferredTypeForSelector( | 8006 TypeMask type = TypeMaskFactory.inferredTypeForSelector( |
8775 selector, expression.instructionType, compiler); | 8007 selector, expression.instructionType, compiler); |
8776 if (type.containsOnlyString(compiler.world)) { | 8008 if (type.containsOnlyString(compiler.world)) { |
8777 builder.pushInvokeDynamic( | 8009 builder.pushInvokeDynamic(node, selector, expression.instructionType, |
8778 node, selector, | 8010 <HInstruction>[expression]); |
8779 expression.instructionType, <HInstruction>[expression]); | |
8780 append(builder.pop()); | 8011 append(builder.pop()); |
8781 return; | 8012 return; |
8782 } | 8013 } |
8783 | 8014 |
8784 append(stringify(node, expression)); | 8015 append(stringify(node, expression)); |
8785 } | 8016 } |
8786 | 8017 |
8787 void visitStringInterpolation(ast.StringInterpolation node) { | 8018 void visitStringInterpolation(ast.StringInterpolation node) { |
8788 node.visitChildren(this); | 8019 node.visitChildren(this); |
8789 } | 8020 } |
8790 | 8021 |
8791 void visitStringInterpolationPart(ast.StringInterpolationPart node) { | 8022 void visitStringInterpolationPart(ast.StringInterpolationPart node) { |
8792 visit(node.expression); | 8023 visit(node.expression); |
8793 visit(node.string); | 8024 visit(node.string); |
8794 } | 8025 } |
8795 | 8026 |
8796 void visitStringJuxtaposition(ast.StringJuxtaposition node) { | 8027 void visitStringJuxtaposition(ast.StringJuxtaposition node) { |
8797 node.visitChildren(this); | 8028 node.visitChildren(this); |
8798 } | 8029 } |
8799 | 8030 |
8800 void visitNodeList(ast.NodeList node) { | 8031 void visitNodeList(ast.NodeList node) { |
8801 node.visitChildren(this); | 8032 node.visitChildren(this); |
8802 } | 8033 } |
8803 | 8034 |
8804 void append(HInstruction expression) { | 8035 void append(HInstruction expression) { |
8805 result = (result == null) ? expression : concat(result, expression); | 8036 result = (result == null) ? expression : concat(result, expression); |
8806 } | 8037 } |
8807 | 8038 |
8808 HInstruction concat(HInstruction left, HInstruction right) { | 8039 HInstruction concat(HInstruction left, HInstruction right) { |
8809 HInstruction instruction = new HStringConcat( | 8040 HInstruction instruction = |
8810 left, right, builder.backend.stringType); | 8041 new HStringConcat(left, right, builder.backend.stringType); |
8811 builder.add(instruction); | 8042 builder.add(instruction); |
8812 return instruction; | 8043 return instruction; |
8813 } | 8044 } |
8814 | 8045 |
8815 HInstruction stringify(ast.Node node, HInstruction expression) { | 8046 HInstruction stringify(ast.Node node, HInstruction expression) { |
8816 HInstruction instruction = | 8047 HInstruction instruction = |
8817 new HStringify(expression, builder.backend.stringType); | 8048 new HStringify(expression, builder.backend.stringType); |
8818 builder.add(instruction); | 8049 builder.add(instruction); |
8819 return instruction; | 8050 return instruction; |
8820 } | 8051 } |
(...skipping 14 matching lines...) Expand all Loading... |
8835 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4; | 8066 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4; |
8836 | 8067 |
8837 bool seenReturn = false; | 8068 bool seenReturn = false; |
8838 bool tooDifficult = false; | 8069 bool tooDifficult = false; |
8839 int nodeCount = 0; | 8070 int nodeCount = 0; |
8840 final int maxInliningNodes; | 8071 final int maxInliningNodes; |
8841 final bool useMaxInliningNodes; | 8072 final bool useMaxInliningNodes; |
8842 final bool allowLoops; | 8073 final bool allowLoops; |
8843 final bool enableUserAssertions; | 8074 final bool enableUserAssertions; |
8844 | 8075 |
8845 InlineWeeder(this.maxInliningNodes, | 8076 InlineWeeder(this.maxInliningNodes, this.useMaxInliningNodes, this.allowLoops, |
8846 this.useMaxInliningNodes, | 8077 this.enableUserAssertions); |
8847 this.allowLoops, | |
8848 this.enableUserAssertions); | |
8849 | 8078 |
8850 static bool canBeInlined(FunctionElement function, | 8079 static bool canBeInlined( |
8851 int maxInliningNodes, | 8080 FunctionElement function, int maxInliningNodes, bool useMaxInliningNodes, |
8852 bool useMaxInliningNodes, | 8081 {bool allowLoops: false, bool enableUserAssertions: null}) { |
8853 {bool allowLoops: false, | |
8854 bool enableUserAssertions: null}) { | |
8855 assert(enableUserAssertions is bool); // Ensure we passed it. | 8082 assert(enableUserAssertions is bool); // Ensure we passed it. |
8856 if (function.resolvedAst.elements.containsTryStatement) return false; | 8083 if (function.resolvedAst.elements.containsTryStatement) return false; |
8857 | 8084 |
8858 InlineWeeder weeder = | 8085 InlineWeeder weeder = new InlineWeeder(maxInliningNodes, |
8859 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops, | 8086 useMaxInliningNodes, allowLoops, enableUserAssertions); |
8860 enableUserAssertions); | |
8861 ast.FunctionExpression functionExpression = function.node; | 8087 ast.FunctionExpression functionExpression = function.node; |
8862 weeder.visit(functionExpression.initializers); | 8088 weeder.visit(functionExpression.initializers); |
8863 weeder.visit(functionExpression.body); | 8089 weeder.visit(functionExpression.body); |
8864 weeder.visit(functionExpression.asyncModifier); | 8090 weeder.visit(functionExpression.asyncModifier); |
8865 return !weeder.tooDifficult; | 8091 return !weeder.tooDifficult; |
8866 } | 8092 } |
8867 | 8093 |
8868 bool registerNode() { | 8094 bool registerNode() { |
8869 if (!useMaxInliningNodes) return true; | 8095 if (!useMaxInliningNodes) return true; |
8870 if (nodeCount++ > maxInliningNodes) { | 8096 if (nodeCount++ > maxInliningNodes) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8929 tooDifficult = true; | 8155 tooDifficult = true; |
8930 } | 8156 } |
8931 | 8157 |
8932 void visitRethrow(ast.Rethrow node) { | 8158 void visitRethrow(ast.Rethrow node) { |
8933 if (!registerNode()) return; | 8159 if (!registerNode()) return; |
8934 tooDifficult = true; | 8160 tooDifficult = true; |
8935 } | 8161 } |
8936 | 8162 |
8937 void visitReturn(ast.Return node) { | 8163 void visitReturn(ast.Return node) { |
8938 if (!registerNode()) return; | 8164 if (!registerNode()) return; |
8939 if (seenReturn | 8165 if (seenReturn || identical(node.beginToken.stringValue, 'native')) { |
8940 || identical(node.beginToken.stringValue, 'native')) { | |
8941 tooDifficult = true; | 8166 tooDifficult = true; |
8942 return; | 8167 return; |
8943 } | 8168 } |
8944 node.visitChildren(this); | 8169 node.visitChildren(this); |
8945 seenReturn = true; | 8170 seenReturn = true; |
8946 } | 8171 } |
8947 | 8172 |
8948 void visitThrow(ast.Throw node) { | 8173 void visitThrow(ast.Throw node) { |
8949 if (!registerNode()) return; | 8174 if (!registerNode()) return; |
8950 // For now, we don't want to handle throw after a return even if | 8175 // For now, we don't want to handle throw after a return even if |
(...skipping 19 matching lines...) Expand all Loading... |
8970 | 8195 |
8971 class AstInliningState extends InliningState { | 8196 class AstInliningState extends InliningState { |
8972 final Local oldReturnLocal; | 8197 final Local oldReturnLocal; |
8973 final DartType oldReturnType; | 8198 final DartType oldReturnType; |
8974 final TreeElements oldElements; | 8199 final TreeElements oldElements; |
8975 final List<HInstruction> oldStack; | 8200 final List<HInstruction> oldStack; |
8976 final LocalsHandler oldLocalsHandler; | 8201 final LocalsHandler oldLocalsHandler; |
8977 final bool inTryStatement; | 8202 final bool inTryStatement; |
8978 final bool allFunctionsCalledOnce; | 8203 final bool allFunctionsCalledOnce; |
8979 | 8204 |
8980 AstInliningState(FunctionElement function, | 8205 AstInliningState( |
8981 this.oldReturnLocal, | 8206 FunctionElement function, |
8982 this.oldReturnType, | 8207 this.oldReturnLocal, |
8983 this.oldElements, | 8208 this.oldReturnType, |
8984 this.oldStack, | 8209 this.oldElements, |
8985 this.oldLocalsHandler, | 8210 this.oldStack, |
8986 this.inTryStatement, | 8211 this.oldLocalsHandler, |
8987 this.allFunctionsCalledOnce) | 8212 this.inTryStatement, |
| 8213 this.allFunctionsCalledOnce) |
8988 : super(function); | 8214 : super(function); |
8989 } | 8215 } |
8990 | 8216 |
8991 class SsaBranch { | 8217 class SsaBranch { |
8992 final SsaBranchBuilder branchBuilder; | 8218 final SsaBranchBuilder branchBuilder; |
8993 final HBasicBlock block; | 8219 final HBasicBlock block; |
8994 LocalsHandler startLocals; | 8220 LocalsHandler startLocals; |
8995 LocalsHandler exitLocals; | 8221 LocalsHandler exitLocals; |
8996 SubGraph graph; | 8222 SubGraph graph; |
8997 | 8223 |
8998 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); | 8224 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); |
8999 } | 8225 } |
9000 | 8226 |
9001 class SsaBranchBuilder { | 8227 class SsaBranchBuilder { |
9002 final SsaBuilder builder; | 8228 final SsaBuilder builder; |
9003 final ast.Node diagnosticNode; | 8229 final ast.Node diagnosticNode; |
9004 | 8230 |
9005 SsaBranchBuilder(this.builder, [this.diagnosticNode]); | 8231 SsaBranchBuilder(this.builder, [this.diagnosticNode]); |
9006 | 8232 |
9007 Compiler get compiler => builder.compiler; | 8233 Compiler get compiler => builder.compiler; |
9008 | 8234 |
9009 void checkNotAborted() { | 8235 void checkNotAborted() { |
9010 if (builder.isAborted()) { | 8236 if (builder.isAborted()) { |
9011 compiler.unimplemented(diagnosticNode, "aborted control flow"); | 8237 compiler.unimplemented(diagnosticNode, "aborted control flow"); |
9012 } | 8238 } |
9013 } | 8239 } |
9014 | 8240 |
9015 void buildCondition(void visitCondition(), | 8241 void buildCondition( |
9016 SsaBranch conditionBranch, | 8242 void visitCondition(), |
9017 SsaBranch thenBranch, | 8243 SsaBranch conditionBranch, |
9018 SsaBranch elseBranch, | 8244 SsaBranch thenBranch, |
9019 SourceInformation sourceInformation) { | 8245 SsaBranch elseBranch, |
| 8246 SourceInformation sourceInformation) { |
9020 startBranch(conditionBranch); | 8247 startBranch(conditionBranch); |
9021 visitCondition(); | 8248 visitCondition(); |
9022 checkNotAborted(); | 8249 checkNotAborted(); |
9023 assert(identical(builder.current, builder.lastOpenedBlock)); | 8250 assert(identical(builder.current, builder.lastOpenedBlock)); |
9024 HInstruction conditionValue = builder.popBoolified(); | 8251 HInstruction conditionValue = builder.popBoolified(); |
9025 HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; | 8252 HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; |
9026 HBasicBlock conditionExitBlock = builder.current; | 8253 HBasicBlock conditionExitBlock = builder.current; |
9027 builder.close(branch); | 8254 builder.close(branch); |
9028 conditionBranch.exitLocals = builder.localsHandler; | 8255 conditionBranch.exitLocals = builder.localsHandler; |
9029 conditionExitBlock.addSuccessor(thenBranch.block); | 8256 conditionExitBlock.addSuccessor(thenBranch.block); |
9030 conditionExitBlock.addSuccessor(elseBranch.block); | 8257 conditionExitBlock.addSuccessor(elseBranch.block); |
9031 bool conditionBranchLocalsCanBeReused = | 8258 bool conditionBranchLocalsCanBeReused = |
9032 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); | 8259 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); |
9033 mergeLocals(conditionBranch, elseBranch, | 8260 mergeLocals(conditionBranch, elseBranch, |
9034 mayReuseFromLocals: conditionBranchLocalsCanBeReused); | 8261 mayReuseFromLocals: conditionBranchLocalsCanBeReused); |
9035 | 8262 |
9036 conditionBranch.graph = | 8263 conditionBranch.graph = |
9037 new SubExpression(conditionBranch.block, conditionExitBlock); | 8264 new SubExpression(conditionBranch.block, conditionExitBlock); |
9038 } | 8265 } |
9039 | 8266 |
9040 /** | 8267 /** |
9041 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] | 8268 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] |
9042 * return value implies that [mayReuseFromLocals] was set to [:true:]. | 8269 * return value implies that [mayReuseFromLocals] was set to [:true:]. |
9043 */ | 8270 */ |
9044 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, | 8271 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, |
9045 {bool mayReuseFromLocals}) { | 8272 {bool mayReuseFromLocals}) { |
9046 LocalsHandler fromLocals = fromBranch.exitLocals; | 8273 LocalsHandler fromLocals = fromBranch.exitLocals; |
9047 if (toBranch.startLocals == null) { | 8274 if (toBranch.startLocals == null) { |
9048 if (mayReuseFromLocals) { | 8275 if (mayReuseFromLocals) { |
9049 toBranch.startLocals = fromLocals; | 8276 toBranch.startLocals = fromLocals; |
9050 return false; | 8277 return false; |
9051 } else { | 8278 } else { |
9052 toBranch.startLocals = new LocalsHandler.from(fromLocals); | 8279 toBranch.startLocals = new LocalsHandler.from(fromLocals); |
9053 return true; | 8280 return true; |
9054 } | 8281 } |
9055 } else { | 8282 } else { |
9056 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); | 8283 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); |
9057 return true; | 8284 return true; |
9058 } | 8285 } |
9059 } | 8286 } |
9060 | 8287 |
9061 void startBranch(SsaBranch branch) { | 8288 void startBranch(SsaBranch branch) { |
9062 builder.graph.addBlock(branch.block); | 8289 builder.graph.addBlock(branch.block); |
9063 builder.localsHandler = branch.startLocals; | 8290 builder.localsHandler = branch.startLocals; |
9064 builder.open(branch.block); | 8291 builder.open(branch.block); |
9065 } | 8292 } |
9066 | 8293 |
9067 HInstruction buildBranch(SsaBranch branch, | 8294 HInstruction buildBranch(SsaBranch branch, void visitBranch(), |
9068 void visitBranch(), | 8295 SsaBranch joinBranch, bool isExpression) { |
9069 SsaBranch joinBranch, | |
9070 bool isExpression) { | |
9071 startBranch(branch); | 8296 startBranch(branch); |
9072 visitBranch(); | 8297 visitBranch(); |
9073 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); | 8298 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); |
9074 branch.exitLocals = builder.localsHandler; | 8299 branch.exitLocals = builder.localsHandler; |
9075 if (!builder.isAborted()) { | 8300 if (!builder.isAborted()) { |
9076 builder.goto(builder.current, joinBranch.block); | 8301 builder.goto(builder.current, joinBranch.block); |
9077 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); | 8302 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); |
9078 } | 8303 } |
9079 if (isExpression) { | 8304 if (isExpression) { |
9080 checkNotAborted(); | 8305 checkNotAborted(); |
9081 return builder.pop(); | 8306 return builder.pop(); |
9082 } | 8307 } |
9083 return null; | 8308 return null; |
9084 } | 8309 } |
9085 | 8310 |
9086 handleIf(void visitCondition(), | 8311 handleIf(void visitCondition(), void visitThen(), void visitElse(), |
9087 void visitThen(), | 8312 {SourceInformation sourceInformation}) { |
9088 void visitElse(), | |
9089 {SourceInformation sourceInformation}) { | |
9090 if (visitElse == null) { | 8313 if (visitElse == null) { |
9091 // Make sure to have an else part to avoid a critical edge. A | 8314 // Make sure to have an else part to avoid a critical edge. A |
9092 // critical edge is an edge that connects a block with multiple | 8315 // critical edge is an edge that connects a block with multiple |
9093 // successors to a block with multiple predecessors. We avoid | 8316 // successors to a block with multiple predecessors. We avoid |
9094 // such edges because they prevent inserting copies during code | 8317 // such edges because they prevent inserting copies during code |
9095 // generation of phi instructions. | 8318 // generation of phi instructions. |
9096 visitElse = () {}; | 8319 visitElse = () {}; |
9097 } | 8320 } |
9098 | 8321 |
9099 _handleDiamondBranch( | 8322 _handleDiamondBranch(visitCondition, visitThen, visitElse, |
9100 visitCondition, visitThen, visitElse, isExpression: false, | 8323 isExpression: false, sourceInformation: sourceInformation); |
9101 sourceInformation: sourceInformation); | |
9102 } | 8324 } |
9103 | 8325 |
9104 handleConditional(void visitCondition(), | 8326 handleConditional(void visitCondition(), void visitThen(), void visitElse()) { |
9105 void visitThen(), | |
9106 void visitElse()) { | |
9107 assert(visitElse != null); | 8327 assert(visitElse != null); |
9108 _handleDiamondBranch( | 8328 _handleDiamondBranch(visitCondition, visitThen, visitElse, |
9109 visitCondition, visitThen, visitElse, isExpression: true); | 8329 isExpression: true); |
9110 } | 8330 } |
9111 | 8331 |
9112 handleIfNull(void left(), void right()) { | 8332 handleIfNull(void left(), void right()) { |
9113 // x ?? y is transformed into: x == null ? y : x | 8333 // x ?? y is transformed into: x == null ? y : x |
9114 HInstruction leftExpression; | 8334 HInstruction leftExpression; |
9115 handleConditional( | 8335 handleConditional(() { |
9116 () { | 8336 left(); |
9117 left(); | 8337 leftExpression = builder.pop(); |
9118 leftExpression = builder.pop(); | 8338 builder.pushCheckNull(leftExpression); |
9119 builder.pushCheckNull(leftExpression); | 8339 }, right, () => builder.stack.add(leftExpression)); |
9120 }, | |
9121 right, | |
9122 () => builder.stack.add(leftExpression)); | |
9123 } | 8340 } |
9124 | 8341 |
9125 void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { | 8342 void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { |
9126 // x && y is transformed into: | 8343 // x && y is transformed into: |
9127 // t0 = boolify(x); | 8344 // t0 = boolify(x); |
9128 // if (t0) { | 8345 // if (t0) { |
9129 // t1 = boolify(y); | 8346 // t1 = boolify(y); |
9130 // } | 8347 // } |
9131 // result = phi(t1, false); | 8348 // result = phi(t1, false); |
9132 // | 8349 // |
(...skipping 17 matching lines...) Expand all Loading... |
9150 | 8367 |
9151 void visitThen() { | 8368 void visitThen() { |
9152 right(); | 8369 right(); |
9153 boolifiedRight = builder.popBoolified(); | 8370 boolifiedRight = builder.popBoolified(); |
9154 } | 8371 } |
9155 | 8372 |
9156 handleIf(visitCondition, visitThen, null); | 8373 handleIf(visitCondition, visitThen, null); |
9157 HConstant notIsAnd = | 8374 HConstant notIsAnd = |
9158 builder.graph.addConstantBool(!isAnd, builder.compiler); | 8375 builder.graph.addConstantBool(!isAnd, builder.compiler); |
9159 JavaScriptBackend backend = builder.backend; | 8376 JavaScriptBackend backend = builder.backend; |
9160 HPhi result = new HPhi.manyInputs(null, | 8377 HPhi result = new HPhi.manyInputs( |
9161 <HInstruction>[boolifiedRight, notIsAnd], | 8378 null, <HInstruction>[boolifiedRight, notIsAnd], backend.dynamicType); |
9162 backend.dynamicType); | |
9163 builder.current.addPhi(result); | 8379 builder.current.addPhi(result); |
9164 builder.stack.add(result); | 8380 builder.stack.add(result); |
9165 } | 8381 } |
9166 | 8382 |
9167 void handleLogicalAndOrWithLeftNode(ast.Node left, | 8383 void handleLogicalAndOrWithLeftNode(ast.Node left, void visitRight(), |
9168 void visitRight(), | 8384 {bool isAnd}) { |
9169 {bool isAnd}) { | |
9170 // This method is similar to [handleLogicalAndOr] but optimizes the case | 8385 // This method is similar to [handleLogicalAndOr] but optimizes the case |
9171 // where left is a logical "and" or logical "or". | 8386 // where left is a logical "and" or logical "or". |
9172 // | 8387 // |
9173 // For example (x && y) && z is transformed into x && (y && z): | 8388 // For example (x && y) && z is transformed into x && (y && z): |
9174 // t0 = boolify(x); | 8389 // t0 = boolify(x); |
9175 // if (t0) { | 8390 // if (t0) { |
9176 // t1 = boolify(y); | 8391 // t1 = boolify(y); |
9177 // if (t1) { | 8392 // if (t1) { |
9178 // t2 = boolify(z); | 8393 // t2 = boolify(z); |
9179 // } | 8394 // } |
9180 // t3 = phi(t2, false); | 8395 // t3 = phi(t2, false); |
9181 // } | 8396 // } |
9182 // result = phi(t3, false); | 8397 // result = phi(t3, false); |
9183 | 8398 |
9184 ast.Send send = left.asSend(); | 8399 ast.Send send = left.asSend(); |
9185 if (send != null && | 8400 if (send != null && (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { |
9186 (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { | |
9187 ast.Node newLeft = send.receiver; | 8401 ast.Node newLeft = send.receiver; |
9188 Link<ast.Node> link = send.argumentsNode.nodes; | 8402 Link<ast.Node> link = send.argumentsNode.nodes; |
9189 assert(link.tail.isEmpty); | 8403 assert(link.tail.isEmpty); |
9190 ast.Node middle = link.head; | 8404 ast.Node middle = link.head; |
9191 handleLogicalAndOrWithLeftNode( | 8405 handleLogicalAndOrWithLeftNode( |
9192 newLeft, | 8406 newLeft, |
9193 () => handleLogicalAndOrWithLeftNode(middle, visitRight, | 8407 () => |
9194 isAnd: isAnd), | 8408 handleLogicalAndOrWithLeftNode(middle, visitRight, isAnd: isAnd), |
9195 isAnd: isAnd); | 8409 isAnd: isAnd); |
9196 } else { | 8410 } else { |
9197 handleLogicalAndOr(() => builder.visit(left), visitRight, isAnd: isAnd); | 8411 handleLogicalAndOr(() => builder.visit(left), visitRight, isAnd: isAnd); |
9198 } | 8412 } |
9199 } | 8413 } |
9200 | 8414 |
9201 void _handleDiamondBranch(void visitCondition(), | 8415 void _handleDiamondBranch( |
9202 void visitThen(), | 8416 void visitCondition(), void visitThen(), void visitElse(), |
9203 void visitElse(), | 8417 {bool isExpression, SourceInformation sourceInformation}) { |
9204 {bool isExpression, | |
9205 SourceInformation sourceInformation}) { | |
9206 SsaBranch conditionBranch = new SsaBranch(this); | 8418 SsaBranch conditionBranch = new SsaBranch(this); |
9207 SsaBranch thenBranch = new SsaBranch(this); | 8419 SsaBranch thenBranch = new SsaBranch(this); |
9208 SsaBranch elseBranch = new SsaBranch(this); | 8420 SsaBranch elseBranch = new SsaBranch(this); |
9209 SsaBranch joinBranch = new SsaBranch(this); | 8421 SsaBranch joinBranch = new SsaBranch(this); |
9210 | 8422 |
9211 conditionBranch.startLocals = builder.localsHandler; | 8423 conditionBranch.startLocals = builder.localsHandler; |
9212 builder.goto(builder.current, conditionBranch.block); | 8424 builder.goto(builder.current, conditionBranch.block); |
9213 | 8425 |
9214 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, | 8426 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, |
9215 sourceInformation); | 8427 sourceInformation); |
9216 HInstruction thenValue = | 8428 HInstruction thenValue = |
9217 buildBranch(thenBranch, visitThen, joinBranch, isExpression); | 8429 buildBranch(thenBranch, visitThen, joinBranch, isExpression); |
9218 HInstruction elseValue = | 8430 HInstruction elseValue = |
9219 buildBranch(elseBranch, visitElse, joinBranch, isExpression); | 8431 buildBranch(elseBranch, visitElse, joinBranch, isExpression); |
9220 | 8432 |
9221 if (isExpression) { | 8433 if (isExpression) { |
9222 assert(thenValue != null && elseValue != null); | 8434 assert(thenValue != null && elseValue != null); |
9223 JavaScriptBackend backend = builder.backend; | 8435 JavaScriptBackend backend = builder.backend; |
9224 HPhi phi = new HPhi.manyInputs( | 8436 HPhi phi = new HPhi.manyInputs( |
9225 null, <HInstruction>[thenValue, elseValue], backend.dynamicType); | 8437 null, <HInstruction>[thenValue, elseValue], backend.dynamicType); |
9226 joinBranch.block.addPhi(phi); | 8438 joinBranch.block.addPhi(phi); |
9227 builder.stack.add(phi); | 8439 builder.stack.add(phi); |
9228 } | 8440 } |
9229 | 8441 |
9230 HBasicBlock joinBlock; | 8442 HBasicBlock joinBlock; |
9231 // If at least one branch did not abort, open the joinBranch. | 8443 // If at least one branch did not abort, open the joinBranch. |
9232 if (!joinBranch.block.predecessors.isEmpty) { | 8444 if (!joinBranch.block.predecessors.isEmpty) { |
9233 startBranch(joinBranch); | 8445 startBranch(joinBranch); |
9234 joinBlock = joinBranch.block; | 8446 joinBlock = joinBranch.block; |
9235 } | 8447 } |
9236 | 8448 |
9237 HIfBlockInformation info = | 8449 HIfBlockInformation info = new HIfBlockInformation( |
9238 new HIfBlockInformation( | 8450 new HSubExpressionBlockInformation(conditionBranch.graph), |
9239 new HSubExpressionBlockInformation(conditionBranch.graph), | 8451 new HSubGraphBlockInformation(thenBranch.graph), |
9240 new HSubGraphBlockInformation(thenBranch.graph), | 8452 new HSubGraphBlockInformation(elseBranch.graph)); |
9241 new HSubGraphBlockInformation(elseBranch.graph)); | |
9242 | 8453 |
9243 HBasicBlock conditionStartBlock = conditionBranch.block; | 8454 HBasicBlock conditionStartBlock = conditionBranch.block; |
9244 conditionStartBlock.setBlockFlow(info, joinBlock); | 8455 conditionStartBlock.setBlockFlow(info, joinBlock); |
9245 SubGraph conditionGraph = conditionBranch.graph; | 8456 SubGraph conditionGraph = conditionBranch.graph; |
9246 HIf branch = conditionGraph.end.last; | 8457 HIf branch = conditionGraph.end.last; |
9247 assert(branch is HIf); | 8458 assert(branch is HIf); |
9248 branch.blockInformation = conditionStartBlock.blockFlow; | 8459 branch.blockInformation = conditionStartBlock.blockFlow; |
9249 } | 8460 } |
9250 } | 8461 } |
9251 | 8462 |
9252 class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { | 8463 class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { |
9253 final ClassWorld classWorld; | 8464 final ClassWorld classWorld; |
9254 | 8465 |
9255 TypeBuilder(this.classWorld); | 8466 TypeBuilder(this.classWorld); |
9256 | 8467 |
9257 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); | 8468 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); |
9258 | 8469 |
9259 void visitVoidType(VoidType type, SsaBuilder builder) { | 8470 void visitVoidType(VoidType type, SsaBuilder builder) { |
9260 ClassElement cls = builder.backend.helpers.VoidRuntimeType; | 8471 ClassElement cls = builder.backend.helpers.VoidRuntimeType; |
9261 builder.push(new HVoidType(type, new TypeMask.exact(cls, classWorld))); | 8472 builder.push(new HVoidType(type, new TypeMask.exact(cls, classWorld))); |
9262 } | 8473 } |
9263 | 8474 |
9264 void visitTypeVariableType(TypeVariableType type, | 8475 void visitTypeVariableType(TypeVariableType type, SsaBuilder builder) { |
9265 SsaBuilder builder) { | |
9266 ClassElement cls = builder.backend.helpers.RuntimeType; | 8476 ClassElement cls = builder.backend.helpers.RuntimeType; |
9267 TypeMask instructionType = new TypeMask.subclass(cls, classWorld); | 8477 TypeMask instructionType = new TypeMask.subclass(cls, classWorld); |
9268 if (!builder.sourceElement.enclosingElement.isClosure && | 8478 if (!builder.sourceElement.enclosingElement.isClosure && |
9269 builder.sourceElement.isInstanceMember) { | 8479 builder.sourceElement.isInstanceMember) { |
9270 HInstruction receiver = builder.localsHandler.readThis(); | 8480 HInstruction receiver = builder.localsHandler.readThis(); |
9271 builder.push(new HReadTypeVariable(type, receiver, instructionType)); | 8481 builder.push(new HReadTypeVariable(type, receiver, instructionType)); |
9272 } else { | 8482 } else { |
9273 builder.push( | 8483 builder.push(new HReadTypeVariable.noReceiver( |
9274 new HReadTypeVariable.noReceiver( | 8484 type, builder.addTypeVariableReference(type), instructionType)); |
9275 type, builder.addTypeVariableReference(type), instructionType)); | |
9276 } | 8485 } |
9277 } | 8486 } |
9278 | 8487 |
9279 void visitFunctionType(FunctionType type, SsaBuilder builder) { | 8488 void visitFunctionType(FunctionType type, SsaBuilder builder) { |
9280 type.returnType.accept(this, builder); | 8489 type.returnType.accept(this, builder); |
9281 HInstruction returnType = builder.pop(); | 8490 HInstruction returnType = builder.pop(); |
9282 List<HInstruction> inputs = <HInstruction>[returnType]; | 8491 List<HInstruction> inputs = <HInstruction>[returnType]; |
9283 | 8492 |
9284 for (DartType parameter in type.parameterTypes) { | 8493 for (DartType parameter in type.parameterTypes) { |
9285 parameter.accept(this, builder); | 8494 parameter.accept(this, builder); |
9286 inputs.add(builder.pop()); | 8495 inputs.add(builder.pop()); |
9287 } | 8496 } |
9288 | 8497 |
9289 for (DartType parameter in type.optionalParameterTypes) { | 8498 for (DartType parameter in type.optionalParameterTypes) { |
9290 parameter.accept(this, builder); | 8499 parameter.accept(this, builder); |
9291 inputs.add(builder.pop()); | 8500 inputs.add(builder.pop()); |
9292 } | 8501 } |
9293 | 8502 |
9294 List<DartType> namedParameterTypes = type.namedParameterTypes; | 8503 List<DartType> namedParameterTypes = type.namedParameterTypes; |
9295 List<String> names = type.namedParameters; | 8504 List<String> names = type.namedParameters; |
9296 for (int index = 0; index < names.length; index++) { | 8505 for (int index = 0; index < names.length; index++) { |
9297 ast.DartString dartString = new ast.DartString.literal(names[index]); | 8506 ast.DartString dartString = new ast.DartString.literal(names[index]); |
9298 inputs.add( | 8507 inputs.add(builder.graph.addConstantString(dartString, builder.compiler)); |
9299 builder.graph.addConstantString(dartString, builder.compiler)); | |
9300 namedParameterTypes[index].accept(this, builder); | 8508 namedParameterTypes[index].accept(this, builder); |
9301 inputs.add(builder.pop()); | 8509 inputs.add(builder.pop()); |
9302 } | 8510 } |
9303 | 8511 |
9304 ClassElement cls = builder.backend.helpers.RuntimeFunctionType; | 8512 ClassElement cls = builder.backend.helpers.RuntimeFunctionType; |
9305 builder.push(new HFunctionType(inputs, type, | 8513 builder.push( |
9306 new TypeMask.exact(cls, classWorld))); | 8514 new HFunctionType(inputs, type, new TypeMask.exact(cls, classWorld))); |
9307 } | 8515 } |
9308 | 8516 |
9309 void visitMalformedType(MalformedType type, SsaBuilder builder) { | 8517 void visitMalformedType(MalformedType type, SsaBuilder builder) { |
9310 visitDynamicType(const DynamicType(), builder); | 8518 visitDynamicType(const DynamicType(), builder); |
9311 } | 8519 } |
9312 | 8520 |
9313 void visitStatementType(StatementType type, SsaBuilder builder) { | 8521 void visitStatementType(StatementType type, SsaBuilder builder) { |
9314 throw 'not implemented visitStatementType($type)'; | 8522 throw 'not implemented visitStatementType($type)'; |
9315 } | 8523 } |
9316 | 8524 |
9317 void visitInterfaceType(InterfaceType type, SsaBuilder builder) { | 8525 void visitInterfaceType(InterfaceType type, SsaBuilder builder) { |
9318 List<HInstruction> inputs = <HInstruction>[]; | 8526 List<HInstruction> inputs = <HInstruction>[]; |
9319 for (DartType typeArgument in type.typeArguments) { | 8527 for (DartType typeArgument in type.typeArguments) { |
9320 typeArgument.accept(this, builder); | 8528 typeArgument.accept(this, builder); |
9321 inputs.add(builder.pop()); | 8529 inputs.add(builder.pop()); |
9322 } | 8530 } |
9323 ClassElement cls; | 8531 ClassElement cls; |
9324 if (type.typeArguments.isEmpty) { | 8532 if (type.typeArguments.isEmpty) { |
9325 cls = builder.backend.helpers.RuntimeTypePlain; | 8533 cls = builder.backend.helpers.RuntimeTypePlain; |
9326 } else { | 8534 } else { |
9327 cls = builder.backend.helpers.RuntimeTypeGeneric; | 8535 cls = builder.backend.helpers.RuntimeTypeGeneric; |
9328 } | 8536 } |
9329 builder.push(new HInterfaceType(inputs, type, | 8537 builder.push( |
9330 new TypeMask.exact(cls, classWorld))); | 8538 new HInterfaceType(inputs, type, new TypeMask.exact(cls, classWorld))); |
9331 } | 8539 } |
9332 | 8540 |
9333 void visitTypedefType(TypedefType type, SsaBuilder builder) { | 8541 void visitTypedefType(TypedefType type, SsaBuilder builder) { |
9334 DartType unaliased = type.unaliased; | 8542 DartType unaliased = type.unaliased; |
9335 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 8543 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
9336 unaliased.accept(this, builder); | 8544 unaliased.accept(this, builder); |
9337 } | 8545 } |
9338 | 8546 |
9339 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 8547 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
9340 JavaScriptBackend backend = builder.compiler.backend; | 8548 JavaScriptBackend backend = builder.compiler.backend; |
(...skipping 10 matching lines...) Expand all Loading... |
9351 const _LoopTypeVisitor(); | 8559 const _LoopTypeVisitor(); |
9352 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; | 8560 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; |
9353 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; | 8561 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; |
9354 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; | 8562 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; |
9355 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; | 8563 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; |
9356 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 8564 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
9357 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 8565 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
9358 int visitSwitchStatement(ast.SwitchStatement node) => | 8566 int visitSwitchStatement(ast.SwitchStatement node) => |
9359 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; | 8567 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; |
9360 } | 8568 } |
OLD | NEW |