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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/optimize.dart

Issue 12042003: Move relational operators to the new interceptors. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 11 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 | Annotate | Revision Log
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 part of ssa; 5 part of ssa;
6 6
7 abstract class OptimizationPhase { 7 abstract class OptimizationPhase {
8 String get name; 8 String get name;
9 void visitGraph(HGraph graph); 9 void visitGraph(HGraph graph);
10 } 10 }
(...skipping 23 matching lines...) Expand all
34 JavaScriptItemCompilationContext context = work.compilationContext; 34 JavaScriptItemCompilationContext context = work.compilationContext;
35 HTypeMap types = context.types; 35 HTypeMap types = context.types;
36 measure(() { 36 measure(() {
37 List<OptimizationPhase> phases = <OptimizationPhase>[ 37 List<OptimizationPhase> phases = <OptimizationPhase>[
38 // Run trivial constant folding first to optimize 38 // Run trivial constant folding first to optimize
39 // some patterns useful for type conversion. 39 // some patterns useful for type conversion.
40 new SsaConstantFolder(constantSystem, backend, work, types), 40 new SsaConstantFolder(constantSystem, backend, work, types),
41 new SsaTypeConversionInserter(compiler), 41 new SsaTypeConversionInserter(compiler),
42 new SsaTypePropagator(compiler, types), 42 new SsaTypePropagator(compiler, types),
43 new SsaConstantFolder(constantSystem, backend, work, types), 43 new SsaConstantFolder(constantSystem, backend, work, types),
44 // The constant folder affects the types of instructions, so
45 // we run the type propagator again. Note that this would
46 // not be necessary if types were directly stored on
47 // instructions.
48 new SsaTypePropagator(compiler, types),
44 new SsaCheckInserter(backend, work, types, context.boundsChecked), 49 new SsaCheckInserter(backend, work, types, context.boundsChecked),
45 new SsaRedundantPhiEliminator(), 50 new SsaRedundantPhiEliminator(),
46 new SsaDeadPhiEliminator(), 51 new SsaDeadPhiEliminator(),
47 new SsaConstantFolder(constantSystem, backend, work, types), 52 new SsaConstantFolder(constantSystem, backend, work, types),
48 new SsaTypePropagator(compiler, types), 53 new SsaTypePropagator(compiler, types),
49 new SsaReceiverSpecialization(compiler), 54 new SsaReceiverSpecialization(compiler),
50 new SsaGlobalValueNumberer(compiler, types), 55 new SsaGlobalValueNumberer(compiler, types),
51 new SsaCodeMotion(), 56 new SsaCodeMotion(),
52 new SsaValueRangeAnalyzer(constantSystem, types, work), 57 new SsaValueRangeAnalyzer(constantSystem, types, work),
53 // Previous optimizations may have generated new 58 // Previous optimizations may have generated new
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 } 218 }
214 return null; 219 return null;
215 } 220 }
216 221
217 HInstruction handleInterceptorCall(HInvokeDynamicMethod node) { 222 HInstruction handleInterceptorCall(HInvokeDynamicMethod node) {
218 HInstruction input = node.inputs[1]; 223 HInstruction input = node.inputs[1];
219 if (input.isString(types) 224 if (input.isString(types)
220 && node.selector.name == const SourceString('toString')) { 225 && node.selector.name == const SourceString('toString')) {
221 return node.inputs[1]; 226 return node.inputs[1];
222 } 227 }
223 // Check if this call does not need to be intercepted.
224 HType type = types[input];
225 var interceptor = node.inputs[0];
226 if (interceptor is !HThis && !type.canBePrimitive()) {
227 // If the type can be null, and the intercepted method can be in
228 // the object class, keep the interceptor.
229 if (type.canBeNull()
230 && interceptor.interceptedClasses.contains(compiler.objectClass)) {
231 return node;
232 }
233 // Change the call to a regular invoke dynamic call.
234 return new HInvokeDynamicMethod(
235 node.selector, node.inputs.getRange(1, node.inputs.length - 1));
236 }
237 228
238 // Try constant folding the instruction. 229 // Try constant folding the instruction.
239 Operation operation = node.specializer.operation(constantSystem); 230 Operation operation = node.specializer.operation(constantSystem);
240 if (operation != null) { 231 if (operation != null) {
241 HInstruction instruction = node.inputs.length == 2 232 HInstruction instruction = node.inputs.length == 2
242 ? foldUnary(operation, node.inputs[1]) 233 ? foldUnary(operation, node.inputs[1])
243 : foldBinary(operation, node.inputs[1], node.inputs[2]); 234 : foldBinary(operation, node.inputs[1], node.inputs[2]);
244 if (instruction != null) return instruction; 235 if (instruction != null) return instruction;
245 } 236 }
246 237
247 // Try converting the instruction to a builtin instruction. 238 // Try converting the instruction to a builtin instruction.
248 HInstruction instruction = 239 HInstruction instruction =
249 node.specializer.tryConvertToBuiltin(node, types); 240 node.specializer.tryConvertToBuiltin(node, types);
250 if (instruction != null) return instruction; 241 if (instruction != null) return instruction;
251 242
243 // Check if this call does not need to be intercepted.
244 HType type = types[input];
245 var interceptor = node.inputs[0];
246 if (interceptor is !HThis && !type.canBePrimitive()) {
247 // If the type can be null, and the intercepted method can be in
248 // the object class, keep the interceptor.
249 if (type.canBeNull()
250 && interceptor.interceptedClasses.contains(compiler.objectClass)) {
251 return node;
252 }
253 // Change the call to a regular invoke dynamic call.
254 return new HInvokeDynamicMethod(
255 node.selector, node.inputs.getRange(1, node.inputs.length - 1));
256 }
257
252 Selector selector = node.selector; 258 Selector selector = node.selector;
253 SourceString selectorName = selector.name; 259 SourceString selectorName = selector.name;
254 Element target; 260 Element target;
255 if (input.isExtendableArray(types)) { 261 if (input.isExtendableArray(types)) {
256 if (selectorName == backend.jsArrayRemoveLast.name 262 if (selectorName == backend.jsArrayRemoveLast.name
257 && selector.argumentCount == 0) { 263 && selector.argumentCount == 0) {
258 target = backend.jsArrayRemoveLast; 264 target = backend.jsArrayRemoveLast;
259 } else if (selectorName == backend.jsArrayAdd.name 265 } else if (selectorName == backend.jsArrayAdd.name
260 && selector.argumentCount == 1 266 && selector.argumentCount == 1
261 && selector.namedArgumentCount == 0 267 && selector.namedArgumentCount == 0
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 } 383 }
378 return null; 384 return null;
379 } 385 }
380 386
381 HInstruction visitInvokeBinary(HInvokeBinary node) { 387 HInstruction visitInvokeBinary(HInvokeBinary node) {
382 HInstruction left = node.left; 388 HInstruction left = node.left;
383 HInstruction right = node.right; 389 HInstruction right = node.right;
384 BinaryOperation operation = node.operation(constantSystem); 390 BinaryOperation operation = node.operation(constantSystem);
385 HConstant folded = foldBinary(operation, left, right); 391 HConstant folded = foldBinary(operation, left, right);
386 if (folded != null) return folded; 392 if (folded != null) return folded;
387
388 if (!left.canBePrimitive(types)
389 && operation.isUserDefinable()
390 // The equals operation is being optimized in visitEquals.
391 && node is! HEquals) {
392 Selector selector = new Selector.binaryOperator(operation.name);
393 return fromPrimitiveInstructionToDynamicInvocation(node, selector);
394 }
395 return node; 393 return node;
396 } 394 }
397 395
398 bool allUsersAreBoolifies(HInstruction instruction) { 396 bool allUsersAreBoolifies(HInstruction instruction) {
399 List<HInstruction> users = instruction.usedBy; 397 List<HInstruction> users = instruction.usedBy;
400 int length = users.length; 398 int length = users.length;
401 for (int i = 0; i < length; i++) { 399 for (int i = 0; i < length; i++) {
402 if (users[i] is! HBoolify) return false; 400 if (users[i] is! HBoolify) return false;
403 } 401 }
404 return true; 402 return true;
405 } 403 }
406 404
407 HInstruction visitRelational(HRelational node) { 405 HInstruction visitRelational(HRelational node) {
408 if (allUsersAreBoolifies(node)) { 406 if (allUsersAreBoolifies(node)) {
409 Interceptors interceptors = backend.builder.interceptors; 407 Interceptors interceptors = backend.builder.interceptors;
410 HStatic oldTarget = node.target;
411 Element boolifiedInterceptor =
412 interceptors.getBoolifiedVersionOf(oldTarget.element);
413 if (boolifiedInterceptor != null) {
414 HStatic boolifiedTarget = new HStatic(boolifiedInterceptor);
415 // We don't remove the [oldTarget] in case it is used by other
416 // instructions. If it is unused it will be treated as dead code and
417 // discarded.
418 oldTarget.block.addAfter(oldTarget, boolifiedTarget);
419 // Remove us as user from the [oldTarget].
420 oldTarget.removeUser(node);
421 // Replace old target with boolified target.
422 assert(node.target == node.inputs[0]);
423 node.inputs[0] = boolifiedTarget;
424 boolifiedTarget.usedBy.add(node);
425 node.usesBoolifiedInterceptor = true;
426 types[node] = HType.BOOLEAN;
427 }
428 // This node stays the same, but the Boolify node will go away. 408 // This node stays the same, but the Boolify node will go away.
429 } 409 }
430 // Note that we still have to call [super] to make sure that we end up 410 // Note that we still have to call [super] to make sure that we end up
431 // in the remaining optimizations. 411 // in the remaining optimizations.
432 return super.visitRelational(node); 412 return super.visitRelational(node);
433 } 413 }
434 414
435 HInstruction handleIdentityCheck(HRelational node) { 415 HInstruction handleIdentityCheck(HRelational node) {
436 HInstruction left = node.left; 416 HInstruction left = node.left;
437 HInstruction right = node.right; 417 HInstruction right = node.right;
(...skipping 25 matching lines...) Expand all
463 } 443 }
464 444
465 return null; 445 return null;
466 } 446 }
467 447
468 HInstruction visitIdentity(HIdentity node) { 448 HInstruction visitIdentity(HIdentity node) {
469 HInstruction newInstruction = handleIdentityCheck(node); 449 HInstruction newInstruction = handleIdentityCheck(node);
470 return newInstruction == null ? super.visitIdentity(node) : newInstruction; 450 return newInstruction == null ? super.visitIdentity(node) : newInstruction;
471 } 451 }
472 452
473 HInstruction foldBuiltinEqualsCheck(HEquals node) {
474 // TODO(floitsch): cache interceptors.
475 HInstruction newInstruction = handleIdentityCheck(node);
476 if (newInstruction == null) {
477 HStatic target = new HStatic(
478 backend.builder.interceptors.getTripleEqualsInterceptor());
479 node.block.addBefore(node, target);
480 return new HIdentity(target, node.left, node.right);
481 } else {
482 return newInstruction;
483 }
484 }
485
486 HInstruction visitEquals(HEquals node) {
487 HInstruction left = node.left;
488 HInstruction right = node.right;
489
490 if (node.isBuiltin(types)) {
491 return foldBuiltinEqualsCheck(node);
492 }
493
494 if (left.isConstant() && right.isConstant()) {
495 return super.visitEquals(node);
496 }
497
498 HType leftType = types[left];
499 if (leftType.isExact()) {
500 HBoundedType type = leftType;
501 Element element = type.lookupMember(const SourceString('=='));
502 if (element != null) {
503 // If the left-hand side is guaranteed to be a non-primitive
504 // type and and it defines operator==, we emit a call to that
505 // operator.
506 return super.visitEquals(node);
507 } else if (right.isConstantNull()) {
508 return graph.addConstantBool(false, constantSystem);
509 } else {
510 // We can just emit an identity check because the type does
511 // not implement operator=.
512 return foldBuiltinEqualsCheck(node);
513 }
514 }
515
516 if (right.isConstantNull()) {
517 if (leftType.isPrimitive()) {
518 return graph.addConstantBool(false, constantSystem);
519 }
520 }
521
522 // All other cases are dealt with by the [visitRelational] and
523 // [visitInvokeBinary], which are visited by invoking the [super]'s
524 // visit method.
525 return super.visitEquals(node);
526 }
527
528 HInstruction visitTypeGuard(HTypeGuard node) { 453 HInstruction visitTypeGuard(HTypeGuard node) {
529 HInstruction value = node.guarded; 454 HInstruction value = node.guarded;
530 // If the intersection of the types is still the incoming type then 455 // If the intersection of the types is still the incoming type then
531 // the incoming type was a subtype of the guarded type, and no check 456 // the incoming type was a subtype of the guarded type, and no check
532 // is required. 457 // is required.
533 HType combinedType = types[value].intersection(node.guardedType, compiler); 458 HType combinedType = types[value].intersection(node.guardedType, compiler);
534 return (combinedType == types[value]) ? value : node; 459 return (combinedType == types[value]) ? value : node;
535 } 460 }
536 461
537 HInstruction visitIs(HIs node) { 462 HInstruction visitIs(HIs node) {
(...skipping 978 matching lines...) Expand 10 before | Expand all | Expand 10 after
1516 || otherIntercepted.contains(backend.jsDoubleClass)) { 1441 || otherIntercepted.contains(backend.jsDoubleClass)) {
1517 interceptor.interceptedClasses.addAll(user.interceptedClasses); 1442 interceptor.interceptedClasses.addAll(user.interceptedClasses);
1518 } 1443 }
1519 user.interceptedClasses = interceptor.interceptedClasses; 1444 user.interceptedClasses = interceptor.interceptedClasses;
1520 } 1445 }
1521 } 1446 }
1522 } 1447 }
1523 1448
1524 // TODO(ngeoffray): Also implement it for non-intercepted calls. 1449 // TODO(ngeoffray): Also implement it for non-intercepted calls.
1525 } 1450 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698