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; | |
8 import '../elements/resolution_types.dart'; | 7 import '../elements/resolution_types.dart'; |
9 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
10 import '../elements/entities.dart'; | 9 import '../elements/entities.dart'; |
11 import '../io/source_information.dart'; | 10 import '../io/source_information.dart'; |
12 import '../js/js.dart' as js; | 11 import '../js/js.dart' as js; |
13 import '../js_backend/js_backend.dart'; | 12 import '../js_backend/native_data.dart'; |
| 13 import '../js_backend/interceptor_data.dart'; |
14 import '../native/native.dart' as native; | 14 import '../native/native.dart' as native; |
15 import '../tree/tree.dart' as ast; | 15 import '../tree/tree.dart' as ast; |
16 import '../types/types.dart'; | 16 import '../types/types.dart'; |
17 import '../world.dart' show ClosedWorld; | 17 import '../world.dart' show ClosedWorld; |
18 | 18 |
19 import 'graph_builder.dart'; | 19 import 'graph_builder.dart'; |
20 import 'nodes.dart'; | 20 import 'nodes.dart'; |
21 import 'types.dart'; | 21 import 'types.dart'; |
22 | 22 |
23 /// Keeps track of locals (including parameters and phis) when building. The | 23 /// Keeps track of locals (including parameters and phis) when building. The |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 /// } | 55 /// } |
56 /// main() { | 56 /// main() { |
57 /// new Foo<String>('foo'); | 57 /// new Foo<String>('foo'); |
58 /// } | 58 /// } |
59 /// | 59 /// |
60 /// [instanceType] is not used if it contains type variables, since these | 60 /// [instanceType] is not used if it contains type variables, since these |
61 /// might not be in scope or from the current instance. | 61 /// might not be in scope or from the current instance. |
62 /// | 62 /// |
63 final ResolutionInterfaceType instanceType; | 63 final ResolutionInterfaceType instanceType; |
64 | 64 |
65 final Compiler _compiler; | 65 final NativeData _nativeData; |
66 | 66 |
67 LocalsHandler(this.builder, this.executableContext, | 67 final InterceptorData _interceptorData; |
68 ResolutionInterfaceType instanceType, this._compiler) | 68 |
| 69 LocalsHandler( |
| 70 this.builder, |
| 71 this.executableContext, |
| 72 ResolutionInterfaceType instanceType, |
| 73 this._nativeData, |
| 74 this._interceptorData) |
69 : this.instanceType = | 75 : this.instanceType = |
70 instanceType == null || instanceType.containsTypeVariables | 76 instanceType == null || instanceType.containsTypeVariables |
71 ? null | 77 ? null |
72 : instanceType; | 78 : instanceType; |
73 | 79 |
74 ClosedWorld get closedWorld => builder.closedWorld; | 80 ClosedWorld get closedWorld => builder.closedWorld; |
75 | 81 |
76 CommonMasks get commonMasks => closedWorld.commonMasks; | 82 CommonMasks get commonMasks => closedWorld.commonMasks; |
77 | 83 |
78 GlobalTypeInferenceResults get _globalInferenceResults => | 84 GlobalTypeInferenceResults get _globalInferenceResults => |
79 _compiler.globalInference.results; | 85 builder.globalInferenceResults; |
| 86 |
| 87 ClosureTask get _closureToClassMapper => builder.closureToClassMapper; |
80 | 88 |
81 /// Substituted type variables occurring in [type] into the context of | 89 /// Substituted type variables occurring in [type] into the context of |
82 /// [contextClass]. | 90 /// [contextClass]. |
83 ResolutionDartType substInContext(ResolutionDartType type) { | 91 ResolutionDartType substInContext(ResolutionDartType type) { |
84 if (contextClass != null) { | 92 if (contextClass != null) { |
85 ClassElement typeContext = Types.getClassContext(type); | 93 ClassElement typeContext = Types.getClassContext(type); |
86 if (typeContext != null) { | 94 if (typeContext != null) { |
87 type = type.substByContext(contextClass.asInstanceOf(typeContext)); | 95 type = type.substByContext(contextClass.asInstanceOf(typeContext)); |
88 } | 96 } |
89 } | 97 } |
90 if (instanceType != null) { | 98 if (instanceType != null) { |
91 type = type.substByContext(instanceType); | 99 type = type.substByContext(instanceType); |
92 } | 100 } |
93 return type; | 101 return type; |
94 } | 102 } |
95 | 103 |
96 /// Creates a new [LocalsHandler] based on [other]. We only need to | 104 /// Creates a new [LocalsHandler] based on [other]. We only need to |
97 /// copy the [directLocals], since the other fields can be shared | 105 /// copy the [directLocals], since the other fields can be shared |
98 /// throughout the AST visit. | 106 /// throughout the AST visit. |
99 LocalsHandler.from(LocalsHandler other) | 107 LocalsHandler.from(LocalsHandler other) |
100 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), | 108 : directLocals = new Map<Local, HInstruction>.from(other.directLocals), |
101 redirectionMapping = other.redirectionMapping, | 109 redirectionMapping = other.redirectionMapping, |
102 executableContext = other.executableContext, | 110 executableContext = other.executableContext, |
103 instanceType = other.instanceType, | 111 instanceType = other.instanceType, |
104 builder = other.builder, | 112 builder = other.builder, |
105 closureData = other.closureData, | 113 closureData = other.closureData, |
106 _compiler = other._compiler, | 114 _nativeData = other._nativeData, |
| 115 _interceptorData = other._interceptorData, |
107 activationVariables = other.activationVariables, | 116 activationVariables = other.activationVariables, |
108 cachedTypeOfThis = other.cachedTypeOfThis, | 117 cachedTypeOfThis = other.cachedTypeOfThis, |
109 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; | 118 cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables; |
110 | 119 |
111 /// Redirects accesses from element [from] to element [to]. The [to] element | 120 /// Redirects accesses from element [from] to element [to]. The [to] element |
112 /// must be a boxed variable or a variable that is stored in a closure-field. | 121 /// must be a boxed variable or a variable that is stored in a closure-field. |
113 void redirectElement(Local from, CapturedVariable to) { | 122 void redirectElement(Local from, CapturedVariable to) { |
114 assert(redirectionMapping[from] == null); | 123 assert(redirectionMapping[from] == null); |
115 redirectionMapping[from] = to; | 124 redirectionMapping[from] = to; |
116 assert(isStoredInClosureField(from) || isBoxed(from)); | 125 assert(isStoredInClosureField(from) || isBoxed(from)); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 updateLocal(boxedVariable, oldValue); | 193 updateLocal(boxedVariable, oldValue); |
185 } | 194 } |
186 updateLocal(boxElement, newBox); | 195 updateLocal(boxElement, newBox); |
187 } | 196 } |
188 | 197 |
189 /// Documentation wanted -- johnniwinther | 198 /// Documentation wanted -- johnniwinther |
190 /// | 199 /// |
191 /// Invariant: [function] must be an implementation element. | 200 /// Invariant: [function] must be an implementation element. |
192 void startFunction(MemberElement element, ast.Node node) { | 201 void startFunction(MemberElement element, ast.Node node) { |
193 assert(invariant(element, element.isImplementation)); | 202 assert(invariant(element, element.isImplementation)); |
194 closureData = _compiler.closureToClassMapper | 203 closureData = |
195 .getClosureToClassMapping(element.resolvedAst); | 204 _closureToClassMapper.getClosureToClassMapping(element.resolvedAst); |
196 | 205 |
197 if (element is MethodElement) { | 206 if (element is MethodElement) { |
198 MethodElement functionElement = element; | 207 MethodElement functionElement = element; |
199 FunctionSignature params = functionElement.functionSignature; | 208 FunctionSignature params = functionElement.functionSignature; |
200 ClosureScope scopeData = closureData.capturingScopes[node]; | 209 ClosureScope scopeData = closureData.capturingScopes[node]; |
201 params.orderedForEachParameter((ParameterElement parameterElement) { | 210 params.orderedForEachParameter((ParameterElement parameterElement) { |
202 if (element.isGenerativeConstructorBody) { | 211 if (element.isGenerativeConstructorBody) { |
203 if (scopeData != null && | 212 if (scopeData != null && |
204 scopeData.isCapturedVariable(parameterElement)) { | 213 scopeData.isCapturedVariable(parameterElement)) { |
205 // The parameter will be a field in the box passed as the | 214 // The parameter will be a field in the box passed as the |
(...skipping 11 matching lines...) Expand all Loading... |
217 } | 226 } |
218 | 227 |
219 enterScope(node, element); | 228 enterScope(node, element); |
220 | 229 |
221 // If the freeVariableMapping is not empty, then this function was a | 230 // If the freeVariableMapping is not empty, then this function was a |
222 // nested closure that captures variables. Redirect the captured | 231 // nested closure that captures variables. Redirect the captured |
223 // variables to fields in the closure. | 232 // variables to fields in the closure. |
224 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 233 closureData.forEachFreeVariable((Local from, CapturedVariable to) { |
225 redirectElement(from, to); | 234 redirectElement(from, to); |
226 }); | 235 }); |
227 JavaScriptBackend backend = _compiler.backend; | |
228 if (closureData.isClosure) { | 236 if (closureData.isClosure) { |
229 // Inside closure redirect references to itself to [:this:]. | 237 // Inside closure redirect references to itself to [:this:]. |
230 HThis thisInstruction = | 238 HThis thisInstruction = |
231 new HThis(closureData.thisLocal, commonMasks.nonNullType); | 239 new HThis(closureData.thisLocal, commonMasks.nonNullType); |
232 builder.graph.thisInstruction = thisInstruction; | 240 builder.graph.thisInstruction = thisInstruction; |
233 builder.graph.entry.addAtEntry(thisInstruction); | 241 builder.graph.entry.addAtEntry(thisInstruction); |
234 updateLocal(closureData.closureElement, thisInstruction); | 242 updateLocal(closureData.closureElement, thisInstruction); |
235 } else if (element.isInstanceMember) { | 243 } else if (element.isInstanceMember) { |
236 // Once closures have been mapped to classes their instance members might | 244 // Once closures have been mapped to classes their instance members might |
237 // not have any thisElement if the closure was created inside a static | 245 // not have any thisElement if the closure was created inside a static |
238 // context. | 246 // context. |
239 HThis thisInstruction = new HThis(closureData.thisLocal, getTypeOfThis()); | 247 HThis thisInstruction = new HThis(closureData.thisLocal, getTypeOfThis()); |
240 builder.graph.thisInstruction = thisInstruction; | 248 builder.graph.thisInstruction = thisInstruction; |
241 builder.graph.entry.addAtEntry(thisInstruction); | 249 builder.graph.entry.addAtEntry(thisInstruction); |
242 directLocals[closureData.thisLocal] = thisInstruction; | 250 directLocals[closureData.thisLocal] = thisInstruction; |
243 } | 251 } |
244 | 252 |
245 // If this method is an intercepted method, add the extra | 253 // If this method is an intercepted method, add the extra |
246 // parameter to it, that is the actual receiver for intercepted | 254 // parameter to it, that is the actual receiver for intercepted |
247 // classes, or the same as [:this:] for non-intercepted classes. | 255 // classes, or the same as [:this:] for non-intercepted classes. |
248 ClassElement cls = element.enclosingClass; | 256 ClassElement cls = element.enclosingClass; |
249 | 257 |
250 // When the class extends a native class, the instance is pre-constructed | 258 // When the class extends a native class, the instance is pre-constructed |
251 // and passed to the generative constructor factory function as a parameter. | 259 // and passed to the generative constructor factory function as a parameter. |
252 // Instead of allocating and initializing the object, the constructor | 260 // Instead of allocating and initializing the object, the constructor |
253 // 'upgrades' the native subclass object by initializing the Dart fields. | 261 // 'upgrades' the native subclass object by initializing the Dart fields. |
254 bool isNativeUpgradeFactory = element.isGenerativeConstructor && | 262 bool isNativeUpgradeFactory = element.isGenerativeConstructor && |
255 backend.nativeData.isNativeOrExtendsNative(cls); | 263 _nativeData.isNativeOrExtendsNative(cls); |
256 if (backend.interceptorData.isInterceptedMethod(element)) { | 264 if (_interceptorData.isInterceptedMethod(element)) { |
257 bool isInterceptedClass = | 265 bool isInterceptedClass = |
258 backend.interceptorData.isInterceptedClass(cls.declaration); | 266 _interceptorData.isInterceptedClass(cls.declaration); |
259 String name = isInterceptedClass ? 'receiver' : '_'; | 267 String name = isInterceptedClass ? 'receiver' : '_'; |
260 SyntheticLocal parameter = new SyntheticLocal(name, executableContext); | 268 SyntheticLocal parameter = new SyntheticLocal(name, executableContext); |
261 HParameterValue value = new HParameterValue(parameter, getTypeOfThis()); | 269 HParameterValue value = new HParameterValue(parameter, getTypeOfThis()); |
262 builder.graph.explicitReceiverParameter = value; | 270 builder.graph.explicitReceiverParameter = value; |
263 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); | 271 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); |
264 if (builder.lastAddedParameter == null) { | 272 if (builder.lastAddedParameter == null) { |
265 // If this is the first parameter inserted, make sure it stays first. | 273 // If this is the first parameter inserted, make sure it stays first. |
266 builder.lastAddedParameter = value; | 274 builder.lastAddedParameter = value; |
267 } | 275 } |
268 if (isInterceptedClass) { | 276 if (isInterceptedClass) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 return closureData.variablesUsedInTryOrGenerator.contains(local); | 319 return closureData.variablesUsedInTryOrGenerator.contains(local); |
312 } | 320 } |
313 | 321 |
314 /// Returns an [HInstruction] for the given element. If the element is | 322 /// Returns an [HInstruction] for the given element. If the element is |
315 /// boxed or stored in a closure then the method generates code to retrieve | 323 /// boxed or stored in a closure then the method generates code to retrieve |
316 /// the value. | 324 /// the value. |
317 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { | 325 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
318 if (isAccessedDirectly(local)) { | 326 if (isAccessedDirectly(local)) { |
319 if (directLocals[local] == null) { | 327 if (directLocals[local] == null) { |
320 if (local is TypeVariableElement) { | 328 if (local is TypeVariableElement) { |
321 _compiler.reporter.internalError(_compiler.currentElement, | 329 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, |
322 "Runtime type information not available for $local."); | 330 "Runtime type information not available for $local."); |
323 } else { | 331 } else { |
324 _compiler.reporter.internalError( | 332 throw new SpannableAssertionFailure( |
325 local, "Cannot find value $local in ${directLocals.keys}."); | 333 local, "Cannot find value $local in ${directLocals.keys}."); |
326 } | 334 } |
327 } | 335 } |
328 HInstruction value = directLocals[local]; | 336 HInstruction value = directLocals[local]; |
329 if (sourceInformation != null) { | 337 if (sourceInformation != null) { |
330 value = new HRef(value, sourceInformation); | 338 value = new HRef(value, sourceInformation); |
331 builder.add(value); | 339 builder.add(value); |
332 } | 340 } |
333 return value; | 341 return value; |
334 } else if (isStoredInClosureField(local)) { | 342 } else if (isStoredInClosureField(local)) { |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
670 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); | 678 final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30); |
671 static int _nextHashCode = 0; | 679 static int _nextHashCode = 0; |
672 | 680 |
673 SyntheticLocal(this.name, this.executableContext); | 681 SyntheticLocal(this.name, this.executableContext); |
674 | 682 |
675 @override | 683 @override |
676 MemberElement get memberContext => executableContext.memberContext; | 684 MemberElement get memberContext => executableContext.memberContext; |
677 | 685 |
678 toString() => 'SyntheticLocal($name)'; | 686 toString() => 'SyntheticLocal($name)'; |
679 } | 687 } |
OLD | NEW |