| 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 '../elements/elements.dart'; | 7 import '../elements/elements.dart'; |
| 8 import '../elements/entities.dart'; | 8 import '../elements/entities.dart'; |
| 9 import '../elements/types.dart'; | 9 import '../elements/types.dart'; |
| 10 import '../io/source_information.dart'; | 10 import '../io/source_information.dart'; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 /// The values of locals that can be directly accessed (without redirections | 25 /// The values of locals that can be directly accessed (without redirections |
| 26 /// to boxes or closure-fields). | 26 /// to boxes or closure-fields). |
| 27 /// | 27 /// |
| 28 /// [directLocals] is iterated, so it is "insertion ordered" to make the | 28 /// [directLocals] is iterated, so it is "insertion ordered" to make the |
| 29 /// iteration order a function only of insertions and not a function of | 29 /// iteration order a function only of insertions and not a function of |
| 30 /// e.g. Element hash codes. I'd prefer to use a SortedMap but some elements | 30 /// e.g. Element hash codes. I'd prefer to use a SortedMap but some elements |
| 31 /// don't have source locations for [Elements.compareByPosition]. | 31 /// don't have source locations for [Elements.compareByPosition]. |
| 32 Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>(); | 32 Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>(); |
| 33 Map<Local, FieldEntity> redirectionMapping = new Map<Local, FieldEntity>(); | 33 Map<Local, FieldEntity> redirectionMapping = new Map<Local, FieldEntity>(); |
| 34 final GraphBuilder builder; | 34 final GraphBuilder builder; |
| 35 ClosureClassMap closureData; | 35 ClosureRepresentationInfo closureData; |
| 36 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = | 36 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = |
| 37 new Map<TypeVariableType, TypeVariableLocal>(); | 37 new Map<TypeVariableType, TypeVariableLocal>(); |
| 38 final Entity executableContext; | 38 final Entity executableContext; |
| 39 final MemberEntity memberContext; | 39 final MemberEntity memberContext; |
| 40 | 40 |
| 41 /// The class that defines the current type environment or null if no type | 41 /// The class that defines the current type environment or null if no type |
| 42 /// variables are in scope. | 42 /// variables are in scope. |
| 43 final ClassEntity contextClass; | 43 final ClassEntity contextClass; |
| 44 | 44 |
| 45 /// The type of the current instance, if concrete. | 45 /// The type of the current instance, if concrete. |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 HInstruction oldValue = readLocal(boxedVariable); | 189 HInstruction oldValue = readLocal(boxedVariable); |
| 190 updateLocal(boxElement, newBox); | 190 updateLocal(boxElement, newBox); |
| 191 updateLocal(boxedVariable, oldValue); | 191 updateLocal(boxedVariable, oldValue); |
| 192 } | 192 } |
| 193 updateLocal(boxElement, newBox); | 193 updateLocal(boxElement, newBox); |
| 194 } | 194 } |
| 195 | 195 |
| 196 /// Documentation wanted -- johnniwinther | 196 /// Documentation wanted -- johnniwinther |
| 197 /// | 197 /// |
| 198 /// Invariant: [function] must be an implementation element. | 198 /// Invariant: [function] must be an implementation element. |
| 199 void startFunction(MemberEntity element, ClosureClassMap closureData, | 199 void startFunction( |
| 200 ClosureScope scopeData, Map<Local, TypeMask> parameters, | 200 MemberEntity element, |
| 201 ClosureRepresentationInfo closureData, |
| 202 ClosureAnalysisInfo scopeData, |
| 203 Map<Local, TypeMask> parameters, |
| 201 {bool isGenerativeConstructorBody}) { | 204 {bool isGenerativeConstructorBody}) { |
| 202 assert(!(element is MemberElement && !element.isImplementation), | 205 assert(!(element is MemberElement && !element.isImplementation), |
| 203 failedAt(element)); | 206 failedAt(element)); |
| 204 this.closureData = closureData; | 207 this.closureData = closureData; |
| 205 | 208 |
| 206 parameters.forEach((Local local, TypeMask typeMask) { | 209 parameters.forEach((Local local, TypeMask typeMask) { |
| 207 if (isGenerativeConstructorBody) { | 210 if (isGenerativeConstructorBody) { |
| 208 if (scopeData != null && scopeData.isCaptured(local)) { | 211 if (scopeData.isCaptured(local)) { |
| 209 // The parameter will be a field in the box passed as the | 212 // The parameter will be a field in the box passed as the |
| 210 // last parameter. So no need to have it. | 213 // last parameter. So no need to have it. |
| 211 return; | 214 return; |
| 212 } | 215 } |
| 213 } | 216 } |
| 214 HInstruction parameter = builder.addParameter(local, typeMask); | 217 HInstruction parameter = builder.addParameter(local, typeMask); |
| 215 builder.parameters[local] = parameter; | 218 builder.parameters[local] = parameter; |
| 216 directLocals[local] = parameter; | 219 directLocals[local] = parameter; |
| 217 }); | 220 }); |
| 218 | 221 |
| 219 if (scopeData != null) { | 222 enterScope(scopeData, |
| 220 // TODO(efortuna): Remove the above if wrapper (always execute this step) | 223 forGenerativeConstructorBody: isGenerativeConstructorBody); |
| 221 // when the switch away from ClosureClassMap is complete (prior behavior | |
| 222 // in enterScope it was acceptable to pass in a null scopeData, but no | |
| 223 // longer). | |
| 224 enterScope(scopeData, | |
| 225 forGenerativeConstructorBody: isGenerativeConstructorBody); | |
| 226 } | |
| 227 | 224 |
| 228 // If the freeVariableMapping is not empty, then this function was a | 225 // If the freeVariableMapping is not empty, then this function was a |
| 229 // nested closure that captures variables. Redirect the captured | 226 // nested closure that captures variables. Redirect the captured |
| 230 // variables to fields in the closure. | 227 // variables to fields in the closure. |
| 231 closureData.forEachFreeVariable((Local from, FieldEntity to) { | 228 closureData.forEachFreeVariable((Local from, FieldEntity to) { |
| 232 redirectElement(from, to); | 229 redirectElement(from, to); |
| 233 }); | 230 }); |
| 234 if (closureData.isClosure) { | 231 if (closureData.isClosure) { |
| 235 // Inside closure redirect references to itself to [:this:]. | 232 // Inside closure redirect references to itself to [:this:]. |
| 236 HThis thisInstruction = | 233 HThis thisInstruction = |
| 237 new HThis(closureData.thisLocal, commonMasks.nonNullType); | 234 new HThis(closureData.thisLocal, commonMasks.nonNullType); |
| 238 builder.graph.thisInstruction = thisInstruction; | 235 builder.graph.thisInstruction = thisInstruction; |
| 239 builder.graph.entry.addAtEntry(thisInstruction); | 236 builder.graph.entry.addAtEntry(thisInstruction); |
| 240 updateLocal(closureData.closureElement, thisInstruction); | 237 updateLocal(closureData.closureEntity, thisInstruction); |
| 241 } else if (element.isInstanceMember) { | 238 } else if (element.isInstanceMember) { |
| 242 // Once closures have been mapped to classes their instance members might | 239 // Once closures have been mapped to classes their instance members might |
| 243 // not have any thisElement if the closure was created inside a static | 240 // not have any thisElement if the closure was created inside a static |
| 244 // context. | 241 // context. |
| 245 HThis thisInstruction = new HThis(closureData.thisLocal, getTypeOfThis()); | 242 HThis thisInstruction = new HThis(closureData.thisLocal, getTypeOfThis()); |
| 246 builder.graph.thisInstruction = thisInstruction; | 243 builder.graph.thisInstruction = thisInstruction; |
| 247 builder.graph.entry.addAtEntry(thisInstruction); | 244 builder.graph.entry.addAtEntry(thisInstruction); |
| 248 directLocals[closureData.thisLocal] = thisInstruction; | 245 directLocals[closureData.thisLocal] = thisInstruction; |
| 249 } | 246 } |
| 250 | 247 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 builder.lastAddedParameter = value; | 285 builder.lastAddedParameter = value; |
| 289 } | 286 } |
| 290 } | 287 } |
| 291 } | 288 } |
| 292 | 289 |
| 293 /// Returns true if the local can be accessed directly. Boxed variables or | 290 /// Returns true if the local can be accessed directly. Boxed variables or |
| 294 /// captured variables that are stored in the closure-field return [:false:]. | 291 /// captured variables that are stored in the closure-field return [:false:]. |
| 295 bool isAccessedDirectly(Local local) { | 292 bool isAccessedDirectly(Local local) { |
| 296 assert(local != null); | 293 assert(local != null); |
| 297 return !redirectionMapping.containsKey(local) && | 294 return !redirectionMapping.containsKey(local) && |
| 298 !closureData.variablesUsedInTryOrGenerator.contains(local); | 295 !closureData.variableIsUsedInTryOrSync(local); |
| 299 } | 296 } |
| 300 | 297 |
| 301 bool isStoredInClosureField(Local local) { | 298 bool isStoredInClosureField(Local local) { |
| 302 assert(local != null); | 299 assert(local != null); |
| 303 if (isAccessedDirectly(local)) return false; | 300 if (isAccessedDirectly(local)) return false; |
| 304 FieldEntity redirectTarget = redirectionMapping[local]; | 301 FieldEntity redirectTarget = redirectionMapping[local]; |
| 305 if (redirectTarget == null) return false; | 302 if (redirectTarget == null) return false; |
| 306 return redirectTarget is ClosureFieldElement; | 303 return redirectTarget is ClosureFieldElement; |
| 307 } | 304 } |
| 308 | 305 |
| 309 bool isBoxed(Local local) { | 306 bool isBoxed(Local local) { |
| 310 if (isAccessedDirectly(local)) return false; | 307 if (isAccessedDirectly(local)) return false; |
| 311 if (isStoredInClosureField(local)) return false; | 308 if (isStoredInClosureField(local)) return false; |
| 312 return redirectionMapping.containsKey(local); | 309 return redirectionMapping.containsKey(local); |
| 313 } | 310 } |
| 314 | 311 |
| 315 bool isUsedInTryOrGenerator(Local local) { | 312 bool isUsedInTryOrGenerator(Local local) { |
| 316 return closureData.variablesUsedInTryOrGenerator.contains(local); | 313 return closureData.variableIsUsedInTryOrSync(local); |
| 317 } | 314 } |
| 318 | 315 |
| 319 /// Returns an [HInstruction] for the given element. If the element is | 316 /// Returns an [HInstruction] for the given element. If the element is |
| 320 /// boxed or stored in a closure then the method generates code to retrieve | 317 /// boxed or stored in a closure then the method generates code to retrieve |
| 321 /// the value. | 318 /// the value. |
| 322 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { | 319 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
| 323 if (isAccessedDirectly(local)) { | 320 if (isAccessedDirectly(local)) { |
| 324 if (directLocals[local] == null) { | 321 if (directLocals[local] == null) { |
| 325 if (local is TypeVariableLocal) { | 322 if (local is TypeVariableLocal) { |
| 326 throw new SpannableAssertionFailure( | 323 throw new SpannableAssertionFailure( |
| 327 CURRENT_ELEMENT_SPANNABLE, | 324 CURRENT_ELEMENT_SPANNABLE, |
| 328 "Runtime type information not available for $local " | 325 "Runtime type information not available for $local " |
| 329 "in $executableContext."); | 326 "in $executableContext."); |
| 330 } else { | 327 } else { |
| 331 throw new SpannableAssertionFailure( | 328 throw new SpannableAssertionFailure( |
| 332 local, | 329 local, |
| 333 "Cannot find value $local in ${directLocals.keys} for " | 330 "Cannot find value $local in ${directLocals.keys} for " |
| 334 "$executableContext."); | 331 "$executableContext."); |
| 335 } | 332 } |
| 336 } | 333 } |
| 337 HInstruction value = directLocals[local]; | 334 HInstruction value = directLocals[local]; |
| 338 if (sourceInformation != null) { | 335 if (sourceInformation != null) { |
| 339 value = new HRef(value, sourceInformation); | 336 value = new HRef(value, sourceInformation); |
| 340 builder.add(value); | 337 builder.add(value); |
| 341 } | 338 } |
| 342 return value; | 339 return value; |
| 343 } else if (isStoredInClosureField(local)) { | 340 } else if (isStoredInClosureField(local)) { |
| 344 ClosureFieldElement redirect = redirectionMapping[local]; | 341 ClosureFieldElement redirect = redirectionMapping[local]; |
| 345 HInstruction receiver = readLocal(closureData.closureElement); | 342 HInstruction receiver = readLocal(closureData.closureEntity); |
| 346 TypeMask type = local is BoxLocal | 343 TypeMask type = local is BoxLocal |
| 347 ? commonMasks.nonNullType | 344 ? commonMasks.nonNullType |
| 348 : getTypeOfCapturedVariable(redirect); | 345 : getTypeOfCapturedVariable(redirect); |
| 349 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); | 346 HInstruction fieldGet = new HFieldGet(redirect, receiver, type); |
| 350 builder.add(fieldGet); | 347 builder.add(fieldGet); |
| 351 return fieldGet..sourceInformation = sourceInformation; | 348 return fieldGet..sourceInformation = sourceInformation; |
| 352 } else if (isBoxed(local)) { | 349 } else if (isBoxed(local)) { |
| 353 BoxFieldElement redirect = redirectionMapping[local]; | 350 BoxFieldElement redirect = redirectionMapping[local]; |
| 354 // In the function that declares the captured variable the box is | 351 // In the function that declares the captured variable the box is |
| 355 // accessed as direct local. Inside the nested closure the box is | 352 // accessed as direct local. Inside the nested closure the box is |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 final MemberEntity memberContext; | 673 final MemberEntity memberContext; |
| 677 | 674 |
| 678 // Avoid slow Object.hashCode. | 675 // Avoid slow Object.hashCode. |
| 679 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 676 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
| 680 static int _nextHashCode = 0; | 677 static int _nextHashCode = 0; |
| 681 | 678 |
| 682 SyntheticLocal(this.name, this.executableContext, this.memberContext); | 679 SyntheticLocal(this.name, this.executableContext, this.memberContext); |
| 683 | 680 |
| 684 toString() => 'SyntheticLocal($name)'; | 681 toString() => 'SyntheticLocal($name)'; |
| 685 } | 682 } |
| OLD | NEW |