OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 '../closure.dart'; | 5 import '../closure.dart'; |
6 import '../common.dart'; | 6 import '../common.dart'; |
7 import '../compiler.dart' show Compiler; | 7 import '../compiler.dart' show Compiler; |
8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
10 import '../io/source_information.dart'; | 10 import '../io/source_information.dart'; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 /// } | 54 /// } |
55 /// main() { | 55 /// main() { |
56 /// new Foo<String>('foo'); | 56 /// new Foo<String>('foo'); |
57 /// } | 57 /// } |
58 /// | 58 /// |
59 /// [instanceType] is not used if it contains type variables, since these | 59 /// [instanceType] is not used if it contains type variables, since these |
60 /// might not be in scope or from the current instance. | 60 /// might not be in scope or from the current instance. |
61 /// | 61 /// |
62 final InterfaceType instanceType; | 62 final InterfaceType instanceType; |
63 | 63 |
64 final Compiler compiler; | 64 final Compiler _compiler; |
65 | 65 |
66 LocalsHandler(this.builder, this.executableContext, | 66 LocalsHandler(this.builder, this.executableContext, |
67 InterfaceType instanceType, this.compiler) | 67 InterfaceType instanceType, this._compiler) |
68 : this.instanceType = | 68 : this.instanceType = |
69 instanceType == null || instanceType.containsTypeVariables | 69 instanceType == null || instanceType.containsTypeVariables |
70 ? null | 70 ? null |
71 : instanceType; | 71 : instanceType; |
72 | 72 |
73 /// Substituted type variables occurring in [type] into the context of | 73 /// Substituted type variables occurring in [type] into the context of |
74 /// [contextClass]. | 74 /// [contextClass]. |
75 DartType substInContext(DartType type) { | 75 DartType substInContext(DartType type) { |
76 if (contextClass != null) { | 76 if (contextClass != null) { |
77 ClassElement typeContext = Types.getClassContext(type); | 77 ClassElement typeContext = Types.getClassContext(type); |
(...skipping 10 matching lines...) Expand all Loading... |
88 /// Creates a new [LocalsHandler] based on [other]. We only need to | 88 /// Creates a new [LocalsHandler] based on [other]. We only need to |
89 /// copy the [directLocals], since the other fields can be shared | 89 /// copy the [directLocals], since the other fields can be shared |
90 /// throughout the AST visit. | 90 /// throughout the AST visit. |
91 LocalsHandler.from(LocalsHandler other) | 91 LocalsHandler.from(LocalsHandler other) |
92 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), | 92 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), |
93 redirectionMapping = other.redirectionMapping, | 93 redirectionMapping = other.redirectionMapping, |
94 executableContext = other.executableContext, | 94 executableContext = other.executableContext, |
95 instanceType = other.instanceType, | 95 instanceType = other.instanceType, |
96 builder = other.builder, | 96 builder = other.builder, |
97 closureData = other.closureData, | 97 closureData = other.closureData, |
98 compiler = other.compiler, | 98 _compiler = other._compiler, |
99 activationVariables = other.activationVariables, | 99 activationVariables = other.activationVariables, |
100 cachedTypeOfThis = other.cachedTypeOfThis, | 100 cachedTypeOfThis = other.cachedTypeOfThis, |
101 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; | 101 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; |
102 | 102 |
103 /// Redirects accesses from element [from] to element [to]. The [to] element | 103 /// Redirects accesses from element [from] to element [to]. The [to] element |
104 /// must be a boxed variable or a variable that is stored in a closure-field. | 104 /// must be a boxed variable or a variable that is stored in a closure-field. |
105 void redirectElement(Local from, CapturedVariable to) { | 105 void redirectElement(Local from, CapturedVariable to) { |
106 assert(redirectionMapping[from] == null); | 106 assert(redirectionMapping[from] == null); |
107 redirectionMapping[from] = to; | 107 redirectionMapping[from] = to; |
108 assert(isStoredInClosureField(from) || isBoxed(from)); | 108 assert(isStoredInClosureField(from) || isBoxed(from)); |
109 } | 109 } |
110 | 110 |
111 HInstruction createBox() { | 111 HInstruction createBox() { |
112 // TODO(floitsch): Clean up this hack. Should we create a box-object by | 112 // TODO(floitsch): Clean up this hack. Should we create a box-object by |
113 // just creating an empty object literal? | 113 // just creating an empty object literal? |
114 JavaScriptBackend backend = compiler.backend; | 114 JavaScriptBackend backend = _compiler.backend; |
115 HInstruction box = new HForeignCode( | 115 HInstruction box = new HForeignCode( |
116 js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[], | 116 js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[], |
117 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); | 117 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); |
118 builder.add(box); | 118 builder.add(box); |
119 return box; | 119 return box; |
120 } | 120 } |
121 | 121 |
122 /// If the scope (function or loop) [node] has captured variables then this | 122 /// If the scope (function or loop) [node] has captured variables then this |
123 /// method creates a box and sets up the redirections. | 123 /// method creates a box and sets up the redirections. |
124 void enterScope(ast.Node node, Element element) { | 124 void enterScope(ast.Node node, Element element) { |
125 // See if any variable in the top-scope of the function is captured. If yes | 125 // See if any variable in the top-scope of the function is captured. If yes |
126 // we need to create a box-object. | 126 // we need to create a box-object. |
127 ClosureScope scopeData = closureData.capturingScopes[node]; | 127 ClosureScope scopeData = closureData.capturingScopes[node]; |
128 if (scopeData == null) return; | 128 if (scopeData == null) return; |
129 HInstruction box; | 129 HInstruction box; |
130 // The scope has captured variables. | 130 // The scope has captured variables. |
131 if (element != null && element.isGenerativeConstructorBody) { | 131 if (element != null && element.isGenerativeConstructorBody) { |
132 // The box is passed as a parameter to a generative | 132 // The box is passed as a parameter to a generative |
133 // constructor body. | 133 // constructor body. |
134 JavaScriptBackend backend = compiler.backend; | 134 JavaScriptBackend backend = _compiler.backend; |
135 box = builder.addParameter(scopeData.boxElement, backend.nonNullType); | 135 box = builder.addParameter(scopeData.boxElement, backend.nonNullType); |
136 } else { | 136 } else { |
137 box = createBox(); | 137 box = createBox(); |
138 } | 138 } |
139 // Add the box to the known locals. | 139 // Add the box to the known locals. |
140 directLocals[scopeData.boxElement] = box; | 140 directLocals[scopeData.boxElement] = box; |
141 // Make sure that accesses to the boxed locals go into the box. We also | 141 // Make sure that accesses to the boxed locals go into the box. We also |
142 // need to make sure that parameters are copied into the box if necessary. | 142 // need to make sure that parameters are copied into the box if necessary. |
143 scopeData.forEachCapturedVariable( | 143 scopeData.forEachCapturedVariable( |
144 (LocalVariableElement from, BoxFieldElement to) { | 144 (LocalVariableElement from, BoxFieldElement to) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 updateLocal(boxedVariable, oldValue); | 178 updateLocal(boxedVariable, oldValue); |
179 } | 179 } |
180 updateLocal(boxElement, newBox); | 180 updateLocal(boxElement, newBox); |
181 } | 181 } |
182 | 182 |
183 /// Documentation wanted -- johnniwinther | 183 /// Documentation wanted -- johnniwinther |
184 /// | 184 /// |
185 /// Invariant: [function] must be an implementation element. | 185 /// Invariant: [function] must be an implementation element. |
186 void startFunction(AstElement element, ast.Node node) { | 186 void startFunction(AstElement element, ast.Node node) { |
187 assert(invariant(element, element.isImplementation)); | 187 assert(invariant(element, element.isImplementation)); |
188 closureData = compiler.closureToClassMapper | 188 closureData = _compiler.closureToClassMapper |
189 .computeClosureToClassMapping(element.resolvedAst); | 189 .computeClosureToClassMapping(element.resolvedAst); |
190 | 190 |
191 if (element is FunctionElement) { | 191 if (element is FunctionElement) { |
192 FunctionElement functionElement = element; | 192 FunctionElement functionElement = element; |
193 FunctionSignature params = functionElement.functionSignature; | 193 FunctionSignature params = functionElement.functionSignature; |
194 ClosureScope scopeData = closureData.capturingScopes[node]; | 194 ClosureScope scopeData = closureData.capturingScopes[node]; |
195 params.orderedForEachParameter((ParameterElement parameterElement) { | 195 params.orderedForEachParameter((ParameterElement parameterElement) { |
196 if (element.isGenerativeConstructorBody) { | 196 if (element.isGenerativeConstructorBody) { |
197 if (scopeData != null && | 197 if (scopeData != null && |
198 scopeData.isCapturedVariable(parameterElement)) { | 198 scopeData.isCapturedVariable(parameterElement)) { |
199 // The parameter will be a field in the box passed as the | 199 // The parameter will be a field in the box passed as the |
200 // last parameter. So no need to have it. | 200 // last parameter. So no need to have it. |
201 return; | 201 return; |
202 } | 202 } |
203 } | 203 } |
204 HInstruction parameter = builder.addParameter(parameterElement, | 204 HInstruction parameter = builder.addParameter( |
205 TypeMaskFactory.inferredTypeForElement(parameterElement, compiler)); | 205 parameterElement, |
| 206 TypeMaskFactory.inferredTypeForElement( |
| 207 parameterElement, _compiler)); |
206 builder.parameters[parameterElement] = parameter; | 208 builder.parameters[parameterElement] = parameter; |
207 directLocals[parameterElement] = parameter; | 209 directLocals[parameterElement] = parameter; |
208 }); | 210 }); |
209 } | 211 } |
210 | 212 |
211 enterScope(node, element); | 213 enterScope(node, element); |
212 | 214 |
213 // If the freeVariableMapping is not empty, then this function was a | 215 // If the freeVariableMapping is not empty, then this function was a |
214 // nested closure that captures variables. Redirect the captured | 216 // nested closure that captures variables. Redirect the captured |
215 // variables to fields in the closure. | 217 // variables to fields in the closure. |
216 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 218 closureData.forEachFreeVariable((Local from, CapturedVariable to) { |
217 redirectElement(from, to); | 219 redirectElement(from, to); |
218 }); | 220 }); |
219 JavaScriptBackend backend = compiler.backend; | 221 JavaScriptBackend backend = _compiler.backend; |
220 if (closureData.isClosure) { | 222 if (closureData.isClosure) { |
221 // Inside closure redirect references to itself to [:this:]. | 223 // Inside closure redirect references to itself to [:this:]. |
222 HThis thisInstruction = | 224 HThis thisInstruction = |
223 new HThis(closureData.thisLocal, backend.nonNullType); | 225 new HThis(closureData.thisLocal, backend.nonNullType); |
224 builder.graph.thisInstruction = thisInstruction; | 226 builder.graph.thisInstruction = thisInstruction; |
225 builder.graph.entry.addAtEntry(thisInstruction); | 227 builder.graph.entry.addAtEntry(thisInstruction); |
226 updateLocal(closureData.closureElement, thisInstruction); | 228 updateLocal(closureData.closureElement, thisInstruction); |
227 } else if (element.isInstanceMember) { | 229 } else if (element.isInstanceMember) { |
228 // Once closures have been mapped to classes their instance members might | 230 // Once closures have been mapped to classes their instance members might |
229 // not have any thisElement if the closure was created inside a static | 231 // not have any thisElement if the closure was created inside a static |
(...skipping 28 matching lines...) Expand all Loading... |
258 } | 260 } |
259 if (isInterceptorClass) { | 261 if (isInterceptorClass) { |
260 // Only use the extra parameter in intercepted classes. | 262 // Only use the extra parameter in intercepted classes. |
261 directLocals[closureData.thisLocal] = value; | 263 directLocals[closureData.thisLocal] = value; |
262 } | 264 } |
263 } else if (isNativeUpgradeFactory) { | 265 } else if (isNativeUpgradeFactory) { |
264 SyntheticLocal parameter = | 266 SyntheticLocal parameter = |
265 new SyntheticLocal('receiver', executableContext); | 267 new SyntheticLocal('receiver', executableContext); |
266 // Unlike `this`, receiver is nullable since direct calls to generative | 268 // Unlike `this`, receiver is nullable since direct calls to generative |
267 // constructor call the constructor with `null`. | 269 // constructor call the constructor with `null`. |
268 ClassWorld classWorld = compiler.world; | 270 ClassWorld classWorld = _compiler.world; |
269 HParameterValue value = | 271 HParameterValue value = |
270 new HParameterValue(parameter, new TypeMask.exact(cls, classWorld)); | 272 new HParameterValue(parameter, new TypeMask.exact(cls, classWorld)); |
271 builder.graph.explicitReceiverParameter = value; | 273 builder.graph.explicitReceiverParameter = value; |
272 builder.graph.entry.addAtEntry(value); | 274 builder.graph.entry.addAtEntry(value); |
273 } | 275 } |
274 } | 276 } |
275 | 277 |
276 /// Returns true if the local can be accessed directly. Boxed variables or | 278 /// Returns true if the local can be accessed directly. Boxed variables or |
277 /// captured variables that are stored in the closure-field return [:false:]. | 279 /// captured variables that are stored in the closure-field return [:false:]. |
278 bool isAccessedDirectly(Local local) { | 280 bool isAccessedDirectly(Local local) { |
(...skipping 20 matching lines...) Expand all Loading... |
299 return closureData.variablesUsedInTryOrGenerator.contains(local); | 301 return closureData.variablesUsedInTryOrGenerator.contains(local); |
300 } | 302 } |
301 | 303 |
302 /// Returns an [HInstruction] for the given element. If the element is | 304 /// Returns an [HInstruction] for the given element. If the element is |
303 /// boxed or stored in a closure then the method generates code to retrieve | 305 /// boxed or stored in a closure then the method generates code to retrieve |
304 /// the value. | 306 /// the value. |
305 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { | 307 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
306 if (isAccessedDirectly(local)) { | 308 if (isAccessedDirectly(local)) { |
307 if (directLocals[local] == null) { | 309 if (directLocals[local] == null) { |
308 if (local is TypeVariableElement) { | 310 if (local is TypeVariableElement) { |
309 compiler.reporter.internalError(compiler.currentElement, | 311 _compiler.reporter.internalError(_compiler.currentElement, |
310 "Runtime type information not available for $local."); | 312 "Runtime type information not available for $local."); |
311 } else { | 313 } else { |
312 compiler.reporter.internalError( | 314 _compiler.reporter.internalError( |
313 local, "Cannot find value $local in ${directLocals.keys}."); | 315 local, "Cannot find value $local in ${directLocals.keys}."); |
314 } | 316 } |
315 } | 317 } |
316 HInstruction value = directLocals[local]; | 318 HInstruction value = directLocals[local]; |
317 if (sourceInformation != null) { | 319 if (sourceInformation != null) { |
318 value = new HRef(value, sourceInformation); | 320 value = new HRef(value, sourceInformation); |
319 builder.add(value); | 321 builder.add(value); |
320 } | 322 } |
321 return value; | 323 return value; |
322 } else if (isStoredInClosureField(local)) { | 324 } else if (isStoredInClosureField(local)) { |
323 ClosureFieldElement redirect = redirectionMapping[local]; | 325 ClosureFieldElement redirect = redirectionMapping[local]; |
324 HInstruction receiver = readLocal(closureData.closureElement); | 326 HInstruction receiver = readLocal(closureData.closureElement); |
325 TypeMask type = local is BoxLocal | 327 TypeMask type = local is BoxLocal |
326 ? (compiler.backend as JavaScriptBackend).nonNullType | 328 ? (_compiler.backend as JavaScriptBackend).nonNullType |
327 : getTypeOfCapturedVariable(redirect); | 329 : getTypeOfCapturedVariable(redirect); |
328 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); | 330 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); |
329 builder.add(fieldGet); | 331 builder.add(fieldGet); |
330 return fieldGet..sourceInformation = sourceInformation; | 332 return fieldGet..sourceInformation = sourceInformation; |
331 } else if (isBoxed(local)) { | 333 } else if (isBoxed(local)) { |
332 BoxFieldElement redirect = redirectionMapping[local]; | 334 BoxFieldElement redirect = redirectionMapping[local]; |
333 // In the function that declares the captured variable the box is | 335 // In the function that declares the captured variable the box is |
334 // accessed as direct local. Inside the nested closure the box is | 336 // accessed as direct local. Inside the nested closure the box is |
335 // accessed through a closure-field. | 337 // accessed through a closure-field. |
336 // Calling [readLocal] makes sure we generate the correct code to get | 338 // Calling [readLocal] makes sure we generate the correct code to get |
337 // the box. | 339 // the box. |
338 HInstruction box = readLocal(redirect.box); | 340 HInstruction box = readLocal(redirect.box); |
339 HInstruction lookup = | 341 HInstruction lookup = |
340 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); | 342 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); |
341 builder.add(lookup); | 343 builder.add(lookup); |
342 return lookup..sourceInformation = sourceInformation; | 344 return lookup..sourceInformation = sourceInformation; |
343 } else { | 345 } else { |
344 assert(isUsedInTryOrGenerator(local)); | 346 assert(isUsedInTryOrGenerator(local)); |
345 HLocalValue localValue = getLocal(local); | 347 HLocalValue localValue = getLocal(local); |
346 HInstruction instruction = new HLocalGet( | 348 HInstruction instruction = new HLocalGet( |
347 local, | 349 local, |
348 localValue, | 350 localValue, |
349 (compiler.backend as JavaScriptBackend).dynamicType, | 351 (_compiler.backend as JavaScriptBackend).dynamicType, |
350 sourceInformation); | 352 sourceInformation); |
351 builder.add(instruction); | 353 builder.add(instruction); |
352 return instruction; | 354 return instruction; |
353 } | 355 } |
354 } | 356 } |
355 | 357 |
356 HInstruction readThis() { | 358 HInstruction readThis() { |
357 HInstruction res = readLocal(closureData.thisLocal); | 359 HInstruction res = readLocal(closureData.thisLocal); |
358 if (res.instructionType == null) { | 360 if (res.instructionType == null) { |
359 res.instructionType = getTypeOfThis(); | 361 res.instructionType = getTypeOfThis(); |
360 } | 362 } |
361 return res; | 363 return res; |
362 } | 364 } |
363 | 365 |
364 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { | 366 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { |
365 // If the element is a parameter, we already have a | 367 // If the element is a parameter, we already have a |
366 // HParameterValue for it. We cannot create another one because | 368 // HParameterValue for it. We cannot create another one because |
367 // it could then have another name than the real parameter. And | 369 // it could then have another name than the real parameter. And |
368 // the other one would not know it is just a copy of the real | 370 // the other one would not know it is just a copy of the real |
369 // parameter. | 371 // parameter. |
370 if (local is ParameterElement) { | 372 if (local is ParameterElement) { |
371 assert(invariant(local, builder.parameters.containsKey(local), | 373 assert(invariant(local, builder.parameters.containsKey(local), |
372 message: "No local value for parameter $local in " | 374 message: "No local value for parameter $local in " |
373 "${builder.parameters}.")); | 375 "${builder.parameters}.")); |
374 return builder.parameters[local]; | 376 return builder.parameters[local]; |
375 } | 377 } |
376 | 378 |
377 return activationVariables.putIfAbsent(local, () { | 379 return activationVariables.putIfAbsent(local, () { |
378 JavaScriptBackend backend = compiler.backend; | 380 JavaScriptBackend backend = _compiler.backend; |
379 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) | 381 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) |
380 ..sourceInformation = sourceInformation; | 382 ..sourceInformation = sourceInformation; |
381 builder.graph.entry.addAtExit(localValue); | 383 builder.graph.entry.addAtExit(localValue); |
382 return localValue; | 384 return localValue; |
383 }); | 385 }); |
384 } | 386 } |
385 | 387 |
386 Local getTypeVariableAsLocal(TypeVariableType type) { | 388 Local getTypeVariableAsLocal(TypeVariableType type) { |
387 return typeVariableLocals.putIfAbsent(type, () { | 389 return typeVariableLocals.putIfAbsent(type, () { |
388 return new TypeVariableLocal(type, executableContext); | 390 return new TypeVariableLocal(type, executableContext); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
473 } | 475 } |
474 } | 476 } |
475 | 477 |
476 /// Create phis at the loop entry for local variables (ready for the values | 478 /// Create phis at the loop entry for local variables (ready for the values |
477 /// from the back edge). Populate the phis with the current values. | 479 /// from the back edge). Populate the phis with the current values. |
478 void beginLoopHeader(HBasicBlock loopEntry) { | 480 void beginLoopHeader(HBasicBlock loopEntry) { |
479 // Create a copy because we modify the map while iterating over it. | 481 // Create a copy because we modify the map while iterating over it. |
480 Map<Local, HInstruction> savedDirectLocals = | 482 Map<Local, HInstruction> savedDirectLocals = |
481 new Map<Local, HInstruction>.from(directLocals); | 483 new Map<Local, HInstruction>.from(directLocals); |
482 | 484 |
483 JavaScriptBackend backend = compiler.backend; | 485 JavaScriptBackend backend = _compiler.backend; |
484 // Create phis for all elements in the definitions environment. | 486 // Create phis for all elements in the definitions environment. |
485 savedDirectLocals.forEach((Local local, HInstruction instruction) { | 487 savedDirectLocals.forEach((Local local, HInstruction instruction) { |
486 if (isAccessedDirectly(local)) { | 488 if (isAccessedDirectly(local)) { |
487 // We know 'this' cannot be modified. | 489 // We know 'this' cannot be modified. |
488 if (local != closureData.thisLocal) { | 490 if (local != closureData.thisLocal) { |
489 HPhi phi = | 491 HPhi phi = |
490 new HPhi.singleInput(local, instruction, backend.dynamicType); | 492 new HPhi.singleInput(local, instruction, backend.dynamicType); |
491 loopEntry.addPhi(phi); | 493 loopEntry.addPhi(phi); |
492 directLocals[local] = phi; | 494 directLocals[local] = phi; |
493 } else { | 495 } else { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 /// there is a conflict. | 539 /// there is a conflict. |
538 /// If a phi node is necessary, it will use this handler's instruction as the | 540 /// If a phi node is necessary, it will use this handler's instruction as the |
539 /// first input, and the otherLocals instruction as the second. | 541 /// first input, and the otherLocals instruction as the second. |
540 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 542 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
541 // If an element is in one map but not the other we can safely | 543 // If an element is in one map but not the other we can safely |
542 // ignore it. It means that a variable was declared in the | 544 // ignore it. It means that a variable was declared in the |
543 // block. Since variable declarations are scoped the declared | 545 // block. Since variable declarations are scoped the declared |
544 // variable cannot be alive outside the block. Note: this is only | 546 // variable cannot be alive outside the block. Note: this is only |
545 // true for nodes where we do joins. | 547 // true for nodes where we do joins. |
546 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 548 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
547 JavaScriptBackend backend = compiler.backend; | 549 JavaScriptBackend backend = _compiler.backend; |
548 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { | 550 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { |
549 // We know 'this' cannot be modified. | 551 // We know 'this' cannot be modified. |
550 if (local == closureData.thisLocal) { | 552 if (local == closureData.thisLocal) { |
551 assert(directLocals[local] == instruction); | 553 assert(directLocals[local] == instruction); |
552 joinedLocals[local] = instruction; | 554 joinedLocals[local] = instruction; |
553 } else { | 555 } else { |
554 HInstruction mine = directLocals[local]; | 556 HInstruction mine = directLocals[local]; |
555 if (mine == null) return; | 557 if (mine == null) return; |
556 if (identical(instruction, mine)) { | 558 if (identical(instruction, mine)) { |
557 joinedLocals[local] = instruction; | 559 joinedLocals[local] = instruction; |
(...skipping 12 matching lines...) Expand all Loading... |
570 /// localsHandlers into a new one using phis. The new localsHandler is | 572 /// localsHandlers into a new one using phis. The new localsHandler is |
571 /// returned. Unless it is also in the list, the current localsHandler is not | 573 /// returned. Unless it is also in the list, the current localsHandler is not |
572 /// used for its values, only for its declared variables. This is a way to | 574 /// used for its values, only for its declared variables. This is a way to |
573 /// exclude local values from the result when they are no longer in scope. | 575 /// exclude local values from the result when they are no longer in scope. |
574 LocalsHandler mergeMultiple( | 576 LocalsHandler mergeMultiple( |
575 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { | 577 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { |
576 assert(localsHandlers.length > 0); | 578 assert(localsHandlers.length > 0); |
577 if (localsHandlers.length == 1) return localsHandlers[0]; | 579 if (localsHandlers.length == 1) return localsHandlers[0]; |
578 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 580 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
579 HInstruction thisValue = null; | 581 HInstruction thisValue = null; |
580 JavaScriptBackend backend = compiler.backend; | 582 JavaScriptBackend backend = _compiler.backend; |
581 directLocals.forEach((Local local, HInstruction instruction) { | 583 directLocals.forEach((Local local, HInstruction instruction) { |
582 if (local != closureData.thisLocal) { | 584 if (local != closureData.thisLocal) { |
583 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); | 585 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); |
584 joinedLocals[local] = phi; | 586 joinedLocals[local] = phi; |
585 joinBlock.addPhi(phi); | 587 joinBlock.addPhi(phi); |
586 } else { | 588 } else { |
587 // We know that "this" never changes, if it's there. | 589 // We know that "this" never changes, if it's there. |
588 // Save it for later. While merging, there is no phi for "this", | 590 // Save it for later. While merging, there is no phi for "this", |
589 // so we don't have to special case it in the merge loop. | 591 // so we don't have to special case it in the merge loop. |
590 thisValue = instruction; | 592 thisValue = instruction; |
(...skipping 25 matching lines...) Expand all Loading... |
616 return this; | 618 return this; |
617 } | 619 } |
618 | 620 |
619 TypeMask cachedTypeOfThis; | 621 TypeMask cachedTypeOfThis; |
620 | 622 |
621 TypeMask getTypeOfThis() { | 623 TypeMask getTypeOfThis() { |
622 TypeMask result = cachedTypeOfThis; | 624 TypeMask result = cachedTypeOfThis; |
623 if (result == null) { | 625 if (result == null) { |
624 ThisLocal local = closureData.thisLocal; | 626 ThisLocal local = closureData.thisLocal; |
625 ClassElement cls = local.enclosingClass; | 627 ClassElement cls = local.enclosingClass; |
626 ClassWorld classWorld = compiler.world; | 628 ClassWorld classWorld = _compiler.world; |
627 if (classWorld.isUsedAsMixin(cls)) { | 629 if (classWorld.isUsedAsMixin(cls)) { |
628 // If the enclosing class is used as a mixin, [:this:] can be | 630 // If the enclosing class is used as a mixin, [:this:] can be |
629 // of the class that mixins the enclosing class. These two | 631 // of the class that mixins the enclosing class. These two |
630 // classes do not have a subclass relationship, so, for | 632 // classes do not have a subclass relationship, so, for |
631 // simplicity, we mark the type as an interface type. | 633 // simplicity, we mark the type as an interface type. |
632 result = new TypeMask.nonNullSubtype(cls.declaration, compiler.world); | 634 result = new TypeMask.nonNullSubtype(cls.declaration, _compiler.world); |
633 } else { | 635 } else { |
634 result = new TypeMask.nonNullSubclass(cls.declaration, compiler.world); | 636 result = new TypeMask.nonNullSubclass(cls.declaration, _compiler.world); |
635 } | 637 } |
636 cachedTypeOfThis = result; | 638 cachedTypeOfThis = result; |
637 } | 639 } |
638 return result; | 640 return result; |
639 } | 641 } |
640 | 642 |
641 Map<Element, TypeMask> cachedTypesOfCapturedVariables = | 643 Map<Element, TypeMask> cachedTypesOfCapturedVariables = |
642 new Map<Element, TypeMask>(); | 644 new Map<Element, TypeMask>(); |
643 | 645 |
644 TypeMask getTypeOfCapturedVariable(Element element) { | 646 TypeMask getTypeOfCapturedVariable(Element element) { |
645 assert(element.isField); | 647 assert(element.isField); |
646 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { | 648 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { |
647 return TypeMaskFactory.inferredTypeForElement(element, compiler); | 649 return TypeMaskFactory.inferredTypeForElement(element, _compiler); |
648 }); | 650 }); |
649 } | 651 } |
650 | 652 |
651 /// Variables stored in the current activation. These variables are | 653 /// Variables stored in the current activation. These variables are |
652 /// being updated in try/catch blocks, and should be | 654 /// being updated in try/catch blocks, and should be |
653 /// accessed indirectly through [HLocalGet] and [HLocalSet]. | 655 /// accessed indirectly through [HLocalGet] and [HLocalSet]. |
654 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; | 656 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; |
655 } | 657 } |
OLD | NEW |