OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'dart:io'; |
| 6 import 'package:async_helper/async_helper.dart'; |
| 7 import 'package:compiler/src/common.dart'; |
| 8 import 'package:compiler/src/compiler.dart'; |
| 9 import 'package:compiler/src/diagnostics/diagnostic_listener.dart'; |
| 10 import 'package:compiler/src/elements/elements.dart'; |
| 11 import 'package:compiler/src/elements/entities.dart'; |
| 12 import 'package:compiler/src/elements/jumps.dart'; |
| 13 import 'package:compiler/src/js_model/locals.dart'; |
| 14 import 'package:compiler/src/kernel/element_map.dart'; |
| 15 import 'package:compiler/src/kernel/kernel_backend_strategy.dart'; |
| 16 import 'package:compiler/src/tree/nodes.dart' as ast; |
| 17 import '../equivalence/id_equivalence.dart'; |
| 18 import '../equivalence/id_equivalence_helper.dart'; |
| 19 import 'package:kernel/ast.dart' as ir; |
| 20 |
| 21 main() { |
| 22 asyncTest(() async { |
| 23 Directory dataDir = new Directory.fromUri(Platform.script.resolve('data')); |
| 24 await for (FileSystemEntity entity in dataDir.list()) { |
| 25 print('Checking ${entity.uri}'); |
| 26 String annotatedCode = await new File.fromUri(entity.uri).readAsString(); |
| 27 await checkCode(annotatedCode, computeJumpsData, compileFromSource); |
| 28 await checkCode(annotatedCode, computeKernelJumpsData, compileFromDill); |
| 29 } |
| 30 }); |
| 31 } |
| 32 |
| 33 /// Compute closure data mapping for [_member] as a [MemberElement]. |
| 34 /// |
| 35 /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans |
| 36 /// for the data origin. |
| 37 void computeJumpsData( |
| 38 Compiler compiler, MemberEntity _member, Map<Id, ActualData> actualMap, |
| 39 {bool verbose: false}) { |
| 40 MemberElement member = _member; |
| 41 new JumpsAstComputer(compiler.reporter, actualMap, member.resolvedAst).run(); |
| 42 } |
| 43 |
| 44 /// Compute closure data mapping for [member] as a kernel based element. |
| 45 /// |
| 46 /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans |
| 47 /// for the data origin. |
| 48 void computeKernelJumpsData( |
| 49 Compiler compiler, MemberEntity member, Map<Id, ActualData> actualMap, |
| 50 {bool verbose: false}) { |
| 51 KernelBackendStrategy backendStrategy = compiler.backendStrategy; |
| 52 KernelToElementMapForBuilding elementMap = backendStrategy.elementMap; |
| 53 GlobalLocalsMap localsMap = backendStrategy.globalLocalsMapForTesting; |
| 54 MemberDefinition definition = elementMap.getMemberDefinition(member); |
| 55 new JumpsIrChecker( |
| 56 actualMap, elementMap, member, localsMap.getLocalsMap(member)) |
| 57 .run(definition.node); |
| 58 } |
| 59 |
| 60 class TargetData { |
| 61 final int index; |
| 62 final NodeId id; |
| 63 final SourceSpan sourceSpan; |
| 64 final JumpTarget target; |
| 65 |
| 66 TargetData(this.index, this.id, this.sourceSpan, this.target); |
| 67 } |
| 68 |
| 69 class GotoData { |
| 70 final NodeId id; |
| 71 final SourceSpan sourceSpan; |
| 72 final JumpTarget target; |
| 73 |
| 74 GotoData(this.id, this.sourceSpan, this.target); |
| 75 } |
| 76 |
| 77 abstract class JumpsMixin { |
| 78 int index = 0; |
| 79 Map<JumpTarget, TargetData> targets = <JumpTarget, TargetData>{}; |
| 80 List<GotoData> gotos = <GotoData>[]; |
| 81 |
| 82 void registerValue(SourceSpan sourceSpan, Id id, String value, Object object); |
| 83 |
| 84 void processData() { |
| 85 targets.forEach((JumpTarget target, TargetData data) { |
| 86 StringBuffer sb = new StringBuffer(); |
| 87 sb.write(data.index); |
| 88 sb.write('@'); |
| 89 bool needsComma = false; |
| 90 if (target.isBreakTarget) { |
| 91 sb.write('break'); |
| 92 needsComma = true; |
| 93 } |
| 94 if (target.isContinueTarget) { |
| 95 if (needsComma) { |
| 96 sb.write(','); |
| 97 } |
| 98 sb.write('continue'); |
| 99 needsComma = true; |
| 100 } |
| 101 String value = sb.toString(); |
| 102 registerValue(data.sourceSpan, data.id, value, target); |
| 103 }); |
| 104 gotos.forEach((GotoData data) { |
| 105 StringBuffer sb = new StringBuffer(); |
| 106 sb.write('target='); |
| 107 TargetData targetData = targets[data.target]; |
| 108 sb.write(targetData.index); |
| 109 String value = sb.toString(); |
| 110 registerValue(data.sourceSpan, data.id, value, data); |
| 111 }); |
| 112 } |
| 113 } |
| 114 |
| 115 /// Ast visitor for computing jump data. |
| 116 class JumpsAstComputer extends AstDataExtractor with JumpsMixin { |
| 117 JumpsAstComputer(DiagnosticReporter reporter, Map<Id, ActualData> actualMap, |
| 118 ResolvedAst resolvedAst) |
| 119 : super(reporter, actualMap, resolvedAst); |
| 120 |
| 121 void run() { |
| 122 super.run(); |
| 123 processData(); |
| 124 } |
| 125 |
| 126 @override |
| 127 String computeNodeValue(ast.Node node, [AstElement element]) { |
| 128 // Node values are computed post-visit in [processData]. |
| 129 return null; |
| 130 } |
| 131 |
| 132 @override |
| 133 String computeElementValue(AstElement element) { |
| 134 return null; |
| 135 } |
| 136 |
| 137 @override |
| 138 visitLoop(ast.Loop node) { |
| 139 JumpTarget target = elements.getTargetDefinition(node); |
| 140 if (target != null) { |
| 141 NodeId id = computeLoopNodeId(node); |
| 142 SourceSpan sourceSpan = computeSourceSpan(node); |
| 143 targets[target] = new TargetData(index++, id, sourceSpan, target); |
| 144 } |
| 145 super.visitLoop(node); |
| 146 } |
| 147 |
| 148 @override |
| 149 visitGotoStatement(ast.GotoStatement node) { |
| 150 JumpTarget target = elements.getTargetOf(node); |
| 151 NodeId id = computeGotoNodeId(node); |
| 152 SourceSpan sourceSpan = computeSourceSpan(node); |
| 153 gotos.add(new GotoData(id, sourceSpan, target)); |
| 154 super.visitGotoStatement(node); |
| 155 } |
| 156 } |
| 157 |
| 158 /// Kernel IR visitor for computing jump data. |
| 159 class JumpsIrChecker extends IrDataExtractor with JumpsMixin { |
| 160 final KernelToLocalsMap _localsMap; |
| 161 |
| 162 JumpsIrChecker(Map<Id, ActualData> actualMap, KernelToElementMap elementMap, |
| 163 MemberEntity member, this._localsMap) |
| 164 : super(actualMap); |
| 165 |
| 166 void run(ir.Node root) { |
| 167 super.run(root); |
| 168 processData(); |
| 169 } |
| 170 |
| 171 @override |
| 172 String computeNodeValue(ir.Node node) { |
| 173 // Node values are computed post-visit in [processData]. |
| 174 return null; |
| 175 } |
| 176 |
| 177 @override |
| 178 String computeMemberValue(ir.Member member) { |
| 179 return null; |
| 180 } |
| 181 |
| 182 visitForStatement(ir.ForStatement node) { |
| 183 JumpTarget target = _localsMap.getJumpTargetForFor(node); |
| 184 if (target != null) { |
| 185 NodeId id = computeLoopNodeId(node); |
| 186 SourceSpan sourceSpan = computeSourceSpan(node); |
| 187 targets[target] = new TargetData(index++, id, sourceSpan, target); |
| 188 } |
| 189 super.visitForStatement(node); |
| 190 } |
| 191 |
| 192 // TODO(johnniwinther): Support testing of do, for-in and while loops. |
| 193 |
| 194 visitBreakStatement(ir.BreakStatement node) { |
| 195 JumpTarget target = _localsMap.getJumpTargetForBreak(node); |
| 196 assert(target != null, 'No target for $node.'); |
| 197 NodeId id = computeGotoNodeId(node); |
| 198 SourceSpan sourceSpan = computeSourceSpan(node); |
| 199 gotos.add(new GotoData(id, sourceSpan, target)); |
| 200 super.visitBreakStatement(node); |
| 201 } |
| 202 } |
OLD | NEW |