OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |