| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 6 | 6 |
| 7 import '../closure.dart'; | 7 import '../closure.dart'; |
| 8 import '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../common/tasks.dart'; | 9 import '../common/tasks.dart'; |
| 10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 /// closure semantics in JS. If this closure captures any variables (meaning | 127 /// closure semantics in JS. If this closure captures any variables (meaning |
| 128 /// the closure accesses a variable that gets accessed at some point), then | 128 /// the closure accesses a variable that gets accessed at some point), then |
| 129 /// boxForCapturedVariables stores the local context for those variables. | 129 /// boxForCapturedVariables stores the local context for those variables. |
| 130 /// If no variables are captured, this parameter is null. | 130 /// If no variables are captured, this parameter is null. |
| 131 void _produceSyntheticElements( | 131 void _produceSyntheticElements( |
| 132 MemberEntity member, | 132 MemberEntity member, |
| 133 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, | 133 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, |
| 134 ScopeInfo info, | 134 ScopeInfo info, |
| 135 ClosedWorldRefiner closedWorldRefiner) { | 135 ClosedWorldRefiner closedWorldRefiner) { |
| 136 String name = _computeClosureName(node); | 136 String name = _computeClosureName(node); |
| 137 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); |
| 137 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo( | 138 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo( |
| 138 name, member.library, info, node.location); | 139 name, member.library, info, node.location, localsMap); |
| 139 | 140 |
| 140 Entity entity; | 141 Entity entity; |
| 141 if (node is ir.Member) { | 142 if (node is ir.Member) { |
| 142 entity = member; | 143 entity = member; |
| 143 } else { | 144 } else { |
| 144 assert(node is ir.FunctionNode); | 145 assert(node is ir.FunctionNode); |
| 145 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); | |
| 146 entity = localsMap.getLocalFunction(node.parent); | 146 entity = localsMap.getLocalFunction(node.parent); |
| 147 // We want the original declaration where that function is used to point | 147 // We want the original declaration where that function is used to point |
| 148 // to the correct closure class. | 148 // to the correct closure class. |
| 149 _closureRepresentationMap[closureClass.callMethod] = closureClass; | 149 _closureRepresentationMap[closureClass.callMethod] = closureClass; |
| 150 } | 150 } |
| 151 assert(entity != null); | 151 assert(entity != null); |
| 152 _closureRepresentationMap[entity] = closureClass; | 152 _closureRepresentationMap[entity] = closureClass; |
| 153 | 153 |
| 154 // Register that a new class has been created. | 154 // Register that a new class has been created. |
| 155 closedWorldRefiner.registerClosureClass(closureClass); | 155 closedWorldRefiner.registerClosureClass(closureClass); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 | 242 |
| 243 class KernelScopeInfo extends ScopeInfo { | 243 class KernelScopeInfo extends ScopeInfo { |
| 244 final Set<Local> localsUsedInTryOrSync; | 244 final Set<Local> localsUsedInTryOrSync; |
| 245 final Local thisLocal; | 245 final Local thisLocal; |
| 246 final Set<Local> boxedVariables; | 246 final Set<Local> boxedVariables; |
| 247 | 247 |
| 248 /// The set of variables that were defined in another scope, but are used in | 248 /// The set of variables that were defined in another scope, but are used in |
| 249 /// this scope. | 249 /// this scope. |
| 250 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>(); | 250 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>(); |
| 251 | 251 |
| 252 /// Used to map [freeVariables] to their corresponding locals. | 252 KernelScopeInfo(this.thisLocal) |
| 253 final KernelToLocalsMap localsMap; | |
| 254 | |
| 255 KernelScopeInfo(this.thisLocal, this.localsMap) | |
| 256 : localsUsedInTryOrSync = new Set<Local>(), | 253 : localsUsedInTryOrSync = new Set<Local>(), |
| 257 boxedVariables = new Set<Local>(); | 254 boxedVariables = new Set<Local>(); |
| 258 | 255 |
| 259 KernelScopeInfo.from(this.thisLocal, KernelScopeInfo info) | 256 KernelScopeInfo.from(this.thisLocal, KernelScopeInfo info) |
| 260 : localsUsedInTryOrSync = info.localsUsedInTryOrSync, | 257 : localsUsedInTryOrSync = info.localsUsedInTryOrSync, |
| 261 boxedVariables = info.boxedVariables, | 258 boxedVariables = info.boxedVariables; |
| 262 localsMap = info.localsMap; | |
| 263 | 259 |
| 264 KernelScopeInfo.withBoxedVariables( | 260 KernelScopeInfo.withBoxedVariables(this.boxedVariables, |
| 265 this.boxedVariables, | 261 this.localsUsedInTryOrSync, this.freeVariables, this.thisLocal); |
| 266 this.localsUsedInTryOrSync, | |
| 267 this.freeVariables, | |
| 268 this.localsMap, | |
| 269 this.thisLocal); | |
| 270 | 262 |
| 271 void forEachBoxedVariable(f(Local local, FieldEntity field)) { | 263 void forEachBoxedVariable(f(Local local, FieldEntity field)) { |
| 272 boxedVariables.forEach((Local l) { | 264 boxedVariables.forEach((Local l) { |
| 273 // TODO(efortuna): add FieldEntities as created. | 265 // TODO(efortuna): add FieldEntities as created. |
| 274 f(l, null); | 266 f(l, null); |
| 275 }); | 267 }); |
| 276 } | 268 } |
| 277 | 269 |
| 278 bool localIsUsedInTryOrSync(Local variable) => | 270 bool localIsUsedInTryOrSync(Local variable) => |
| 279 localsUsedInTryOrSync.contains(variable); | 271 localsUsedInTryOrSync.contains(variable); |
| 280 | 272 |
| 281 String toString() { | 273 String toString() { |
| 282 StringBuffer sb = new StringBuffer(); | 274 StringBuffer sb = new StringBuffer(); |
| 283 sb.write('this=$thisLocal,'); | 275 sb.write('this=$thisLocal,'); |
| 284 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); | 276 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); |
| 285 return sb.toString(); | 277 return sb.toString(); |
| 286 } | 278 } |
| 287 | 279 |
| 288 bool isBoxed(Local variable) => boxedVariables.contains(variable); | 280 bool isBoxed(Local variable) => boxedVariables.contains(variable); |
| 289 } | 281 } |
| 290 | 282 |
| 291 class KernelCapturedScope extends KernelScopeInfo implements CapturedScope { | 283 class KernelCapturedScope extends KernelScopeInfo implements CapturedScope { |
| 292 final Local context; | 284 final Local context; |
| 293 | 285 |
| 294 KernelCapturedScope( | 286 KernelCapturedScope( |
| 295 Set<Local> boxedVariables, | 287 Set<Local> boxedVariables, |
| 296 this.context, | 288 this.context, |
| 297 Set<Local> localsUsedInTryOrSync, | 289 Set<Local> localsUsedInTryOrSync, |
| 298 Set<ir.VariableDeclaration> freeVariables, | 290 Set<ir.VariableDeclaration> freeVariables, |
| 299 KernelToLocalsMap localsMap, | |
| 300 Local thisLocal) | 291 Local thisLocal) |
| 301 : super.withBoxedVariables(boxedVariables, localsUsedInTryOrSync, | 292 : super.withBoxedVariables( |
| 302 freeVariables, localsMap, thisLocal); | 293 boxedVariables, localsUsedInTryOrSync, freeVariables, thisLocal); |
| 303 | 294 |
| 304 bool get requiresContextBox => boxedVariables.isNotEmpty; | 295 bool get requiresContextBox => boxedVariables.isNotEmpty; |
| 305 } | 296 } |
| 306 | 297 |
| 307 class KernelCapturedLoopScope extends KernelCapturedScope | 298 class KernelCapturedLoopScope extends KernelCapturedScope |
| 308 implements CapturedLoopScope { | 299 implements CapturedLoopScope { |
| 309 final List<Local> boxedLoopVariables; | 300 final List<Local> boxedLoopVariables; |
| 310 | 301 |
| 311 KernelCapturedLoopScope( | 302 KernelCapturedLoopScope( |
| 312 Set<Local> boxedVariables, | 303 Set<Local> boxedVariables, |
| 313 this.boxedLoopVariables, | 304 this.boxedLoopVariables, |
| 314 Local context, | 305 Local context, |
| 315 Set<Local> localsUsedInTryOrSync, | 306 Set<Local> localsUsedInTryOrSync, |
| 316 Set<ir.VariableDeclaration> freeVariables, | 307 Set<ir.VariableDeclaration> freeVariables, |
| 317 KernelToLocalsMap localsMap, | |
| 318 Local thisLocal) | 308 Local thisLocal) |
| 319 : super(boxedVariables, context, localsUsedInTryOrSync, freeVariables, | 309 : super(boxedVariables, context, localsUsedInTryOrSync, freeVariables, |
| 320 localsMap, thisLocal); | 310 thisLocal); |
| 321 | 311 |
| 322 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; | 312 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
| 323 } | 313 } |
| 324 | 314 |
| 325 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. | 315 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. |
| 326 class KernelClosureClass extends KernelScopeInfo | 316 class KernelClosureClass extends KernelScopeInfo |
| 327 implements ClosureRepresentationInfo, JClass { | 317 implements ClosureRepresentationInfo, JClass { |
| 328 final ir.Location location; | 318 final ir.Location location; |
| 329 | 319 |
| 330 final String name; | 320 final String name; |
| 331 final JLibrary library; | 321 final JLibrary library; |
| 332 | 322 |
| 333 /// Index into the classData, classList and classEnvironment lists where this | 323 /// Index into the classData, classList and classEnvironment lists where this |
| 334 /// entity is stored in [JsToFrontendMapImpl]. | 324 /// entity is stored in [JsToFrontendMapImpl]. |
| 335 int classIndex; | 325 int classIndex; |
| 336 | 326 |
| 337 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); | 327 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); |
| 338 | 328 |
| 339 KernelClosureClass.fromScopeInfo( | 329 KernelClosureClass.fromScopeInfo(this.name, this.library, |
| 340 this.name, this.library, KernelScopeInfo info, this.location) | 330 KernelScopeInfo info, this.location, KernelToLocalsMap localsMap) |
| 341 : super.from(info.thisLocal, info) { | 331 : super.from(info.thisLocal, info) { |
| 342 // Make a corresponding field entity in this closure class for every single | 332 // Make a corresponding field entity in this closure class for every single |
| 343 // freeVariable in the KernelScopeInfo.freeVariable. | 333 // freeVariable in the KernelScopeInfo.freeVariable. |
| 344 int i = 0; | 334 int i = 0; |
| 345 for (ir.VariableDeclaration variable in info.freeVariables) { | 335 for (ir.VariableDeclaration variable in info.freeVariables) { |
| 346 // NOTE: This construction order may be slightly different than the | 336 // NOTE: This construction order may be slightly different than the |
| 347 // old Element version. The old version did all the boxed items and then | 337 // old Element version. The old version did all the boxed items and then |
| 348 // all the others. | 338 // all the others. |
| 349 Local capturedLocal = info.localsMap.getLocalVariable(variable); | 339 Local capturedLocal = localsMap.getLocalVariable(variable); |
| 350 if (info.isBoxed(capturedLocal)) { | 340 if (info.isBoxed(capturedLocal)) { |
| 351 // TODO(efortuna): Coming soon. | 341 // TODO(efortuna): Coming soon. |
| 352 } else { | 342 } else { |
| 353 localToFieldMap[capturedLocal] = new ClosureField( | 343 localToFieldMap[capturedLocal] = new ClosureField( |
| 354 _getClosureVariableName(capturedLocal.name, i), | 344 _getClosureVariableName(capturedLocal.name, i), |
| 355 this, | 345 this, |
| 356 variable.isConst, | 346 variable.isConst, |
| 357 variable.isFinal || variable.isConst); | 347 variable.isFinal || variable.isConst); |
| 358 // TODO(efortuna): These probably need to get registered somewhere. | 348 // TODO(efortuna): These probably need to get registered somewhere. |
| 359 } | 349 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 ClosureClassDefinition(this.cls, this.location); | 415 ClosureClassDefinition(this.cls, this.location); |
| 426 | 416 |
| 427 ClassKind get kind => ClassKind.closure; | 417 ClassKind get kind => ClassKind.closure; |
| 428 | 418 |
| 429 ir.Node get node => | 419 ir.Node get node => |
| 430 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); | 420 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); |
| 431 | 421 |
| 432 String toString() => | 422 String toString() => |
| 433 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; | 423 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; |
| 434 } | 424 } |
| OLD | NEW |