Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: pkg/compiler/lib/src/ssa/types_propagation.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/compiler/lib/src/ssa/types.dart ('k') | pkg/compiler/lib/src/ssa/validate.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 '../compiler.dart' show Compiler; 5 import '../compiler.dart' show Compiler;
6 import '../elements/elements.dart'; 6 import '../elements/elements.dart';
7 import '../js_backend/js_backend.dart'; 7 import '../js_backend/js_backend.dart';
8 import '../types/types.dart'; 8 import '../types/types.dart';
9 import '../universe/selector.dart' show Selector; 9 import '../universe/selector.dart' show Selector;
10 import '../world.dart' show ClassWorld, World; 10 import '../world.dart' show ClassWorld, World;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 } 91 }
92 } 92 }
93 // While processing the optimizable arithmetic instructions, we 93 // While processing the optimizable arithmetic instructions, we
94 // may discover better type information for dominated users of 94 // may discover better type information for dominated users of
95 // replaced operands, so we may need to take another stab at 95 // replaced operands, so we may need to take another stab at
96 // emptying the worklist afterwards. 96 // emptying the worklist afterwards.
97 processPendingOptimizations(); 97 processPendingOptimizations();
98 } while (!worklist.isEmpty); 98 } while (!worklist.isEmpty);
99 } 99 }
100 100
101
102 void addToWorkList(HInstruction instruction) { 101 void addToWorkList(HInstruction instruction) {
103 final int id = instruction.id; 102 final int id = instruction.id;
104 103
105 if (!workmap.containsKey(id)) { 104 if (!workmap.containsKey(id)) {
106 worklist.add(id); 105 worklist.add(id);
107 workmap[id] = instruction; 106 workmap[id] = instruction;
108 } 107 }
109 } 108 }
110 109
111 TypeMask visitBinaryArithmetic(HBinaryArithmetic instruction) { 110 TypeMask visitBinaryArithmetic(HBinaryArithmetic instruction) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 } 167 }
169 168
170 TypeMask visitTypeConversion(HTypeConversion instruction) { 169 TypeMask visitTypeConversion(HTypeConversion instruction) {
171 HInstruction input = instruction.checkedInput; 170 HInstruction input = instruction.checkedInput;
172 TypeMask inputType = input.instructionType; 171 TypeMask inputType = input.instructionType;
173 TypeMask checkedType = instruction.checkedType; 172 TypeMask checkedType = instruction.checkedType;
174 if (instruction.isArgumentTypeCheck || instruction.isReceiverTypeCheck) { 173 if (instruction.isArgumentTypeCheck || instruction.isReceiverTypeCheck) {
175 // We must make sure a type conversion for receiver or argument check 174 // We must make sure a type conversion for receiver or argument check
176 // does not try to do an int check, because an int check is not enough. 175 // does not try to do an int check, because an int check is not enough.
177 // We only do an int check if the input is integer or null. 176 // We only do an int check if the input is integer or null.
178 if (checkedType.containsOnlyNum(classWorld) 177 if (checkedType.containsOnlyNum(classWorld) &&
179 && !checkedType.containsOnlyDouble(classWorld) 178 !checkedType.containsOnlyDouble(classWorld) &&
180 && input.isIntegerOrNull(compiler)) { 179 input.isIntegerOrNull(compiler)) {
181 instruction.checkedType = backend.intType; 180 instruction.checkedType = backend.intType;
182 } else if (checkedType.containsOnlyInt(classWorld) 181 } else if (checkedType.containsOnlyInt(classWorld) &&
183 && !input.isIntegerOrNull(compiler)) { 182 !input.isIntegerOrNull(compiler)) {
184 instruction.checkedType = backend.numType; 183 instruction.checkedType = backend.numType;
185 } 184 }
186 } 185 }
187 186
188 TypeMask outputType = checkedType.intersection(inputType, classWorld); 187 TypeMask outputType = checkedType.intersection(inputType, classWorld);
189 if (outputType.isEmpty) { 188 if (outputType.isEmpty) {
190 // Intersection of double and integer conflicts (is empty), but JS numbers 189 // Intersection of double and integer conflicts (is empty), but JS numbers
191 // can be both int and double at the same time. For example, the input 190 // can be both int and double at the same time. For example, the input
192 // can be a literal double '8.0' that is marked as an integer (because 'is 191 // can be a literal double '8.0' that is marked as an integer (because 'is
193 // int' will return 'true'). What we really need to do is make the 192 // int' will return 'true'). What we really need to do is make the
194 // overlap between int and double values explicit in the TypeMask system. 193 // overlap between int and double values explicit in the TypeMask system.
195 if (inputType.containsOnlyInt(classWorld) 194 if (inputType.containsOnlyInt(classWorld) &&
196 && checkedType.containsOnlyDouble(classWorld)) { 195 checkedType.containsOnlyDouble(classWorld)) {
197 if (inputType.isNullable && checkedType.isNullable) { 196 if (inputType.isNullable && checkedType.isNullable) {
198 outputType = backend.doubleType.nullable(); 197 outputType = backend.doubleType.nullable();
199 } else { 198 } else {
200 outputType = backend.doubleType; 199 outputType = backend.doubleType;
201 } 200 }
202 } 201 }
203 } 202 }
204 if (inputType != outputType) { 203 if (inputType != outputType) {
205 input.replaceAllUsersDominatedBy(instruction.next, instruction); 204 input.replaceAllUsersDominatedBy(instruction.next, instruction);
206 } 205 }
207 return outputType; 206 return outputType;
208 } 207 }
209 208
210 TypeMask visitTypeKnown(HTypeKnown instruction) { 209 TypeMask visitTypeKnown(HTypeKnown instruction) {
211 HInstruction input = instruction.checkedInput; 210 HInstruction input = instruction.checkedInput;
212 TypeMask inputType = input.instructionType; 211 TypeMask inputType = input.instructionType;
213 TypeMask outputType = 212 TypeMask outputType =
214 instruction.knownType.intersection(inputType, classWorld); 213 instruction.knownType.intersection(inputType, classWorld);
215 if (inputType != outputType) { 214 if (inputType != outputType) {
216 input.replaceAllUsersDominatedBy(instruction.next, instruction); 215 input.replaceAllUsersDominatedBy(instruction.next, instruction);
217 } 216 }
218 return outputType; 217 return outputType;
219 } 218 }
220 219
221 void convertInput(HInvokeDynamic instruction, 220 void convertInput(
222 HInstruction input, 221 HInvokeDynamic instruction, HInstruction input, TypeMask type, int kind) {
223 TypeMask type,
224 int kind) {
225 Selector selector = (kind == HTypeConversion.RECEIVER_TYPE_CHECK) 222 Selector selector = (kind == HTypeConversion.RECEIVER_TYPE_CHECK)
226 ? instruction.selector 223 ? instruction.selector
227 : null; 224 : null;
228 HTypeConversion converted = new HTypeConversion( 225 HTypeConversion converted =
229 null, kind, type, input, selector) 226 new HTypeConversion(null, kind, type, input, selector)
230 ..sourceInformation = instruction.sourceInformation; 227 ..sourceInformation = instruction.sourceInformation;
231 instruction.block.addBefore(instruction, converted); 228 instruction.block.addBefore(instruction, converted);
232 input.replaceAllUsersDominatedBy(instruction, converted); 229 input.replaceAllUsersDominatedBy(instruction, converted);
233 } 230 }
234 231
235 bool isCheckEnoughForNsmOrAe(HInstruction instruction, 232 bool isCheckEnoughForNsmOrAe(HInstruction instruction, TypeMask type) {
236 TypeMask type) {
237 // In some cases, we want the receiver to be an integer, 233 // In some cases, we want the receiver to be an integer,
238 // but that does not mean we will get a NoSuchMethodError 234 // but that does not mean we will get a NoSuchMethodError
239 // if it's not: the receiver could be a double. 235 // if it's not: the receiver could be a double.
240 if (type.containsOnlyInt(classWorld)) { 236 if (type.containsOnlyInt(classWorld)) {
241 // If the instruction's type is integer or null, the codegen 237 // If the instruction's type is integer or null, the codegen
242 // will emit a null check, which is enough to know if it will 238 // will emit a null check, which is enough to know if it will
243 // hit a noSuchMethod. 239 // hit a noSuchMethod.
244 return instruction.isIntegerOrNull(compiler); 240 return instruction.isIntegerOrNull(compiler);
245 } 241 }
246 return true; 242 return true;
247 } 243 }
248 244
249 // Add a receiver type check when the call can only hit 245 // Add a receiver type check when the call can only hit
250 // [noSuchMethod] if the receiver is not of a specific type. 246 // [noSuchMethod] if the receiver is not of a specific type.
251 // Return true if the receiver type check was added. 247 // Return true if the receiver type check was added.
252 bool checkReceiver(HInvokeDynamic instruction) { 248 bool checkReceiver(HInvokeDynamic instruction) {
253 assert(instruction.isInterceptedCall); 249 assert(instruction.isInterceptedCall);
254 HInstruction receiver = instruction.inputs[1]; 250 HInstruction receiver = instruction.inputs[1];
255 if (receiver.isNumber(compiler)) return false; 251 if (receiver.isNumber(compiler)) return false;
256 if (receiver.isNumberOrNull(compiler)) { 252 if (receiver.isNumberOrNull(compiler)) {
257 convertInput(instruction, 253 convertInput(
258 receiver, 254 instruction,
259 receiver.instructionType.nonNullable(), 255 receiver,
260 HTypeConversion.RECEIVER_TYPE_CHECK); 256 receiver.instructionType.nonNullable(),
257 HTypeConversion.RECEIVER_TYPE_CHECK);
261 return true; 258 return true;
262 } else if (instruction.element == null) { 259 } else if (instruction.element == null) {
263 Iterable<Element> targets = 260 Iterable<Element> targets = compiler.world.allFunctions
264 compiler.world.allFunctions.filter( 261 .filter(instruction.selector, instruction.mask);
265 instruction.selector, instruction.mask);
266 if (targets.length == 1) { 262 if (targets.length == 1) {
267 Element target = targets.first; 263 Element target = targets.first;
268 ClassElement cls = target.enclosingClass; 264 ClassElement cls = target.enclosingClass;
269 TypeMask type = new TypeMask.nonNullSubclass( 265 TypeMask type =
270 cls.declaration, classWorld); 266 new TypeMask.nonNullSubclass(cls.declaration, classWorld);
271 // TODO(ngeoffray): We currently only optimize on primitive 267 // TODO(ngeoffray): We currently only optimize on primitive
272 // types. 268 // types.
273 if (!type.satisfies(backend.helpers.jsIndexableClass, classWorld) && 269 if (!type.satisfies(backend.helpers.jsIndexableClass, classWorld) &&
274 !type.containsOnlyNum(classWorld) && 270 !type.containsOnlyNum(classWorld) &&
275 !type.containsOnlyBool(classWorld)) { 271 !type.containsOnlyBool(classWorld)) {
276 return false; 272 return false;
277 } 273 }
278 if (!isCheckEnoughForNsmOrAe(receiver, type)) return false; 274 if (!isCheckEnoughForNsmOrAe(receiver, type)) return false;
279 instruction.element = target; 275 instruction.element = target;
280 convertInput(instruction, 276 convertInput(
281 receiver, 277 instruction, receiver, type, HTypeConversion.RECEIVER_TYPE_CHECK);
282 type,
283 HTypeConversion.RECEIVER_TYPE_CHECK);
284 return true; 278 return true;
285 } 279 }
286 } 280 }
287 return false; 281 return false;
288 } 282 }
289 283
290 // Add an argument type check if the argument is not of a type 284 // Add an argument type check if the argument is not of a type
291 // expected by the call. 285 // expected by the call.
292 // Return true if the argument type check was added. 286 // Return true if the argument type check was added.
293 bool checkArgument(HInvokeDynamic instruction) { 287 bool checkArgument(HInvokeDynamic instruction) {
294 // We want the right error in checked mode. 288 // We want the right error in checked mode.
295 if (compiler.options.enableTypeAssertions) return false; 289 if (compiler.options.enableTypeAssertions) return false;
296 HInstruction left = instruction.inputs[1]; 290 HInstruction left = instruction.inputs[1];
297 HInstruction right = instruction.inputs[2]; 291 HInstruction right = instruction.inputs[2];
298 292
299 Selector selector = instruction.selector; 293 Selector selector = instruction.selector;
300 if (selector.isOperator && left.isNumber(compiler)) { 294 if (selector.isOperator && left.isNumber(compiler)) {
301 if (right.isNumber(compiler)) return false; 295 if (right.isNumber(compiler)) return false;
302 TypeMask type = right.isIntegerOrNull(compiler) 296 TypeMask type = right.isIntegerOrNull(compiler)
303 ? right.instructionType.nonNullable() 297 ? right.instructionType.nonNullable()
304 : backend.numType; 298 : backend.numType;
305 // TODO(ngeoffray): Some number operations don't have a builtin 299 // TODO(ngeoffray): Some number operations don't have a builtin
306 // variant and will do the check in their method anyway. We 300 // variant and will do the check in their method anyway. We
307 // still add a check because it allows to GVN these operations, 301 // still add a check because it allows to GVN these operations,
308 // but we should find a better way. 302 // but we should find a better way.
309 convertInput(instruction, 303 convertInput(
310 right, 304 instruction, right, type, HTypeConversion.ARGUMENT_TYPE_CHECK);
311 type,
312 HTypeConversion.ARGUMENT_TYPE_CHECK);
313 return true; 305 return true;
314 } 306 }
315 return false; 307 return false;
316 } 308 }
317 309
318 void processPendingOptimizations() { 310 void processPendingOptimizations() {
319 pendingOptimizations.forEach((instruction, action) => action()); 311 pendingOptimizations.forEach((instruction, action) => action());
320 pendingOptimizations.clear(); 312 pendingOptimizations.clear();
321 } 313 }
322 314
323 void addDependentInstructionsToWorkList(HInstruction instruction) { 315 void addDependentInstructionsToWorkList(HInstruction instruction) {
324 for (int i = 0, length = instruction.usedBy.length; i < length; i++) { 316 for (int i = 0, length = instruction.usedBy.length; i < length; i++) {
325 // The type propagator only propagates types forward. We 317 // The type propagator only propagates types forward. We
326 // thus only need to add the users of the [instruction] to the list. 318 // thus only need to add the users of the [instruction] to the list.
327 addToWorkList(instruction.usedBy[i]); 319 addToWorkList(instruction.usedBy[i]);
328 } 320 }
329 } 321 }
330 322
331 void addAllUsersBut(HInvokeDynamic invoke, HInstruction instruction) { 323 void addAllUsersBut(HInvokeDynamic invoke, HInstruction instruction) {
332 instruction.usedBy.forEach((HInstruction user) { 324 instruction.usedBy.forEach((HInstruction user) {
333 if (user != invoke) addToWorkList(user); 325 if (user != invoke) addToWorkList(user);
334 }); 326 });
335 } 327 }
336 328
337 TypeMask visitInvokeDynamic(HInvokeDynamic instruction) { 329 TypeMask visitInvokeDynamic(HInvokeDynamic instruction) {
338 if (instruction.isInterceptedCall) { 330 if (instruction.isInterceptedCall) {
339 // We cannot do the following optimization now, because we have 331 // We cannot do the following optimization now, because we have
340 // to wait for the type propagation to be stable. The receiver 332 // to wait for the type propagation to be stable. The receiver
341 // of [instruction] might move from number to dynamic. 333 // of [instruction] might move from number to dynamic.
342 pendingOptimizations.putIfAbsent(instruction, () => () { 334 pendingOptimizations.putIfAbsent(
343 Selector selector = instruction.selector; 335 instruction,
344 if (selector.isOperator && selector.name != '==') { 336 () => () {
345 if (checkReceiver(instruction)) { 337 Selector selector = instruction.selector;
346 addAllUsersBut(instruction, instruction.inputs[1]); 338 if (selector.isOperator && selector.name != '==') {
347 } 339 if (checkReceiver(instruction)) {
348 if (!selector.isUnaryOperator && 340 addAllUsersBut(instruction, instruction.inputs[1]);
349 checkArgument(instruction)) { 341 }
350 addAllUsersBut(instruction, instruction.inputs[2]); 342 if (!selector.isUnaryOperator && checkArgument(instruction)) {
351 } 343 addAllUsersBut(instruction, instruction.inputs[2]);
352 } 344 }
353 }); 345 }
346 });
354 } 347 }
355 348
356 HInstruction receiver = instruction.getDartReceiver(compiler); 349 HInstruction receiver = instruction.getDartReceiver(compiler);
357 TypeMask receiverType = receiver.instructionType; 350 TypeMask receiverType = receiver.instructionType;
358 instruction.mask = receiverType; 351 instruction.mask = receiverType;
359 352
360 // Try to specialize the receiver after this call. 353 // Try to specialize the receiver after this call.
361 if (receiver.dominatedUsers(instruction).length != 1 354 if (receiver.dominatedUsers(instruction).length != 1 &&
362 && !instruction.selector.isClosureCall) { 355 !instruction.selector.isClosureCall) {
363 TypeMask newType = compiler.world.allFunctions.receiverType( 356 TypeMask newType = compiler.world.allFunctions
364 instruction.selector, instruction.mask); 357 .receiverType(instruction.selector, instruction.mask);
365 newType = newType.intersection(receiverType, classWorld); 358 newType = newType.intersection(receiverType, classWorld);
366 var next = instruction.next; 359 var next = instruction.next;
367 if (next is HTypeKnown && next.checkedInput == receiver) { 360 if (next is HTypeKnown && next.checkedInput == receiver) {
368 // We already have refined [receiver]. We still update the 361 // We already have refined [receiver]. We still update the
369 // type of the [HTypeKnown] instruction because it may have 362 // type of the [HTypeKnown] instruction because it may have
370 // been refined with a correct type at the time, but 363 // been refined with a correct type at the time, but
371 // incorrect now. 364 // incorrect now.
372 if (next.instructionType != newType) { 365 if (next.instructionType != newType) {
373 next.knownType = next.instructionType = newType; 366 next.knownType = next.instructionType = newType;
374 addDependentInstructionsToWorkList(next); 367 addDependentInstructionsToWorkList(next);
375 } 368 }
376 } else if (newType != receiverType) { 369 } else if (newType != receiverType) {
377 // Insert a refinement node after the call and update all 370 // Insert a refinement node after the call and update all
378 // users dominated by the call to use that node instead of 371 // users dominated by the call to use that node instead of
379 // [receiver]. 372 // [receiver].
380 HTypeKnown converted = 373 HTypeKnown converted =
381 new HTypeKnown.witnessed(newType, receiver, instruction); 374 new HTypeKnown.witnessed(newType, receiver, instruction);
382 instruction.block.addBefore(instruction.next, converted); 375 instruction.block.addBefore(instruction.next, converted);
383 receiver.replaceAllUsersDominatedBy(converted.next, converted); 376 receiver.replaceAllUsersDominatedBy(converted.next, converted);
384 addDependentInstructionsToWorkList(converted); 377 addDependentInstructionsToWorkList(converted);
385 } 378 }
386 } 379 }
387 380
388 return instruction.specializer.computeTypeFromInputTypes( 381 return instruction.specializer
389 instruction, compiler); 382 .computeTypeFromInputTypes(instruction, compiler);
390 } 383 }
391 } 384 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/types.dart ('k') | pkg/compiler/lib/src/ssa/validate.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698