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(parameterElement, |
205 TypeMaskFactory.inferredTypeForElement(parameterElement, compiler)); | 205 TypeMaskFactory.inferredTypeForElement(parameterElement, _compiler))
; |
206 builder.parameters[parameterElement] = parameter; | 206 builder.parameters[parameterElement] = parameter; |
207 directLocals[parameterElement] = parameter; | 207 directLocals[parameterElement] = parameter; |
208 }); | 208 }); |
209 } | 209 } |
210 | 210 |
211 enterScope(node, element); | 211 enterScope(node, element); |
212 | 212 |
213 // If the freeVariableMapping is not empty, then this function was a | 213 // If the freeVariableMapping is not empty, then this function was a |
214 // nested closure that captures variables. Redirect the captured | 214 // nested closure that captures variables. Redirect the captured |
215 // variables to fields in the closure. | 215 // variables to fields in the closure. |
216 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 216 closureData.forEachFreeVariable((Local from, CapturedVariable to) { |
217 redirectElement(from, to); | 217 redirectElement(from, to); |
218 }); | 218 }); |
219 JavaScriptBackend backend = compiler.backend; | 219 JavaScriptBackend backend = _compiler.backend; |
220 if (closureData.isClosure) { | 220 if (closureData.isClosure) { |
221 // Inside closure redirect references to itself to [:this:]. | 221 // Inside closure redirect references to itself to [:this:]. |
222 HThis thisInstruction = | 222 HThis thisInstruction = |
223 new HThis(closureData.thisLocal, backend.nonNullType); | 223 new HThis(closureData.thisLocal, backend.nonNullType); |
224 builder.graph.thisInstruction = thisInstruction; | 224 builder.graph.thisInstruction = thisInstruction; |
225 builder.graph.entry.addAtEntry(thisInstruction); | 225 builder.graph.entry.addAtEntry(thisInstruction); |
226 updateLocal(closureData.closureElement, thisInstruction); | 226 updateLocal(closureData.closureElement, thisInstruction); |
227 } else if (element.isInstanceMember) { | 227 } else if (element.isInstanceMember) { |
228 // Once closures have been mapped to classes their instance members might | 228 // Once closures have been mapped to classes their instance members might |
229 // not have any thisElement if the closure was created inside a static | 229 // not have any thisElement if the closure was created inside a static |
(...skipping 28 matching lines...) Expand all Loading... |
258 } | 258 } |
259 if (isInterceptorClass) { | 259 if (isInterceptorClass) { |
260 // Only use the extra parameter in intercepted classes. | 260 // Only use the extra parameter in intercepted classes. |
261 directLocals[closureData.thisLocal] = value; | 261 directLocals[closureData.thisLocal] = value; |
262 } | 262 } |
263 } else if (isNativeUpgradeFactory) { | 263 } else if (isNativeUpgradeFactory) { |
264 SyntheticLocal parameter = | 264 SyntheticLocal parameter = |
265 new SyntheticLocal('receiver', executableContext); | 265 new SyntheticLocal('receiver', executableContext); |
266 // Unlike `this`, receiver is nullable since direct calls to generative | 266 // Unlike `this`, receiver is nullable since direct calls to generative |
267 // constructor call the constructor with `null`. | 267 // constructor call the constructor with `null`. |
268 ClassWorld classWorld = compiler.world; | 268 ClassWorld classWorld = _compiler.world; |
269 HParameterValue value = | 269 HParameterValue value = |
270 new HParameterValue(parameter, new TypeMask.exact(cls, classWorld)); | 270 new HParameterValue(parameter, new TypeMask.exact(cls, classWorld)); |
271 builder.graph.explicitReceiverParameter = value; | 271 builder.graph.explicitReceiverParameter = value; |
272 builder.graph.entry.addAtEntry(value); | 272 builder.graph.entry.addAtEntry(value); |
273 } | 273 } |
274 } | 274 } |
275 | 275 |
276 /// Returns true if the local can be accessed directly. Boxed variables or | 276 /// Returns true if the local can be accessed directly. Boxed variables or |
277 /// captured variables that are stored in the closure-field return [:false:]. | 277 /// captured variables that are stored in the closure-field return [:false:]. |
278 bool isAccessedDirectly(Local local) { | 278 bool isAccessedDirectly(Local local) { |
(...skipping 20 matching lines...) Expand all Loading... |
299 return closureData.variablesUsedInTryOrGenerator.contains(local); | 299 return closureData.variablesUsedInTryOrGenerator.contains(local); |
300 } | 300 } |
301 | 301 |
302 /// Returns an [HInstruction] for the given element. If the element is | 302 /// 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 | 303 /// boxed or stored in a closure then the method generates code to retrieve |
304 /// the value. | 304 /// the value. |
305 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { | 305 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
306 if (isAccessedDirectly(local)) { | 306 if (isAccessedDirectly(local)) { |
307 if (directLocals[local] == null) { | 307 if (directLocals[local] == null) { |
308 if (local is TypeVariableElement) { | 308 if (local is TypeVariableElement) { |
309 compiler.reporter.internalError(compiler.currentElement, | 309 _compiler.reporter.internalError(_compiler.currentElement, |
310 "Runtime type information not available for $local."); | 310 "Runtime type information not available for $local."); |
311 } else { | 311 } else { |
312 compiler.reporter.internalError( | 312 _compiler.reporter.internalError( |
313 local, "Cannot find value $local in ${directLocals.keys}."); | 313 local, "Cannot find value $local in ${directLocals.keys}."); |
314 } | 314 } |
315 } | 315 } |
316 HInstruction value = directLocals[local]; | 316 HInstruction value = directLocals[local]; |
317 if (sourceInformation != null) { | 317 if (sourceInformation != null) { |
318 value = new HRef(value, sourceInformation); | 318 value = new HRef(value, sourceInformation); |
319 builder.add(value); | 319 builder.add(value); |
320 } | 320 } |
321 return value; | 321 return value; |
322 } else if (isStoredInClosureField(local)) { | 322 } else if (isStoredInClosureField(local)) { |
323 ClosureFieldElement redirect = redirectionMapping[local]; | 323 ClosureFieldElement redirect = redirectionMapping[local]; |
324 HInstruction receiver = readLocal(closureData.closureElement); | 324 HInstruction receiver = readLocal(closureData.closureElement); |
325 TypeMask type = local is BoxLocal | 325 TypeMask type = local is BoxLocal |
326 ? (compiler.backend as JavaScriptBackend).nonNullType | 326 ? (_compiler.backend as JavaScriptBackend).nonNullType |
327 : getTypeOfCapturedVariable(redirect); | 327 : getTypeOfCapturedVariable(redirect); |
328 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); | 328 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); |
329 builder.add(fieldGet); | 329 builder.add(fieldGet); |
330 return fieldGet..sourceInformation = sourceInformation; | 330 return fieldGet..sourceInformation = sourceInformation; |
331 } else if (isBoxed(local)) { | 331 } else if (isBoxed(local)) { |
332 BoxFieldElement redirect = redirectionMapping[local]; | 332 BoxFieldElement redirect = redirectionMapping[local]; |
333 // In the function that declares the captured variable the box is | 333 // In the function that declares the captured variable the box is |
334 // accessed as direct local. Inside the nested closure the box is | 334 // accessed as direct local. Inside the nested closure the box is |
335 // accessed through a closure-field. | 335 // accessed through a closure-field. |
336 // Calling [readLocal] makes sure we generate the correct code to get | 336 // Calling [readLocal] makes sure we generate the correct code to get |
337 // the box. | 337 // the box. |
338 HInstruction box = readLocal(redirect.box); | 338 HInstruction box = readLocal(redirect.box); |
339 HInstruction lookup = | 339 HInstruction lookup = |
340 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); | 340 new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect)); |
341 builder.add(lookup); | 341 builder.add(lookup); |
342 return lookup..sourceInformation = sourceInformation; | 342 return lookup..sourceInformation = sourceInformation; |
343 } else { | 343 } else { |
344 assert(isUsedInTryOrGenerator(local)); | 344 assert(isUsedInTryOrGenerator(local)); |
345 HLocalValue localValue = getLocal(local); | 345 HLocalValue localValue = getLocal(local); |
346 HInstruction instruction = new HLocalGet( | 346 HInstruction instruction = new HLocalGet( |
347 local, | 347 local, |
348 localValue, | 348 localValue, |
349 (compiler.backend as JavaScriptBackend).dynamicType, | 349 (_compiler.backend as JavaScriptBackend).dynamicType, |
350 sourceInformation); | 350 sourceInformation); |
351 builder.add(instruction); | 351 builder.add(instruction); |
352 return instruction; | 352 return instruction; |
353 } | 353 } |
354 } | 354 } |
355 | 355 |
356 HInstruction readThis() { | 356 HInstruction readThis() { |
357 HInstruction res = readLocal(closureData.thisLocal); | 357 HInstruction res = readLocal(closureData.thisLocal); |
358 if (res.instructionType == null) { | 358 if (res.instructionType == null) { |
359 res.instructionType = getTypeOfThis(); | 359 res.instructionType = getTypeOfThis(); |
360 } | 360 } |
361 return res; | 361 return res; |
362 } | 362 } |
363 | 363 |
364 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { | 364 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { |
365 // If the element is a parameter, we already have a | 365 // If the element is a parameter, we already have a |
366 // HParameterValue for it. We cannot create another one because | 366 // HParameterValue for it. We cannot create another one because |
367 // it could then have another name than the real parameter. And | 367 // 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 | 368 // the other one would not know it is just a copy of the real |
369 // parameter. | 369 // parameter. |
370 if (local is ParameterElement) { | 370 if (local is ParameterElement) { |
371 assert(invariant(local, builder.parameters.containsKey(local), | 371 assert(invariant(local, builder.parameters.containsKey(local), |
372 message: "No local value for parameter $local in " | 372 message: "No local value for parameter $local in " |
373 "${builder.parameters}.")); | 373 "${builder.parameters}.")); |
374 return builder.parameters[local]; | 374 return builder.parameters[local]; |
375 } | 375 } |
376 | 376 |
377 return activationVariables.putIfAbsent(local, () { | 377 return activationVariables.putIfAbsent(local, () { |
378 JavaScriptBackend backend = compiler.backend; | 378 JavaScriptBackend backend = _compiler.backend; |
379 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) | 379 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) |
380 ..sourceInformation = sourceInformation; | 380 ..sourceInformation = sourceInformation; |
381 builder.graph.entry.addAtExit(localValue); | 381 builder.graph.entry.addAtExit(localValue); |
382 return localValue; | 382 return localValue; |
383 }); | 383 }); |
384 } | 384 } |
385 | 385 |
386 Local getTypeVariableAsLocal(TypeVariableType type) { | 386 Local getTypeVariableAsLocal(TypeVariableType type) { |
387 return typeVariableLocals.putIfAbsent(type, () { | 387 return typeVariableLocals.putIfAbsent(type, () { |
388 return new TypeVariableLocal(type, executableContext); | 388 return new TypeVariableLocal(type, executableContext); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
473 } | 473 } |
474 } | 474 } |
475 | 475 |
476 /// Create phis at the loop entry for local variables (ready for the values | 476 /// 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. | 477 /// from the back edge). Populate the phis with the current values. |
478 void beginLoopHeader(HBasicBlock loopEntry) { | 478 void beginLoopHeader(HBasicBlock loopEntry) { |
479 // Create a copy because we modify the map while iterating over it. | 479 // Create a copy because we modify the map while iterating over it. |
480 Map<Local, HInstruction> savedDirectLocals = | 480 Map<Local, HInstruction> savedDirectLocals = |
481 new Map<Local, HInstruction>.from(directLocals); | 481 new Map<Local, HInstruction>.from(directLocals); |
482 | 482 |
483 JavaScriptBackend backend = compiler.backend; | 483 JavaScriptBackend backend = _compiler.backend; |
484 // Create phis for all elements in the definitions environment. | 484 // Create phis for all elements in the definitions environment. |
485 savedDirectLocals.forEach((Local local, HInstruction instruction) { | 485 savedDirectLocals.forEach((Local local, HInstruction instruction) { |
486 if (isAccessedDirectly(local)) { | 486 if (isAccessedDirectly(local)) { |
487 // We know 'this' cannot be modified. | 487 // We know 'this' cannot be modified. |
488 if (local != closureData.thisLocal) { | 488 if (local != closureData.thisLocal) { |
489 HPhi phi = | 489 HPhi phi = |
490 new HPhi.singleInput(local, instruction, backend.dynamicType); | 490 new HPhi.singleInput(local, instruction, backend.dynamicType); |
491 loopEntry.addPhi(phi); | 491 loopEntry.addPhi(phi); |
492 directLocals[local] = phi; | 492 directLocals[local] = phi; |
493 } else { | 493 } else { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 /// there is a conflict. | 537 /// there is a conflict. |
538 /// If a phi node is necessary, it will use this handler's instruction as the | 538 /// 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. | 539 /// first input, and the otherLocals instruction as the second. |
540 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 540 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
541 // If an element is in one map but not the other we can safely | 541 // 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 | 542 // ignore it. It means that a variable was declared in the |
543 // block. Since variable declarations are scoped the declared | 543 // block. Since variable declarations are scoped the declared |
544 // variable cannot be alive outside the block. Note: this is only | 544 // variable cannot be alive outside the block. Note: this is only |
545 // true for nodes where we do joins. | 545 // true for nodes where we do joins. |
546 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 546 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
547 JavaScriptBackend backend = compiler.backend; | 547 JavaScriptBackend backend = _compiler.backend; |
548 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { | 548 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { |
549 // We know 'this' cannot be modified. | 549 // We know 'this' cannot be modified. |
550 if (local == closureData.thisLocal) { | 550 if (local == closureData.thisLocal) { |
551 assert(directLocals[local] == instruction); | 551 assert(directLocals[local] == instruction); |
552 joinedLocals[local] = instruction; | 552 joinedLocals[local] = instruction; |
553 } else { | 553 } else { |
554 HInstruction mine = directLocals[local]; | 554 HInstruction mine = directLocals[local]; |
555 if (mine == null) return; | 555 if (mine == null) return; |
556 if (identical(instruction, mine)) { | 556 if (identical(instruction, mine)) { |
557 joinedLocals[local] = instruction; | 557 joinedLocals[local] = instruction; |
(...skipping 12 matching lines...) Expand all Loading... |
570 /// localsHandlers into a new one using phis. The new localsHandler is | 570 /// 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 | 571 /// 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 | 572 /// 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. | 573 /// exclude local values from the result when they are no longer in scope. |
574 LocalsHandler mergeMultiple( | 574 LocalsHandler mergeMultiple( |
575 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { | 575 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { |
576 assert(localsHandlers.length > 0); | 576 assert(localsHandlers.length > 0); |
577 if (localsHandlers.length == 1) return localsHandlers[0]; | 577 if (localsHandlers.length == 1) return localsHandlers[0]; |
578 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); | 578 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
579 HInstruction thisValue = null; | 579 HInstruction thisValue = null; |
580 JavaScriptBackend backend = compiler.backend; | 580 JavaScriptBackend backend = _compiler.backend; |
581 directLocals.forEach((Local local, HInstruction instruction) { | 581 directLocals.forEach((Local local, HInstruction instruction) { |
582 if (local != closureData.thisLocal) { | 582 if (local != closureData.thisLocal) { |
583 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); | 583 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); |
584 joinedLocals[local] = phi; | 584 joinedLocals[local] = phi; |
585 joinBlock.addPhi(phi); | 585 joinBlock.addPhi(phi); |
586 } else { | 586 } else { |
587 // We know that "this" never changes, if it's there. | 587 // We know that "this" never changes, if it's there. |
588 // Save it for later. While merging, there is no phi for "this", | 588 // 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. | 589 // so we don't have to special case it in the merge loop. |
590 thisValue = instruction; | 590 thisValue = instruction; |
(...skipping 25 matching lines...) Expand all Loading... |
616 return this; | 616 return this; |
617 } | 617 } |
618 | 618 |
619 TypeMask cachedTypeOfThis; | 619 TypeMask cachedTypeOfThis; |
620 | 620 |
621 TypeMask getTypeOfThis() { | 621 TypeMask getTypeOfThis() { |
622 TypeMask result = cachedTypeOfThis; | 622 TypeMask result = cachedTypeOfThis; |
623 if (result == null) { | 623 if (result == null) { |
624 ThisLocal local = closureData.thisLocal; | 624 ThisLocal local = closureData.thisLocal; |
625 ClassElement cls = local.enclosingClass; | 625 ClassElement cls = local.enclosingClass; |
626 ClassWorld classWorld = compiler.world; | 626 ClassWorld classWorld = _compiler.world; |
627 if (classWorld.isUsedAsMixin(cls)) { | 627 if (classWorld.isUsedAsMixin(cls)) { |
628 // If the enclosing class is used as a mixin, [:this:] can be | 628 // If the enclosing class is used as a mixin, [:this:] can be |
629 // of the class that mixins the enclosing class. These two | 629 // of the class that mixins the enclosing class. These two |
630 // classes do not have a subclass relationship, so, for | 630 // classes do not have a subclass relationship, so, for |
631 // simplicity, we mark the type as an interface type. | 631 // simplicity, we mark the type as an interface type. |
632 result = new TypeMask.nonNullSubtype(cls.declaration, compiler.world); | 632 result = new TypeMask.nonNullSubtype(cls.declaration, _compiler.world); |
633 } else { | 633 } else { |
634 result = new TypeMask.nonNullSubclass(cls.declaration, compiler.world); | 634 result = new TypeMask.nonNullSubclass(cls.declaration, _compiler.world); |
635 } | 635 } |
636 cachedTypeOfThis = result; | 636 cachedTypeOfThis = result; |
637 } | 637 } |
638 return result; | 638 return result; |
639 } | 639 } |
640 | 640 |
641 Map<Element, TypeMask> cachedTypesOfCapturedVariables = | 641 Map<Element, TypeMask> cachedTypesOfCapturedVariables = |
642 new Map<Element, TypeMask>(); | 642 new Map<Element, TypeMask>(); |
643 | 643 |
644 TypeMask getTypeOfCapturedVariable(Element element) { | 644 TypeMask getTypeOfCapturedVariable(Element element) { |
645 assert(element.isField); | 645 assert(element.isField); |
646 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { | 646 return cachedTypesOfCapturedVariables.putIfAbsent(element, () { |
647 return TypeMaskFactory.inferredTypeForElement(element, compiler); | 647 return TypeMaskFactory.inferredTypeForElement(element, _compiler); |
648 }); | 648 }); |
649 } | 649 } |
650 | 650 |
651 /// Variables stored in the current activation. These variables are | 651 /// Variables stored in the current activation. These variables are |
652 /// being updated in try/catch blocks, and should be | 652 /// being updated in try/catch blocks, and should be |
653 /// accessed indirectly through [HLocalGet] and [HLocalSet]. | 653 /// accessed indirectly through [HLocalGet] and [HLocalSet]. |
654 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; | 654 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; |
655 } | 655 } |
OLD | NEW |