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

Side by Side Diff: src/compiler.cc

Issue 340005: In the toplevel compiler, shift the responsibility of assigning a... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 1 month 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
« no previous file with comments | « src/ast.cc ('k') | src/ia32/fast-codegen-ia32.cc » ('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 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 28 matching lines...) Expand all
39 #include "usage-analyzer.h" 39 #include "usage-analyzer.h"
40 40
41 namespace v8 { 41 namespace v8 {
42 namespace internal { 42 namespace internal {
43 43
44 44
45 class CodeGenSelector: public AstVisitor { 45 class CodeGenSelector: public AstVisitor {
46 public: 46 public:
47 enum CodeGenTag { NORMAL, FAST }; 47 enum CodeGenTag { NORMAL, FAST };
48 48
49 CodeGenSelector() : has_supported_syntax_(true) {} 49 CodeGenSelector()
50 : has_supported_syntax_(true),
51 location_(Location::Nowhere()) {
fschneider 2009/10/28 10:06:01 I'm not sure: Should this match the default locati
Kevin Millikin (Chromium) 2009/10/28 11:39:38 Possibly. I wanted it to be nowhere when not insi
52 }
50 53
51 CodeGenTag Select(FunctionLiteral* fun); 54 CodeGenTag Select(FunctionLiteral* fun);
52 55
53 private: 56 private:
54 void VisitDeclarations(ZoneList<Declaration*>* decls); 57 void VisitDeclarations(ZoneList<Declaration*>* decls);
55 void VisitStatements(ZoneList<Statement*>* stmts); 58 void VisitStatements(ZoneList<Statement*>* stmts);
56 59
60 // Visit an expression in effect context with a desired location of
61 // nowhere.
62 void VisitAsEffect(Expression* expr);
63
64 // Visit an expression in value context with a desired location of
65 // temporary.
66 void VisitAsValue(Expression* expr);
67
57 // AST node visit functions. 68 // AST node visit functions.
58 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); 69 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
59 AST_NODE_LIST(DECLARE_VISIT) 70 AST_NODE_LIST(DECLARE_VISIT)
60 #undef DECLARE_VISIT 71 #undef DECLARE_VISIT
61 72
62 bool has_supported_syntax_; 73 bool has_supported_syntax_;
63 74
75 // The desired location of the currently visited expression.
76 Location location_;
77
64 DISALLOW_COPY_AND_ASSIGN(CodeGenSelector); 78 DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
65 }; 79 };
66 80
67 81
68 static Handle<Code> MakeCode(FunctionLiteral* literal, 82 static Handle<Code> MakeCode(FunctionLiteral* literal,
69 Handle<Script> script, 83 Handle<Script> script,
70 Handle<Context> context, 84 Handle<Context> context,
71 bool is_eval) { 85 bool is_eval) {
72 ASSERT(literal != NULL); 86 ASSERT(literal != NULL);
73 87
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 506
493 507
494 void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) { 508 void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
495 for (int i = 0, len = stmts->length(); i < len; i++) { 509 for (int i = 0, len = stmts->length(); i < len; i++) {
496 Visit(stmts->at(i)); 510 Visit(stmts->at(i));
497 CHECK_BAILOUT; 511 CHECK_BAILOUT;
498 } 512 }
499 } 513 }
500 514
501 515
516 void CodeGenSelector::VisitAsEffect(Expression* expr) {
517 if (location_.is_nowhere()) {
518 Visit(expr);
519 } else {
520 Location saved = location_;
521 location_ = Location::Nowhere();
522 Visit(expr);
523 location_ = saved;
524 }
525 }
526
527
528 void CodeGenSelector::VisitAsValue(Expression* expr) {
529 if (location_.is_temporary()) {
530 Visit(expr);
531 } else {
532 Location saved = location_;
533 location_ = Location::Temporary();
534 Visit(expr);
535 location_ = saved;
536 }
537 }
538
539
502 void CodeGenSelector::VisitDeclaration(Declaration* decl) { 540 void CodeGenSelector::VisitDeclaration(Declaration* decl) {
503 Variable* var = decl->proxy()->var(); 541 Variable* var = decl->proxy()->var();
504 if (!var->is_global() || var->mode() == Variable::CONST) { 542 if (!var->is_global() || var->mode() == Variable::CONST) {
505 BAILOUT("Non-global declaration"); 543 BAILOUT("Non-global declaration");
506 } 544 }
507 } 545 }
508 546
509 547
510 void CodeGenSelector::VisitBlock(Block* stmt) { 548 void CodeGenSelector::VisitBlock(Block* stmt) {
511 VisitStatements(stmt->statements()); 549 VisitStatements(stmt->statements());
512 } 550 }
513 551
514 552
515 void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) { 553 void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
516 Expression* expr = stmt->expression(); 554 VisitAsEffect(stmt->expression());
517 Visit(expr);
518 CHECK_BAILOUT;
519 expr->set_location(Location::Nowhere());
520 } 555 }
521 556
522 557
523 void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) { 558 void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) {
524 // EmptyStatement is supported. 559 // EmptyStatement is supported.
525 } 560 }
526 561
527 562
528 void CodeGenSelector::VisitIfStatement(IfStatement* stmt) { 563 void CodeGenSelector::VisitIfStatement(IfStatement* stmt) {
529 BAILOUT("IfStatement"); 564 BAILOUT("IfStatement");
530 } 565 }
531 566
532 567
533 void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) { 568 void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {
534 BAILOUT("ContinueStatement"); 569 BAILOUT("ContinueStatement");
535 } 570 }
536 571
537 572
538 void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) { 573 void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {
539 BAILOUT("BreakStatement"); 574 BAILOUT("BreakStatement");
540 } 575 }
541 576
542 577
543 void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) { 578 void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
544 Visit(stmt->expression()); 579 VisitAsValue(stmt->expression());
545 } 580 }
546 581
547 582
548 void CodeGenSelector::VisitWithEnterStatement(WithEnterStatement* stmt) { 583 void CodeGenSelector::VisitWithEnterStatement(WithEnterStatement* stmt) {
549 BAILOUT("WithEnterStatement"); 584 BAILOUT("WithEnterStatement");
550 } 585 }
551 586
552 587
553 void CodeGenSelector::VisitWithExitStatement(WithExitStatement* stmt) { 588 void CodeGenSelector::VisitWithExitStatement(WithExitStatement* stmt) {
554 BAILOUT("WithExitStatement"); 589 BAILOUT("WithExitStatement");
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 627
593 void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) { 628 void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {
594 BAILOUT("DebuggerStatement"); 629 BAILOUT("DebuggerStatement");
595 } 630 }
596 631
597 632
598 void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) { 633 void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {
599 if (!expr->AllowsLazyCompilation()) { 634 if (!expr->AllowsLazyCompilation()) {
600 BAILOUT("FunctionLiteral does not allow lazy compilation"); 635 BAILOUT("FunctionLiteral does not allow lazy compilation");
601 } 636 }
637 expr->set_location(location_);
602 } 638 }
603 639
604 640
605 void CodeGenSelector::VisitFunctionBoilerplateLiteral( 641 void CodeGenSelector::VisitFunctionBoilerplateLiteral(
606 FunctionBoilerplateLiteral* expr) { 642 FunctionBoilerplateLiteral* expr) {
607 BAILOUT("FunctionBoilerplateLiteral"); 643 BAILOUT("FunctionBoilerplateLiteral");
608 } 644 }
609 645
610 646
611 void CodeGenSelector::VisitConditional(Conditional* expr) { 647 void CodeGenSelector::VisitConditional(Conditional* expr) {
612 BAILOUT("Conditional"); 648 BAILOUT("Conditional");
613 } 649 }
614 650
615 651
616 void CodeGenSelector::VisitSlot(Slot* expr) { 652 void CodeGenSelector::VisitSlot(Slot* expr) {
617 Slot::Type type = expr->type(); 653 UNREACHABLE();
618 if (type != Slot::PARAMETER && type != Slot::LOCAL) {
619 BAILOUT("non-parameter/non-local slot reference");
620 }
621 } 654 }
622 655
623 656
624 void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) { 657 void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
625 Expression* rewrite = expr->var()->rewrite(); 658 Expression* rewrite = expr->var()->rewrite();
626 if (rewrite != NULL) Visit(rewrite); 659 // A rewrite of NULL indicates a global variable.
660 if (rewrite != NULL) {
661 Slot* slot = rewrite->AsSlot();
662 if (slot != NULL) {
663 Slot::Type type = slot->type();
664 if (type != Slot::PARAMETER && type != Slot::LOCAL) {
665 BAILOUT("non-parameter/non-local slot reference");
666 }
William Hesse 2009/10/28 10:28:54 Control flow is tricky here. Reversing sense of s
Kevin Millikin (Chromium) 2009/10/28 11:39:38 I see what you mean. I've changed it.
667 } else {
668 BAILOUT("non-global/non-slot variable reference");
669 }
670 }
671 expr->set_location(location_);
627 } 672 }
628 673
629 674
630 void CodeGenSelector::VisitLiteral(Literal* expr) { 675 void CodeGenSelector::VisitLiteral(Literal* expr) {
631 // Literals are supported. 676 expr->set_location(location_);
632 } 677 }
633 678
634 679
635 void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) { 680 void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
636 // RegexpLiterals are supported. 681 expr->set_location(location_);
637 } 682 }
638 683
639 684
640 void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) { 685 void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
641 for (int i = 0; i < expr->properties()->length(); i++) { 686 ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
642 ObjectLiteral::Property* property = expr->properties()->at(i); 687
643 Visit(property->key()); 688 for (int i = 0, len = properties->length(); i < len; i++) {
644 CHECK_BAILOUT; 689 ObjectLiteral::Property* property = properties->at(i);
645 Visit(property->value()); 690 if (property->IsCompileTimeValue()) continue;
691
692 switch (property->kind()) {
693 case ObjectLiteral::Property::CONSTANT:
694 UNREACHABLE();
695
696 // For (non-compile-time) materialized literals and computed
697 // properties with symbolic keys we will use an IC and therefore not
698 // generate code for the key.
699 case ObjectLiteral::Property::COMPUTED: // Fall through.
700 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
701 if (property->key()->handle()->IsSymbol()) {
702 break;
703 }
704 // Fall through.
705
706 // In all other cases we need the key's value on the stack
707 // for a runtime call. (Relies on TEMP meaning STACK.)
708 case ObjectLiteral::Property::GETTER: // Fall through.
709 case ObjectLiteral::Property::SETTER: // Fall through.
710 case ObjectLiteral::Property::PROTOTYPE:
711 VisitAsValue(property->key());
712 CHECK_BAILOUT;
713 break;
714 }
715 VisitAsValue(property->value());
646 CHECK_BAILOUT; 716 CHECK_BAILOUT;
647 } 717 }
718 expr->set_location(location_);
648 } 719 }
649 720
650 721
651 void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) { 722 void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
652 ZoneList<Expression*>* subexprs = expr->values(); 723 ZoneList<Expression*>* subexprs = expr->values();
653 for (int i = 0, len = subexprs->length(); i < len; i++) { 724 for (int i = 0, len = subexprs->length(); i < len; i++) {
654 Expression* subexpr = subexprs->at(i); 725 Expression* subexpr = subexprs->at(i);
655 if (subexpr->AsLiteral() != NULL) continue; 726 if (subexpr->AsLiteral() != NULL) continue;
656 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 727 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
657 Visit(subexpr); 728 VisitAsValue(subexpr);
658 CHECK_BAILOUT; 729 CHECK_BAILOUT;
659 } 730 }
731 expr->set_location(location_);
660 } 732 }
661 733
662 734
663 void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) { 735 void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
664 BAILOUT("CatchExtensionObject"); 736 BAILOUT("CatchExtensionObject");
665 } 737 }
666 738
667 739
668 void CodeGenSelector::VisitAssignment(Assignment* expr) { 740 void CodeGenSelector::VisitAssignment(Assignment* expr) {
669 // We support plain non-compound assignments to parameters and 741 // We support plain non-compound assignments to parameters and
670 // non-context (stack-allocated) locals. 742 // non-context (stack-allocated) locals.
671 if (expr->starts_initialization_block()) BAILOUT("initialization block"); 743 if (expr->starts_initialization_block() ||
744 expr->ends_initialization_block()) {
745 BAILOUT("initialization block start");
746 }
672 747
673 Token::Value op = expr->op(); 748 Token::Value op = expr->op();
674 if (op == Token::INIT_CONST) BAILOUT("initialize constant"); 749 if (op == Token::INIT_CONST) BAILOUT("initialize constant");
675 if (op != Token::ASSIGN && op != Token::INIT_VAR) { 750 if (op != Token::ASSIGN && op != Token::INIT_VAR) {
676 BAILOUT("compound assignment"); 751 BAILOUT("compound assignment");
677 } 752 }
678 753
679 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); 754 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
680 if (var == NULL) BAILOUT("non-variable assignment"); 755 if (var == NULL) BAILOUT("non-variable assignment");
681 756
682 if (!var->is_global()) { 757 if (!var->is_global()) {
683 ASSERT(var->slot() != NULL); 758 ASSERT(var->slot() != NULL);
684 Slot::Type type = var->slot()->type(); 759 Slot::Type type = var->slot()->type();
685 if (type != Slot::PARAMETER && type != Slot::LOCAL) { 760 if (type != Slot::PARAMETER && type != Slot::LOCAL) {
686 BAILOUT("non-parameter/non-local slot assignment"); 761 BAILOUT("non-parameter/non-local slot assignment");
687 } 762 }
688 } 763 }
689 764
690 Visit(expr->value()); 765 VisitAsValue(expr->value());
766 expr->set_location(location_);
691 } 767 }
692 768
693 769
694 void CodeGenSelector::VisitThrow(Throw* expr) { 770 void CodeGenSelector::VisitThrow(Throw* expr) {
695 BAILOUT("Throw"); 771 BAILOUT("Throw");
696 } 772 }
697 773
698 774
699 void CodeGenSelector::VisitProperty(Property* expr) { 775 void CodeGenSelector::VisitProperty(Property* expr) {
700 Visit(expr->obj()); 776 Visit(expr->obj());
701 CHECK_BAILOUT; 777 CHECK_BAILOUT;
702 Visit(expr->key()); 778 Visit(expr->key());
fschneider 2009/10/28 10:06:01 Also set location here: expr->set_location(locati
Kevin Millikin (Chromium) 2009/10/28 11:39:38 You're right. Svn update can't rewrite these :)
703 } 779 }
704 780
705 781
706 void CodeGenSelector::VisitCall(Call* expr) { 782 void CodeGenSelector::VisitCall(Call* expr) {
707 Expression* fun = expr->expression(); 783 Expression* fun = expr->expression();
708 ZoneList<Expression*>* args = expr->arguments(); 784 ZoneList<Expression*>* args = expr->arguments();
709 Variable* var = fun->AsVariableProxy()->AsVariable(); 785 Variable* var = fun->AsVariableProxy()->AsVariable();
710 786
711 // Check for supported calls 787 // Check for supported calls
712 if (var != NULL && var->is_possibly_eval()) { 788 if (var != NULL && var->is_possibly_eval()) {
713 BAILOUT("Call to a function named 'eval'"); 789 BAILOUT("Call to a function named 'eval'");
714 } else if (var != NULL && !var->is_this() && var->is_global()) { 790 } else if (var != NULL && !var->is_this() && var->is_global()) {
715 // ---------------------------------- 791 // ----------------------------------
716 // JavaScript example: 'foo(1, 2, 3)' // foo is global 792 // JavaScript example: 'foo(1, 2, 3)' // foo is global
717 // ---------------------------------- 793 // ----------------------------------
718 } else { 794 } else {
719 BAILOUT("Call to a non-global function"); 795 BAILOUT("Call to a non-global function");
720 } 796 }
721 // Check all arguments to the call 797 // Check all arguments to the call. (Relies on TEMP meaning STACK.)
722 for (int i = 0; i < args->length(); i++) { 798 for (int i = 0; i < args->length(); i++) {
723 Visit(args->at(i)); 799 VisitAsValue(args->at(i));
724 CHECK_BAILOUT; 800 CHECK_BAILOUT;
725 } 801 }
802 expr->set_location(location_);
726 } 803 }
727 804
728 805
729 void CodeGenSelector::VisitCallNew(CallNew* expr) { 806 void CodeGenSelector::VisitCallNew(CallNew* expr) {
730 Visit(expr->expression()); 807 Visit(expr->expression());
731 CHECK_BAILOUT; 808 CHECK_BAILOUT;
732 ZoneList<Expression*>* args = expr->arguments(); 809 ZoneList<Expression*>* args = expr->arguments();
733 // Check all arguments to the call 810 // Check all arguments to the call
734 for (int i = 0; i < args->length(); i++) { 811 for (int i = 0; i < args->length(); i++) {
735 Visit(args->at(i)); 812 Visit(args->at(i));
736 CHECK_BAILOUT; 813 CHECK_BAILOUT;
737 } 814 }
fschneider 2009/10/28 10:06:01 Also set location here: expr->set_location(locatio
738 } 815 }
739 816
740 817
741 void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) { 818 void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
742 // In case of JS runtime function bail out. 819 // In case of JS runtime function bail out.
743 if (expr->function() == NULL) BAILOUT("CallRuntime"); 820 if (expr->function() == NULL) BAILOUT("call JS runtime function");
744 // Check for inline runtime call 821 // Check for inline runtime call
745 if (expr->name()->Get(0) == '_' && 822 if (expr->name()->Get(0) == '_' &&
746 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) { 823 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
747 BAILOUT("InlineRuntimeCall"); 824 BAILOUT("inlined runtime call");
748 } 825 }
826 // Check all arguments to the call. (Relies on TEMP meaning STACK.)
749 for (int i = 0; i < expr->arguments()->length(); i++) { 827 for (int i = 0; i < expr->arguments()->length(); i++) {
750 Visit(expr->arguments()->at(i)); 828 VisitAsValue(expr->arguments()->at(i));
751 CHECK_BAILOUT; 829 CHECK_BAILOUT;
752 } 830 }
831 expr->set_location(location_);
753 } 832 }
754 833
755 834
756 void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) { 835 void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
757 BAILOUT("UnaryOperation"); 836 BAILOUT("UnaryOperation");
758 } 837 }
759 838
760 839
761 void CodeGenSelector::VisitCountOperation(CountOperation* expr) { 840 void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
762 BAILOUT("CountOperation"); 841 BAILOUT("CountOperation");
763 } 842 }
764 843
765 844
766 void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) { 845 void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
767 switch (expr->op()) { 846 switch (expr->op()) {
768 case Token::OR: 847 case Token::OR:
769 Visit(expr->left()); 848 VisitAsValue(expr->left());
770 CHECK_BAILOUT; 849 CHECK_BAILOUT;
850 // The location for the right subexpression is the same as for the
851 // whole expression.
771 Visit(expr->right()); 852 Visit(expr->right());
772 break; 853 break;
773 854
774 default: 855 default:
775 BAILOUT("Unsupported binary operation"); 856 BAILOUT("Unsupported binary operation");
776 } 857 }
858 expr->set_location(location_);
777 } 859 }
778 860
779 861
780 void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) { 862 void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) {
781 BAILOUT("CompareOperation"); 863 BAILOUT("CompareOperation");
782 } 864 }
783 865
784 866
785 void CodeGenSelector::VisitThisFunction(ThisFunction* expr) { 867 void CodeGenSelector::VisitThisFunction(ThisFunction* expr) {
786 BAILOUT("ThisFunction"); 868 BAILOUT("ThisFunction");
787 } 869 }
788 870
789 #undef BAILOUT 871 #undef BAILOUT
790 #undef CHECK_BAILOUT 872 #undef CHECK_BAILOUT
791 873
792 874
793 } } // namespace v8::internal 875 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ast.cc ('k') | src/ia32/fast-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698