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

Side by Side Diff: src/codegen-ia32.cc

Issue 6301: Document (and assert) some of the safe-but-brittle implicit assumptions... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 12 years, 2 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
« no previous file with comments | « src/codegen-arm.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 51
52 // A reference is a C++ stack-allocated object that keeps an ECMA 52 // A reference is a C++ stack-allocated object that keeps an ECMA
53 // reference on the execution stack while in scope. For variables 53 // reference on the execution stack while in scope. For variables
54 // the reference is empty, indicating that it isn't necessary to 54 // the reference is empty, indicating that it isn't necessary to
55 // store state on the stack for keeping track of references to those. 55 // store state on the stack for keeping track of references to those.
56 // For properties, we keep either one (named) or two (indexed) values 56 // For properties, we keep either one (named) or two (indexed) values
57 // on the execution stack to represent the reference. 57 // on the execution stack to represent the reference.
58 58
59 class Reference BASE_EMBEDDED { 59 class Reference BASE_EMBEDDED {
60 public: 60 public:
61 enum Type { ILLEGAL = -1, EMPTY = 0, NAMED = 1, KEYED = 2 }; 61 // The values of the types is important, see size().
62 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
62 Reference(Ia32CodeGenerator* cgen, Expression* expression); 63 Reference(Ia32CodeGenerator* cgen, Expression* expression);
63 ~Reference(); 64 ~Reference();
64 65
65 Expression* expression() const { return expression_; } 66 Expression* expression() const { return expression_; }
66 Type type() const { return type_; } 67 Type type() const { return type_; }
67 void set_type(Type value) { 68 void set_type(Type value) {
68 ASSERT(type_ == ILLEGAL); 69 ASSERT(type_ == ILLEGAL);
69 type_ = value; 70 type_ = value;
70 } 71 }
71 int size() const { return type_; }
72 72
73 bool is_illegal() const { return type_ == ILLEGAL; } 73 // The size of the reference or -1 if the reference is illegal.
74 int size() const { return type_; }
75
76 bool is_illegal() const { return type_ == ILLEGAL; }
77 bool is_slot() const { return type_ == SLOT; }
78 bool is_property() const { return type_ == NAMED || type_ == KEYED; }
74 79
75 private: 80 private:
76 Ia32CodeGenerator* cgen_; 81 Ia32CodeGenerator* cgen_;
77 Expression* expression_; 82 Expression* expression_;
78 Type type_; 83 Type type_;
79 }; 84 };
80 85
81 86
82 // ------------------------------------------------------------------------- 87 // -------------------------------------------------------------------------
83 // Code generation state 88 // Code generation state
(...skipping 562 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 // saved to TOS, we push ecx onto the stack. 651 // saved to TOS, we push ecx onto the stack.
647 652
648 // Store the arguments object. 653 // Store the arguments object.
649 // This must happen after context initialization because 654 // This must happen after context initialization because
650 // the arguments object may be stored in the context 655 // the arguments object may be stored in the context
651 if (arguments_object_allocated) { 656 if (arguments_object_allocated) {
652 ASSERT(scope->arguments() != NULL); 657 ASSERT(scope->arguments() != NULL);
653 ASSERT(scope->arguments_shadow() != NULL); 658 ASSERT(scope->arguments_shadow() != NULL);
654 Comment cmnt(masm_, "[ store arguments object"); 659 Comment cmnt(masm_, "[ store arguments object");
655 { Reference shadow_ref(this, scope->arguments_shadow()); 660 { Reference shadow_ref(this, scope->arguments_shadow());
661 ASSERT(shadow_ref.is_slot());
656 { Reference arguments_ref(this, scope->arguments()); 662 { Reference arguments_ref(this, scope->arguments());
663 ASSERT(arguments_ref.is_slot());
657 // If the newly-allocated arguments object is already on the 664 // If the newly-allocated arguments object is already on the
658 // stack, we make use of the property that references representing 665 // stack, we make use of the convenient property that references
659 // variables take up no space on the expression stack (ie, it 666 // representing slots take up no space on the expression stack
660 // doesn't matter that the stored value is actually below the 667 // (ie, it doesn't matter that the stored value is actually below
661 // reference). 668 // the reference).
662 ASSERT(arguments_ref.size() == 0); 669 //
663 ASSERT(shadow_ref.size() == 0); 670 // If the newly-allocated argument object is not already on
664 671 // the stack, we rely on the property that loading a
665 // If the newly-allocated argument object is not already on the 672 // zero-sized reference will not clobber the ecx register.
666 // stack, we rely on the property that loading a
667 // (zero-sized) reference will not clobber the ecx register.
668 if (!arguments_object_saved) { 673 if (!arguments_object_saved) {
669 __ push(ecx); 674 __ push(ecx);
670 } 675 }
671 SetValue(&arguments_ref); 676 SetValue(&arguments_ref);
672 } 677 }
673 SetValue(&shadow_ref); 678 SetValue(&shadow_ref);
674 } 679 }
675 __ pop(eax); // Value is no longer needed. 680 __ pop(eax); // Value is no longer needed.
676 } 681 }
677 682
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
838 cgen_->UnloadReference(this); 843 cgen_->UnloadReference(this);
839 } 844 }
840 845
841 846
842 void Ia32CodeGenerator::LoadReference(Reference* ref) { 847 void Ia32CodeGenerator::LoadReference(Reference* ref) {
843 Expression* e = ref->expression(); 848 Expression* e = ref->expression();
844 Property* property = e->AsProperty(); 849 Property* property = e->AsProperty();
845 Variable* var = e->AsVariableProxy()->AsVariable(); 850 Variable* var = e->AsVariableProxy()->AsVariable();
846 851
847 if (property != NULL) { 852 if (property != NULL) {
853 // The expression is either a property or a variable proxy that rewrites
854 // to a property.
848 Load(property->obj()); 855 Load(property->obj());
849 // Used a named reference if the key is a literal symbol. 856 // We use a named reference if the key is a literal symbol, unless it is
850 // We don't use a named reference if they key is a string that can be 857 // a string that can be legally parsed as an integer. This is because
851 // legally parsed as an integer. This is because, otherwise we don't 858 // otherwise we will not get into the slow case code that handles [] on
852 // get into the slow case code that handles [] on String objects. 859 // String objects.
853 Literal* literal = property->key()->AsLiteral(); 860 Literal* literal = property->key()->AsLiteral();
854 uint32_t dummy; 861 uint32_t dummy;
855 if (literal != NULL && literal->handle()->IsSymbol() && 862 if (literal != NULL &&
856 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { 863 literal->handle()->IsSymbol() &&
864 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
857 ref->set_type(Reference::NAMED); 865 ref->set_type(Reference::NAMED);
858 } else { 866 } else {
859 Load(property->key()); 867 Load(property->key());
860 ref->set_type(Reference::KEYED); 868 ref->set_type(Reference::KEYED);
861 } 869 }
862 } else if (var != NULL) { 870 } else if (var != NULL) {
871 // The expression is a variable proxy that does not rewrite to a
872 // property. Global variables are treated as named property references.
863 if (var->is_global()) { 873 if (var->is_global()) {
864 // global variable
865 LoadGlobal(); 874 LoadGlobal();
866 ref->set_type(Reference::NAMED); 875 ref->set_type(Reference::NAMED);
867 } else { 876 } else {
868 // local variable 877 ASSERT(var->slot() != NULL);
869 ref->set_type(Reference::EMPTY); 878 ref->set_type(Reference::SLOT);
870 } 879 }
871 } else { 880 } else {
881 // Anything else is a runtime error.
872 Load(e); 882 Load(e);
873 __ CallRuntime(Runtime::kThrowReferenceError, 1); 883 __ CallRuntime(Runtime::kThrowReferenceError, 1);
874 __ push(eax);
875 } 884 }
876 } 885 }
877 886
878 887
879 void Ia32CodeGenerator::UnloadReference(Reference* ref) { 888 void Ia32CodeGenerator::UnloadReference(Reference* ref) {
880 // Pop n references on the stack while preserving TOS 889 // Pop n references on the stack while preserving TOS
881 Comment cmnt(masm_, "[ UnloadReference"); 890 Comment cmnt(masm_, "[ UnloadReference");
882 int size = ref->size(); 891 int size = ref->size();
883 if (size <= 0) { 892 if (size <= 0) {
884 // Do nothing. No popping is necessary. 893 // Do nothing. No popping is necessary.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
952 // Convert result (eax) to condition code. 961 // Convert result (eax) to condition code.
953 __ test(eax, Operand(eax)); 962 __ test(eax, Operand(eax));
954 963
955 ASSERT(not_equal == not_zero); 964 ASSERT(not_equal == not_zero);
956 cc_reg_ = not_equal; 965 cc_reg_ = not_equal;
957 } 966 }
958 967
959 968
960 void Ia32CodeGenerator::GetReferenceProperty(Expression* key) { 969 void Ia32CodeGenerator::GetReferenceProperty(Expression* key) {
961 ASSERT(!ref()->is_illegal()); 970 ASSERT(!ref()->is_illegal());
962 Reference::Type type = ref()->type();
963 971
964 // TODO(1241834): Make sure that this it is safe to ignore the distinction 972 // TODO(1241834): Make sure that this it is safe to ignore the distinction
965 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance 973 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance
966 // that reference errors can be thrown below, we must distinguish between 974 // that reference errors can be thrown below, we must distinguish between
967 // the two kinds of loads (typeof expression loads must not throw a 975 // the two kinds of loads (typeof expression loads must not throw a
968 // reference error). 976 // reference error).
969 if (type == Reference::NAMED) { 977 if (ref()->type() == Reference::NAMED) {
970 // Compute the name of the property. 978 // Compute the name of the property.
971 Literal* literal = key->AsLiteral(); 979 Literal* literal = key->AsLiteral();
972 Handle<String> name(String::cast(*literal->handle())); 980 Handle<String> name(String::cast(*literal->handle()));
973 981
974 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 982 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
975 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); 983 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
976 // Setup the name register. 984 // Setup the name register.
977 __ Set(ecx, Immediate(name)); 985 __ Set(ecx, Immediate(name));
978 if (var != NULL) { 986 if (var != NULL) {
979 ASSERT(var->is_global()); 987 ASSERT(var->is_global());
980 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); 988 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
981 } else { 989 } else {
982 __ call(ic, RelocInfo::CODE_TARGET); 990 __ call(ic, RelocInfo::CODE_TARGET);
983 } 991 }
984 } else { 992 } else {
985 // Access keyed property. 993 // Access keyed property.
986 ASSERT(type == Reference::KEYED); 994 ASSERT(ref()->type() == Reference::KEYED);
987 995
988 // Call IC code. 996 // Call IC code.
989 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 997 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
990 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); 998 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
991 if (var != NULL) { 999 if (var != NULL) {
992 ASSERT(var->is_global()); 1000 ASSERT(var->is_global());
993 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); 1001 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
994 } else { 1002 } else {
995 __ call(ic, RelocInfo::CODE_TARGET); 1003 __ call(ic, RelocInfo::CODE_TARGET);
996 } 1004 }
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after
1746 Expression* val = NULL; 1754 Expression* val = NULL;
1747 if (node->mode() == Variable::CONST) { 1755 if (node->mode() == Variable::CONST) {
1748 val = new Literal(Factory::the_hole_value()); 1756 val = new Literal(Factory::the_hole_value());
1749 } else { 1757 } else {
1750 val = node->fun(); // NULL if we don't have a function 1758 val = node->fun(); // NULL if we don't have a function
1751 } 1759 }
1752 1760
1753 if (val != NULL) { 1761 if (val != NULL) {
1754 // Set initial value. 1762 // Set initial value.
1755 Reference target(this, node->proxy()); 1763 Reference target(this, node->proxy());
1764 ASSERT(target.is_slot());
1756 Load(val); 1765 Load(val);
1757 SetValue(&target); 1766 SetValue(&target);
1758 // Get rid of the assigned value (declarations are statements). 1767 // Get rid of the assigned value (declarations are statements). It's
1768 // safe to pop the value lying on top of the reference before unloading
1769 // the reference itself (which preserves the top of stack) because we
1770 // know that it is a zero-sized reference.
1759 __ pop(eax); // Pop(no_reg); 1771 __ pop(eax); // Pop(no_reg);
1760 } 1772 }
1761 } 1773 }
1762 1774
1763 1775
1764 void Ia32CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { 1776 void Ia32CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
1765 Comment cmnt(masm_, "[ ExpressionStatement"); 1777 Comment cmnt(masm_, "[ ExpressionStatement");
1766 RecordStatementPosition(node); 1778 RecordStatementPosition(node);
1767 Expression* expression = node->expression(); 1779 Expression* expression = node->expression();
1768 expression->MarkAsStatement(); 1780 expression->MarkAsStatement();
(...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after
2262 2274
2263 // If the property has been removed while iterating, we just skip it. 2275 // If the property has been removed while iterating, we just skip it.
2264 __ cmp(ebx, Factory::null_value()); 2276 __ cmp(ebx, Factory::null_value());
2265 __ j(equal, &next); 2277 __ j(equal, &next);
2266 2278
2267 2279
2268 __ bind(&end_del_check); 2280 __ bind(&end_del_check);
2269 2281
2270 // Store the entry in the 'each' expression and take another spin in the loop. 2282 // Store the entry in the 'each' expression and take another spin in the loop.
2271 // edx: i'th entry of the enum cache (or string there of) 2283 // edx: i'th entry of the enum cache (or string there of)
2272 __ push(Operand(ebx)); 2284 __ push(ebx);
2273 { Reference each(this, node->each()); 2285 { Reference each(this, node->each());
2274 if (!each.is_illegal()) { 2286 if (!each.is_illegal()) {
2275 if (each.size() > 0) { 2287 if (each.size() > 0) {
2276 __ push(Operand(esp, kPointerSize * each.size())); 2288 __ push(Operand(esp, kPointerSize * each.size()));
2277 } 2289 }
2290 // If the reference was to a slot we rely on the convenient property
2291 // that it doesn't matter whether a value (eg, ebx pushed above) is
2292 // right on top of or right underneath a zero-sized reference.
2278 SetValue(&each); 2293 SetValue(&each);
2279 if (each.size() > 0) { 2294 if (each.size() > 0) {
2295 // It's safe to pop the value lying on top of the reference before
2296 // unloading the reference itself (which preserves the top of stack,
2297 // ie, now the topmost value of the non-zero sized reference), since
2298 // we will discard the top of stack after unloading the reference
2299 // anyway.
2280 __ pop(eax); 2300 __ pop(eax);
2281 } 2301 }
2282 } 2302 }
2283 } 2303 }
2284 __ pop(eax); // pop the i'th entry pushed above 2304 // Discard the i'th entry pushed above or else the remainder of the
2305 // reference, whichever is currently on top of the stack.
2306 __ pop(eax);
2285 CheckStack(); // TODO(1222600): ignore if body contains calls. 2307 CheckStack(); // TODO(1222600): ignore if body contains calls.
2286 __ jmp(&loop); 2308 __ jmp(&loop);
2287 2309
2288 // Cleanup. 2310 // Cleanup.
2289 __ bind(&cleanup); 2311 __ bind(&cleanup);
2290 __ bind(node->break_target()); 2312 __ bind(node->break_target());
2291 __ add(Operand(esp), Immediate(5 * kPointerSize)); 2313 __ add(Operand(esp), Immediate(5 * kPointerSize));
2292 2314
2293 // Exit. 2315 // Exit.
2294 __ bind(&exit); 2316 __ bind(&exit);
2295 2317
2296 break_stack_height_ -= kForInStackSize; 2318 break_stack_height_ -= kForInStackSize;
2297 } 2319 }
2298 2320
2299 2321
2300 void Ia32CodeGenerator::VisitTryCatch(TryCatch* node) { 2322 void Ia32CodeGenerator::VisitTryCatch(TryCatch* node) {
2301 Comment cmnt(masm_, "[ TryCatch"); 2323 Comment cmnt(masm_, "[ TryCatch");
2302 2324
2303 Label try_block, exit; 2325 Label try_block, exit;
2304 2326
2305 __ call(&try_block); 2327 __ call(&try_block);
2306 // --- Catch block --- 2328 // --- Catch block ---
2307 __ push(eax); 2329 __ push(eax);
2308 2330
2309 // Store the caught exception in the catch variable. 2331 // Store the caught exception in the catch variable.
2310 { Reference ref(this, node->catch_var()); 2332 { Reference ref(this, node->catch_var());
2311 // Load the exception to the top of the stack. 2333 ASSERT(ref.is_slot());
2312 __ push(Operand(esp, ref.size() * kPointerSize)); 2334 // Load the exception to the top of the stack. Here we make use of the
2335 // convenient property that it doesn't matter whether a value is
2336 // immediately on top of or underneath a zero-sized reference.
2313 SetValue(&ref); 2337 SetValue(&ref);
2314 __ pop(eax); // pop the pushed exception
2315 } 2338 }
2316 2339
2317 // Remove the exception from the stack. 2340 // Remove the exception from the stack.
2318 __ pop(edx); 2341 __ pop(edx);
2319 2342
2320 VisitStatements(node->catch_block()->statements()); 2343 VisitStatements(node->catch_block()->statements());
2321 __ jmp(&exit); 2344 __ jmp(&exit);
2322 2345
2323 2346
2324 // --- Try block --- 2347 // --- Try block ---
(...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after
3044 } else { 3067 } else {
3045 // ------------------------------------------- 3068 // -------------------------------------------
3046 // JavaScript example: 'array[index](1, 2, 3)' 3069 // JavaScript example: 'array[index](1, 2, 3)'
3047 // ------------------------------------------- 3070 // -------------------------------------------
3048 3071
3049 // Load the function to call from the property through a reference. 3072 // Load the function to call from the property through a reference.
3050 Reference ref(this, property); 3073 Reference ref(this, property);
3051 GetValue(&ref); 3074 GetValue(&ref);
3052 3075
3053 // Pass receiver to called function. 3076 // Pass receiver to called function.
3077 // The reference's size is non-negative.
3054 __ push(Operand(esp, ref.size() * kPointerSize)); 3078 __ push(Operand(esp, ref.size() * kPointerSize));
3055 3079
3056 // Call the function. 3080 // Call the function.
3057 CallWithArguments(args, node->position()); 3081 CallWithArguments(args, node->position());
3058 } 3082 }
3059 3083
3060 } else { 3084 } else {
3061 // ---------------------------------- 3085 // ----------------------------------
3062 // JavaScript example: 'foo(1, 2, 3)' // foo is not global 3086 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
3063 // ---------------------------------- 3087 // ----------------------------------
(...skipping 2282 matching lines...) Expand 10 before | Expand all | Expand 10 after
5346 bool is_eval) { 5370 bool is_eval) {
5347 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); 5371 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval);
5348 if (!code.is_null()) { 5372 if (!code.is_null()) {
5349 Counters::total_compiled_code_size.Increment(code->instruction_size()); 5373 Counters::total_compiled_code_size.Increment(code->instruction_size());
5350 } 5374 }
5351 return code; 5375 return code;
5352 } 5376 }
5353 5377
5354 5378
5355 } } // namespace v8::internal 5379 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-arm.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698