Changeset 34852 in webkit for trunk/JavaScriptCore
- Timestamp:
- Jun 28, 2008, 9:03:11 AM (17 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r34851 r34852 1 2008-06-28 Darin Adler <[email protected]> 2 3 Reviewed by Oliver. 4 5 - fix https://bugs.webkit.org/show_bug.cgi?id=19796 6 optimize expressions with ignored results (especially post-increment) 7 8 SunSpider says 0.9% faster. 9 10 * VM/CodeGenerator.h: 11 (KJS::CodeGenerator::tempDestination): Create a new temporary for 12 ignoredResult() too, just as we would for 0. 13 (KJS::CodeGenerator::finalDestination): Use the temporary if the 14 register passed in is ignoredResult() too, just as we would for 0. 15 (KJS::CodeGenerator::destinationForAssignResult): Return 0 if the 16 passed in register is ignoredResult(), just as we would for 0. 17 (KJS::CodeGenerator::moveToDestinationIfNeeded): Return 0 if the 18 register passed in is ignoredResult(). What matters is that we 19 don't want to emit a move. The return value won't be looked at. 20 (KJS::CodeGenerator::emitNode): Allow ignoredResult() and pass it 21 through to the node's emitCode function. 22 23 * VM/RegisterID.h: 24 (KJS::ignoredResult): Added. Special value to indicate the result of 25 a node will be ignored and need not be put in any register. 26 27 * kjs/nodes.cpp: 28 (KJS::NullNode::emitCode): Do nothing if dst == ignoredResult(). 29 (KJS::BooleanNode::emitCode): Ditto. 30 (KJS::NumberNode::emitCode): Ditto. 31 (KJS::StringNode::emitCode): Ditto. 32 (KJS::RegExpNode::emitCode): Ditto. 33 (KJS::ThisNode::emitCode): Ditto. 34 (KJS::ResolveNode::emitCode): Do nothing if dst == ignoredResult() and 35 the identifier resolves to a local variable. 36 (KJS::ObjectLiteralNode::emitCode): Do nothing if dst == ignoredResult() 37 and the object is empty. 38 (KJS::PostIncResolveNode::emitCode): If dst == ignoredResult(), then do 39 nothing for the local constant case, and do a pre-increment in all the 40 other cases. 41 (KJS::PostDecResolveNode::emitCode): Ditto. 42 (KJS::PostIncBracketNode::emitCode): Ditto. 43 (KJS::PostDecBracketNode::emitCode): Ditto. 44 (KJS::PostIncDotNode::emitCode): Ditto. 45 (KJS::PostDecDotNode::emitCode): Ditto. 46 (KJS::DeleteValueNode::emitCode): Pass ignoredResult() when evaluating 47 the expression. 48 (KJS::VoidNode::emitCode): Ditto. 49 (KJS::TypeOfResolveNode::emitCode): If dst == ignoredResult(), do nothing 50 if the identifier resolves to a local variable, and don't bother generating 51 a typeof opcode in the other case. 52 (KJS::TypeOfValueNode::emitCode): Ditto. 53 (KJS::PreIncResolveNode::emitCode): Do nothing if dst == ignoredResult() and 54 the identifier resolves to a local constant. 55 (KJS::PreDecResolveNode::emitCode): Ditto. 56 (KJS::AssignResolveNode::emitCode): Turn ignoredResult() into 0 in a couple 57 places, because we need to put the result into a register so we can assign 58 it. At other sites this is taken care of by functions like finalDestination. 59 (KJS::CommaNode::emitCode): Pass ignoredResult() when evaluating the first 60 expression. 61 (KJS::ForNode::emitCode): Pass ignoredResult() when evaluating the first and 62 third expressions. 63 (KJS::ForInNode::emitCode): Pass ignoredResult() when evaluating the first 64 expression. 65 1 66 2008-06-28 Darin Adler <[email protected]> 2 67 -
trunk/JavaScriptCore/VM/CodeGenerator.h
r34851 r34852 129 129 // Functions for handling of dst register 130 130 131 // Returns 131 // Returns a place to write intermediate values of an operation 132 132 // which reuses dst if it is safe to do so. 133 134 RegisterID* tempDestination(RegisterID* dst) { return (dst && dst->isTemporary()) ? dst : newTemporary(); } 133 RegisterID* tempDestination(RegisterID* dst) 134 { 135 return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); 136 } 135 137 136 138 // Returns the place to write the final output of an operation. 137 139 RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) 138 140 { 139 if (originalDst )141 if (originalDst && originalDst != ignoredResult()) 140 142 return originalDst; 143 ASSERT(tempDst != ignoredResult()); 141 144 if (tempDst && tempDst->isTemporary()) 142 145 return tempDst; … … 146 149 RegisterID* destinationForAssignResult(RegisterID* dst) 147 150 { 148 if (dst && m_codeBlock->needsFullScopeChain)151 if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain) 149 152 return dst->isTemporary() ? dst : newTemporary(); 150 153 return 0; 151 154 } 152 155 153 // moves src to dst if dst is not null and is different from src, otherwise just returns src 154 RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) { return (dst && dst != src) ? emitMove(dst, src) : src; } 156 // Moves src to dst if dst is not null and is different from src, otherwise just returns src. 157 RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) 158 { 159 return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; 160 } 155 161 156 162 PassRefPtr<LabelID> newLabel(); 157 163 158 164 // The emitNode functions are just syntactic sugar for calling 159 // Node::emitCode. They're the only functions that accept a NULL register. 165 // Node::emitCode. These functions accept a 0 for the register, 166 // meaning that the node should allocate a register, or ignoredResult(), 167 // meaning that the node need not put the result in a register. 168 // Other emit functions do not accept 0 or ignoredResult(). 160 169 RegisterID* emitNode(RegisterID* dst, Node* n) 161 170 { 162 171 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. 163 ASSERT(!dst || !dst->isTemporary() || dst->refCount());172 ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); 164 173 if (!m_codeBlock->lineInfo.size() || m_codeBlock->lineInfo.last().lineNumber != n->lineNo()) { 165 174 LineInfo info = { instructions().size(), n->lineNo() }; -
trunk/JavaScriptCore/VM/RegisterID.h
r34372 r34852 100 100 }; 101 101 102 inline RegisterID* ignoredResult() { return reinterpret_cast<RegisterID*>(1); } 103 102 104 } // namespace KJS 103 105 104 106 namespace WTF { 105 107 106 template<> struct VectorTraits<KJS::RegisterID> : VectorTraitsBase<true, KJS::RegisterID> 107 { 108 template<> struct VectorTraits<KJS::RegisterID> : VectorTraitsBase<true, KJS::RegisterID> { 108 109 static const bool needsInitialization = true; 109 110 static const bool canInitializeWithMemset = true; // Default initialization just sets everything to 0 or false, so this is safe. -
trunk/JavaScriptCore/kjs/nodes.cpp
r34851 r34852 272 272 RegisterID* NullNode::emitCode(CodeGenerator& generator, RegisterID* dst) 273 273 { 274 if (dst == ignoredResult()) 275 return 0; 274 276 return generator.emitLoad(generator.finalDestination(dst), jsNull()); 275 277 } … … 279 281 RegisterID* BooleanNode::emitCode(CodeGenerator& generator, RegisterID* dst) 280 282 { 283 if (dst == ignoredResult()) 284 return 0; 281 285 return generator.emitLoad(generator.finalDestination(dst), m_value); 282 286 } … … 286 290 RegisterID* NumberNode::emitCode(CodeGenerator& generator, RegisterID* dst) 287 291 { 292 if (dst == ignoredResult()) 293 return 0; 288 294 return generator.emitLoad(generator.finalDestination(dst), m_double); 289 295 } … … 293 299 RegisterID* StringNode::emitCode(CodeGenerator& generator, RegisterID* dst) 294 300 { 301 if (dst == ignoredResult()) 302 return 0; 295 303 // FIXME: should we try to atomize constant strings? 296 304 return generator.emitLoad(generator.finalDestination(dst), jsOwnedString(generator.globalExec(), m_value)); … … 303 311 if (!m_regExp->isValid()) 304 312 return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(m_regExp->errorMessage())).UTF8String().c_str()); 313 if (dst == ignoredResult()) 314 return 0; 305 315 return generator.emitNewRegExp(generator.finalDestination(dst), m_regExp.get()); 306 316 } … … 310 320 RegisterID* ThisNode::emitCode(CodeGenerator& generator, RegisterID* dst) 311 321 { 322 if (dst == ignoredResult()) 323 return 0; 312 324 return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); 313 325 } … … 322 334 RegisterID* ResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) 323 335 { 324 if (RegisterID* local = generator.registerForLocal(m_ident)) 336 if (RegisterID* local = generator.registerForLocal(m_ident)) { 337 if (dst == ignoredResult()) 338 return 0; 325 339 return generator.moveToDestinationIfNeeded(dst, local); 340 } 326 341 327 342 return generator.emitResolve(generator.finalDestination(dst), m_ident); … … 365 380 RegisterID* ObjectLiteralNode::emitCode(CodeGenerator& generator, RegisterID* dst) 366 381 { 367 if (m_list) 368 return generator.emitNode(dst, m_list.get()); 369 return generator.emitNewObject(generator.finalDestination(dst)); 382 if (!m_list) { 383 if (dst == ignoredResult()) 384 return 0; 385 return generator.emitNewObject(generator.finalDestination(dst)); 386 } 387 return generator.emitNode(dst, m_list.get()); 370 388 } 371 389 … … 487 505 RegisterID* PostIncResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) 488 506 { 489 // FIXME: I think we can detect the absense of dependent expressions here,490 // and emit a PreInc instead of a PostInc. A post-pass to eliminate dead491 // code would work, too.492 507 if (RegisterID* local = generator.registerForLocal(m_ident)) { 493 if (generator.isLocalConstant(m_ident)) 508 if (generator.isLocalConstant(m_ident)) { 509 if (dst == ignoredResult()) 510 return 0; 494 511 return generator.emitToJSNumber(generator.finalDestination(dst), local); 495 512 } 513 514 if (dst == ignoredResult()) 515 return generator.emitPreInc(local); 496 516 return generator.emitPostInc(generator.finalDestination(dst), local); 497 517 } … … 501 521 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) { 502 522 RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index); 503 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 523 RegisterID* oldValue; 524 if (dst == ignoredResult()) { 525 oldValue = 0; 526 generator.emitPreInc(value.get()); 527 } else { 528 oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 529 } 504 530 generator.emitPutScopedVar(depth, index, value.get()); 505 531 return oldValue; … … 508 534 RefPtr<RegisterID> value = generator.newTemporary(); 509 535 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); 510 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 536 RegisterID* oldValue; 537 if (dst == ignoredResult()) { 538 oldValue = 0; 539 generator.emitPreInc(value.get()); 540 } else { 541 oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 542 } 511 543 generator.emitPutById(base.get(), m_ident, value.get()); 512 544 return oldValue; … … 515 547 RegisterID* PostDecResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) 516 548 { 517 // FIXME: I think we can detect the absense of dependent expressions here,518 // and emit a PreDec instead of a PostDec. A post-pass to eliminate dead519 // code would work, too.520 549 if (RegisterID* local = generator.registerForLocal(m_ident)) { 521 if (generator.isLocalConstant(m_ident)) 550 if (generator.isLocalConstant(m_ident)) { 551 if (dst == ignoredResult()) 552 return 0; 522 553 return generator.emitToJSNumber(generator.finalDestination(dst), local); 523 554 } 555 556 if (dst == ignoredResult()) 557 return generator.emitPreDec(local); 524 558 return generator.emitPostDec(generator.finalDestination(dst), local); 525 559 } … … 529 563 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) { 530 564 RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index); 531 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 565 RegisterID* oldValue; 566 if (dst == ignoredResult()) { 567 oldValue = 0; 568 generator.emitPreDec(value.get()); 569 } else { 570 oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 571 } 532 572 generator.emitPutScopedVar(depth, index, value.get()); 533 573 return oldValue; … … 536 576 RefPtr<RegisterID> value = generator.newTemporary(); 537 577 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); 538 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 578 RegisterID* oldValue; 579 if (dst == ignoredResult()) { 580 oldValue = 0; 581 generator.emitPreDec(value.get()); 582 } else { 583 oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 584 } 539 585 generator.emitPutById(base.get(), m_ident, value.get()); 540 586 return oldValue; … … 548 594 RefPtr<RegisterID> property = generator.emitNode(m_subscript.get()); 549 595 RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); 550 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 596 RegisterID* oldValue; 597 if (dst == ignoredResult()) { 598 oldValue = 0; 599 generator.emitPreInc(value.get()); 600 } else { 601 oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 602 } 551 603 generator.emitPutByVal(base.get(), property.get(), value.get()); 552 604 return oldValue; … … 558 610 RefPtr<RegisterID> property = generator.emitNode(m_subscript.get()); 559 611 RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); 560 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 612 RegisterID* oldValue; 613 if (dst == ignoredResult()) { 614 oldValue = 0; 615 generator.emitPreDec(value.get()); 616 } else { 617 oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 618 } 561 619 generator.emitPutByVal(base.get(), property.get(), value.get()); 562 620 return oldValue; … … 569 627 RefPtr<RegisterID> base = generator.emitNode(m_base.get()); 570 628 RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); 571 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 629 RegisterID* oldValue; 630 if (dst == ignoredResult()) { 631 oldValue = 0; 632 generator.emitPreInc(value.get()); 633 } else { 634 oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get()); 635 } 572 636 generator.emitPutById(base.get(), m_ident, value.get()); 573 637 return oldValue; … … 578 642 RefPtr<RegisterID> base = generator.emitNode(m_base.get()); 579 643 RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); 580 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 644 RegisterID* oldValue; 645 if (dst == ignoredResult()) { 646 oldValue = 0; 647 generator.emitPreDec(value.get()); 648 } else { 649 oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get()); 650 } 581 651 generator.emitPutById(base.get(), m_ident, value.get()); 582 652 return oldValue; … … 622 692 RegisterID* DeleteValueNode::emitCode(CodeGenerator& generator, RegisterID* dst) 623 693 { 624 generator.emitNode( m_expr.get());694 generator.emitNode(ignoredResult(), m_expr.get()); 625 695 626 696 // delete on a non-location expression ignores the value and returns true … … 632 702 RegisterID* VoidNode::emitCode(CodeGenerator& generator, RegisterID* dst) 633 703 { 704 if (dst == ignoredResult()) { 705 generator.emitNode(ignoredResult(), m_expr.get()); 706 return 0; 707 } 634 708 RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get()); 635 709 return generator.emitLoad(generator.finalDestination(dst, r0.get()), jsUndefined()); … … 640 714 RegisterID* TypeOfResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) 641 715 { 642 if (RegisterID* local = generator.registerForLocal(m_ident)) 716 if (RegisterID* local = generator.registerForLocal(m_ident)) { 717 if (dst == ignoredResult()) 718 return 0; 643 719 return generator.emitTypeOf(generator.finalDestination(dst), local); 720 } 644 721 645 722 RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); 646 723 generator.emitGetById(scratch.get(), scratch.get(), m_ident); 724 if (dst == ignoredResult()) 725 return 0; 647 726 return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); 648 727 } … … 652 731 RegisterID* TypeOfValueNode::emitCode(CodeGenerator& generator, RegisterID* dst) 653 732 { 733 if (dst == ignoredResult()) { 734 generator.emitNode(ignoredResult(), m_expr.get()); 735 return 0; 736 } 654 737 RefPtr<RegisterID> src = generator.emitNode(m_expr.get()); 655 738 return generator.emitTypeOf(generator.finalDestination(dst), src.get()); … … 662 745 if (RegisterID* local = generator.registerForLocal(m_ident)) { 663 746 if (generator.isLocalConstant(m_ident)) { 747 if (dst == ignoredResult()) 748 return 0; 664 749 RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), 1.0); 665 750 return generator.emitBinaryOp(op_add, r0.get(), local, r0.get()); 666 751 } 667 752 668 753 generator.emitPreInc(local); 669 754 return generator.moveToDestinationIfNeeded(dst, local); … … 690 775 if (RegisterID* local = generator.registerForLocal(m_ident)) { 691 776 if (generator.isLocalConstant(m_ident)) { 777 if (dst == ignoredResult()) 778 return 0; 692 779 RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), -1.0); 693 780 return generator.emitBinaryOp(op_add, r0.get(), local, r0.get()); … … 944 1031 size_t depth = 0; 945 1032 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) { 1033 if (dst == ignoredResult()) 1034 dst = 0; 946 1035 RegisterID* value = generator.emitNode(dst, m_right.get()); 947 1036 generator.emitPutScopedVar(depth, index, value); … … 950 1039 951 1040 RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); 1041 if (dst == ignoredResult()) 1042 dst = 0; 952 1043 RegisterID* value = generator.emitNode(dst, m_right.get()); 953 1044 return generator.emitPutById(base.get(), m_ident, value); … … 1013 1104 RegisterID* CommaNode::emitCode(CodeGenerator& generator, RegisterID* dst) 1014 1105 { 1015 generator.emitNode( m_expr1.get());1106 generator.emitNode(ignoredResult(), m_expr1.get()); 1016 1107 return generator.emitNode(dst, m_expr2.get()); 1017 1108 } … … 1234 1325 { 1235 1326 if (m_expr1) 1236 generator.emitNode( m_expr1.get());1327 generator.emitNode(ignoredResult(), m_expr1.get()); 1237 1328 1238 1329 RefPtr<LabelID> topOfLoop = generator.newLabel(); … … 1248 1339 generator.emitLabel(continueTarget.get()); 1249 1340 if (m_expr3) 1250 generator.emitNode( m_expr3.get());1341 generator.emitNode(ignoredResult(), m_expr3.get()); 1251 1342 1252 1343 generator.emitLabel(beforeCondition.get()); … … 1282 1373 { 1283 1374 if (in) 1284 m_init = new AssignResolveNode(globalData, ident, in, true);1375 m_init = new AssignResolveNode(globalData, ident, in, true); 1285 1376 // for( var foo = bar in baz ) 1286 1377 } … … 1293 1384 1294 1385 if (m_init) 1295 generator.emitNode( m_init.get());1386 generator.emitNode(ignoredResult(), m_init.get()); 1296 1387 RegisterID* forInBase = generator.emitNode(m_expr.get()); 1297 1388 RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase);
Note:
See TracChangeset
for help on using the changeset viewer.