| 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 12 matching lines...) Expand all Loading... |
| 23 /// too. | 23 /// too. |
| 24 class LocalsHandler { | 24 class LocalsHandler { |
| 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, CapturedVariable> redirectionMapping = | 33 Map<Local, FieldEntity> redirectionMapping = new Map<Local, FieldEntity>(); |
| 34 new Map<Local, CapturedVariable>(); | |
| 35 final GraphBuilder builder; | 34 final GraphBuilder builder; |
| 36 ClosureClassMap closureData; | 35 ClosureClassMap closureData; |
| 37 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = | 36 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = |
| 38 new Map<TypeVariableType, TypeVariableLocal>(); | 37 new Map<TypeVariableType, TypeVariableLocal>(); |
| 39 final Entity executableContext; | 38 final Entity executableContext; |
| 40 final MemberEntity memberContext; | 39 final MemberEntity memberContext; |
| 41 | 40 |
| 42 /// 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 |
| 43 /// variables are in scope. | 42 /// variables are in scope. |
| 44 final ClassEntity contextClass; | 43 final ClassEntity contextClass; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 builder = other.builder, | 117 builder = other.builder, |
| 119 closureData = other.closureData, | 118 closureData = other.closureData, |
| 120 _nativeData = other._nativeData, | 119 _nativeData = other._nativeData, |
| 121 _interceptorData = other._interceptorData, | 120 _interceptorData = other._interceptorData, |
| 122 activationVariables = other.activationVariables, | 121 activationVariables = other.activationVariables, |
| 123 cachedTypeOfThis = other.cachedTypeOfThis, | 122 cachedTypeOfThis = other.cachedTypeOfThis, |
| 124 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; | 123 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; |
| 125 | 124 |
| 126 /// Redirects accesses from element [from] to element [to]. The [to] element | 125 /// Redirects accesses from element [from] to element [to]. The [to] element |
| 127 /// must be a boxed variable or a variable that is stored in a closure-field. | 126 /// must be a boxed variable or a variable that is stored in a closure-field. |
| 128 void redirectElement(Local from, CapturedVariable to) { | 127 void redirectElement(Local from, FieldEntity to) { |
| 129 assert(redirectionMapping[from] == null); | 128 assert(redirectionMapping[from] == null); |
| 130 redirectionMapping[from] = to; | 129 redirectionMapping[from] = to; |
| 131 assert(isStoredInClosureField(from) || isBoxed(from)); | 130 assert(isStoredInClosureField(from) || isBoxed(from)); |
| 132 } | 131 } |
| 133 | 132 |
| 134 HInstruction createBox() { | 133 HInstruction createBox() { |
| 135 HInstruction box = new HCreateBox(commonMasks.nonNullType); | 134 HInstruction box = new HCreateBox(commonMasks.nonNullType); |
| 136 builder.add(box); | 135 builder.add(box); |
| 137 return box; | 136 return box; |
| 138 } | 137 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 redirectElement(from, to); | 172 redirectElement(from, to); |
| 174 updateLocal(from, instruction); | 173 updateLocal(from, instruction); |
| 175 } else { | 174 } else { |
| 176 redirectElement(from, to); | 175 redirectElement(from, to); |
| 177 } | 176 } |
| 178 }); | 177 }); |
| 179 } | 178 } |
| 180 | 179 |
| 181 /// Replaces the current box with a new box and copies over the given list | 180 /// Replaces the current box with a new box and copies over the given list |
| 182 /// of elements from the old box into the new box. | 181 /// of elements from the old box into the new box. |
| 183 void updateCaptureBox( | 182 void updateCaptureBox(Local boxElement, List<Local> toBeCopiedElements) { |
| 184 BoxLocal boxElement, List<LocalVariableElement> toBeCopiedElements) { | |
| 185 // Create a new box and copy over the values from the old box into the | 183 // Create a new box and copy over the values from the old box into the |
| 186 // new one. | 184 // new one. |
| 187 HInstruction oldBox = readLocal(boxElement); | 185 HInstruction oldBox = readLocal(boxElement); |
| 188 HInstruction newBox = createBox(); | 186 HInstruction newBox = createBox(); |
| 189 for (LocalVariableElement boxedVariable in toBeCopiedElements) { | 187 for (Local boxedVariable in toBeCopiedElements) { |
| 190 // [readLocal] uses the [boxElement] to find its box. By replacing it | 188 // [readLocal] uses the [boxElement] to find its box. By replacing it |
| 191 // behind its back we can still get to the old values. | 189 // behind its back we can still get to the old values. |
| 192 updateLocal(boxElement, oldBox); | 190 updateLocal(boxElement, oldBox); |
| 193 HInstruction oldValue = readLocal(boxedVariable); | 191 HInstruction oldValue = readLocal(boxedVariable); |
| 194 updateLocal(boxElement, newBox); | 192 updateLocal(boxElement, newBox); |
| 195 updateLocal(boxedVariable, oldValue); | 193 updateLocal(boxedVariable, oldValue); |
| 196 } | 194 } |
| 197 updateLocal(boxElement, newBox); | 195 updateLocal(boxElement, newBox); |
| 198 } | 196 } |
| 199 | 197 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 226 builder.parameters[parameterElement] = parameter; | 224 builder.parameters[parameterElement] = parameter; |
| 227 directLocals[parameterElement] = parameter; | 225 directLocals[parameterElement] = parameter; |
| 228 }); | 226 }); |
| 229 } | 227 } |
| 230 | 228 |
| 231 enterScope(node, forGenerativeConstructorBody: isGenerativeConstructorBody); | 229 enterScope(node, forGenerativeConstructorBody: isGenerativeConstructorBody); |
| 232 | 230 |
| 233 // If the freeVariableMapping is not empty, then this function was a | 231 // If the freeVariableMapping is not empty, then this function was a |
| 234 // nested closure that captures variables. Redirect the captured | 232 // nested closure that captures variables. Redirect the captured |
| 235 // variables to fields in the closure. | 233 // variables to fields in the closure. |
| 236 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 234 closureData.forEachFreeVariable((Local from, FieldEntity to) { |
| 237 redirectElement(from, to); | 235 redirectElement(from, to); |
| 238 }); | 236 }); |
| 239 if (closureData.isClosure) { | 237 if (closureData.isClosure) { |
| 240 // Inside closure redirect references to itself to [:this:]. | 238 // Inside closure redirect references to itself to [:this:]. |
| 241 HThis thisInstruction = | 239 HThis thisInstruction = |
| 242 new HThis(closureData.thisLocal, commonMasks.nonNullType); | 240 new HThis(closureData.thisLocal, commonMasks.nonNullType); |
| 243 builder.graph.thisInstruction = thisInstruction; | 241 builder.graph.thisInstruction = thisInstruction; |
| 244 builder.graph.entry.addAtEntry(thisInstruction); | 242 builder.graph.entry.addAtEntry(thisInstruction); |
| 245 updateLocal(closureData.closureElement, thisInstruction); | 243 updateLocal(closureData.closureElement, thisInstruction); |
| 246 } else if (element.isInstanceMember) { | 244 } else if (element.isInstanceMember) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 /// captured variables that are stored in the closure-field return [:false:]. | 297 /// captured variables that are stored in the closure-field return [:false:]. |
| 300 bool isAccessedDirectly(Local local) { | 298 bool isAccessedDirectly(Local local) { |
| 301 assert(local != null); | 299 assert(local != null); |
| 302 return !redirectionMapping.containsKey(local) && | 300 return !redirectionMapping.containsKey(local) && |
| 303 !closureData.variablesUsedInTryOrGenerator.contains(local); | 301 !closureData.variablesUsedInTryOrGenerator.contains(local); |
| 304 } | 302 } |
| 305 | 303 |
| 306 bool isStoredInClosureField(Local local) { | 304 bool isStoredInClosureField(Local local) { |
| 307 assert(local != null); | 305 assert(local != null); |
| 308 if (isAccessedDirectly(local)) return false; | 306 if (isAccessedDirectly(local)) return false; |
| 309 CapturedVariable redirectTarget = redirectionMapping[local]; | 307 FieldEntity redirectTarget = redirectionMapping[local]; |
| 310 if (redirectTarget == null) return false; | 308 if (redirectTarget == null) return false; |
| 311 return redirectTarget is ClosureFieldElement; | 309 return redirectTarget is ClosureFieldElement; |
| 312 } | 310 } |
| 313 | 311 |
| 314 bool isBoxed(Local local) { | 312 bool isBoxed(Local local) { |
| 315 if (isAccessedDirectly(local)) return false; | 313 if (isAccessedDirectly(local)) return false; |
| 316 if (isStoredInClosureField(local)) return false; | 314 if (isStoredInClosureField(local)) return false; |
| 317 return redirectionMapping.containsKey(local); | 315 return redirectionMapping.containsKey(local); |
| 318 } | 316 } |
| 319 | 317 |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 final MemberEntity memberContext; | 681 final MemberEntity memberContext; |
| 684 | 682 |
| 685 // Avoid slow Object.hashCode. | 683 // Avoid slow Object.hashCode. |
| 686 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 684 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
| 687 static int _nextHashCode = 0; | 685 static int _nextHashCode = 0; |
| 688 | 686 |
| 689 SyntheticLocal(this.name, this.executableContext, this.memberContext); | 687 SyntheticLocal(this.name, this.executableContext, this.memberContext); |
| 690 | 688 |
| 691 toString() => 'SyntheticLocal($name)'; | 689 toString() => 'SyntheticLocal($name)'; |
| 692 } | 690 } |
| OLD | NEW |