Chromium Code Reviews| 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 14 matching lines...) Expand all Loading... | |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "debug.h" | 32 #include "debug.h" |
| 33 #include "scopes.h" | 33 #include "scopes.h" |
| 34 #include "runtime.h" | 34 #include "runtime.h" |
| 35 #include "virtual-frame-ia32-inl.h" | |
| 36 | 35 |
| 37 namespace v8 { namespace internal { | 36 namespace v8 { namespace internal { |
| 38 | 37 |
| 39 #define __ masm_-> | 38 #define __ masm_-> |
| 40 | 39 |
| 41 // ------------------------------------------------------------------------- | 40 // ------------------------------------------------------------------------- |
| 42 // CodeGenState implementation. | 41 // CodeGenState implementation. |
| 43 | 42 |
| 44 CodeGenState::CodeGenState(CodeGenerator* owner) | 43 CodeGenState::CodeGenState(CodeGenerator* owner) |
| 45 : owner_(owner), | 44 : owner_(owner), |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 149 __ lea(eax, frame_->Receiver()); | 148 __ lea(eax, frame_->Receiver()); |
| 150 frame_->Push(frame_->Function()); | 149 frame_->Push(frame_->Function()); |
| 151 frame_->Push(eax); | 150 frame_->Push(eax); |
| 152 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters()))); | 151 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 153 frame_->CallStub(&stub, 3); | 152 frame_->CallStub(&stub, 3); |
| 154 __ mov(ecx, Operand(eax)); | 153 __ mov(ecx, Operand(eax)); |
| 155 arguments_object_allocated = true; | 154 arguments_object_allocated = true; |
| 156 } | 155 } |
| 157 | 156 |
| 158 // Allocate space for locals and initialize them. | 157 // Allocate space for locals and initialize them. |
| 159 frame_->AllocateLocals(); | 158 frame_->AllocateLocals(scope_->num_stack_slots()); |
|
Erik Corry
2008/11/11 10:47:05
Should AllocateLocals be called AllocateStackSlots
Kevin Millikin (Chromium)
2008/11/11 11:37:31
Probably. Changed.
| |
| 160 | 159 |
| 161 if (scope_->num_heap_slots() > 0) { | 160 if (scope_->num_heap_slots() > 0) { |
| 162 Comment cmnt(masm_, "[ allocate local context"); | 161 Comment cmnt(masm_, "[ allocate local context"); |
| 163 // Save the arguments object pointer, if any. | 162 // Save the arguments object pointer, if any. |
| 164 if (arguments_object_allocated && !arguments_object_saved) { | 163 if (arguments_object_allocated && !arguments_object_saved) { |
| 165 frame_->Push(ecx); | 164 frame_->Push(ecx); |
| 166 arguments_object_saved = true; | 165 arguments_object_saved = true; |
| 167 } | 166 } |
| 168 // Allocate local context. | 167 // Allocate local context. |
| 169 // Get outer context and create a new context based on it. | 168 // Get outer context and create a new context based on it. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 // If the newly-allocated argument object is not already on | 239 // If the newly-allocated argument object is not already on |
| 241 // the stack, we rely on the property that loading a | 240 // the stack, we rely on the property that loading a |
| 242 // zero-sized reference will not clobber the ecx register. | 241 // zero-sized reference will not clobber the ecx register. |
| 243 if (!arguments_object_saved) { | 242 if (!arguments_object_saved) { |
| 244 frame_->Push(ecx); | 243 frame_->Push(ecx); |
| 245 } | 244 } |
| 246 arguments_ref.SetValue(NOT_CONST_INIT); | 245 arguments_ref.SetValue(NOT_CONST_INIT); |
| 247 } | 246 } |
| 248 shadow_ref.SetValue(NOT_CONST_INIT); | 247 shadow_ref.SetValue(NOT_CONST_INIT); |
| 249 } | 248 } |
| 250 frame_->Pop(); // Value is no longer needed. | 249 frame_->Drop(); // Value is no longer needed. |
| 251 } | 250 } |
| 252 | 251 |
| 253 // Generate code to 'execute' declarations and initialize functions | 252 // Generate code to 'execute' declarations and initialize functions |
| 254 // (source elements). In case of an illegal redeclaration we need to | 253 // (source elements). In case of an illegal redeclaration we need to |
| 255 // handle that instead of processing the declarations. | 254 // handle that instead of processing the declarations. |
| 256 if (scope_->HasIllegalRedeclaration()) { | 255 if (scope_->HasIllegalRedeclaration()) { |
| 257 Comment cmnt(masm_, "[ illegal redeclarations"); | 256 Comment cmnt(masm_, "[ illegal redeclarations"); |
| 258 scope_->VisitIllegalRedeclaration(this); | 257 scope_->VisitIllegalRedeclaration(this); |
| 259 } else { | 258 } else { |
| 260 Comment cmnt(masm_, "[ declarations"); | 259 Comment cmnt(masm_, "[ declarations"); |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 713 | 712 |
| 714 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 713 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 715 StaticType* type, | 714 StaticType* type, |
| 716 OverwriteMode overwrite_mode) { | 715 OverwriteMode overwrite_mode) { |
| 717 Comment cmnt(masm_, "[ BinaryOperation"); | 716 Comment cmnt(masm_, "[ BinaryOperation"); |
| 718 Comment cmnt_token(masm_, Token::String(op)); | 717 Comment cmnt_token(masm_, Token::String(op)); |
| 719 | 718 |
| 720 if (op == Token::COMMA) { | 719 if (op == Token::COMMA) { |
| 721 // Simply discard left value. | 720 // Simply discard left value. |
| 722 frame_->Pop(eax); | 721 frame_->Pop(eax); |
| 723 frame_->Pop(); | 722 frame_->Drop(); |
| 724 frame_->Push(eax); | 723 frame_->Push(eax); |
| 725 return; | 724 return; |
| 726 } | 725 } |
| 727 | 726 |
| 728 // Set the flags based on the operation, type and loop nesting level. | 727 // Set the flags based on the operation, type and loop nesting level. |
| 729 GenericBinaryFlags flags; | 728 GenericBinaryFlags flags; |
| 730 switch (op) { | 729 switch (op) { |
| 731 case Token::BIT_OR: | 730 case Token::BIT_OR: |
| 732 case Token::BIT_AND: | 731 case Token::BIT_AND: |
| 733 case Token::BIT_XOR: | 732 case Token::BIT_XOR: |
| (...skipping 623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1357 if (val != NULL) { | 1356 if (val != NULL) { |
| 1358 // Set initial value. | 1357 // Set initial value. |
| 1359 Reference target(this, node->proxy()); | 1358 Reference target(this, node->proxy()); |
| 1360 ASSERT(target.is_slot()); | 1359 ASSERT(target.is_slot()); |
| 1361 Load(val); | 1360 Load(val); |
| 1362 target.SetValue(NOT_CONST_INIT); | 1361 target.SetValue(NOT_CONST_INIT); |
| 1363 // Get rid of the assigned value (declarations are statements). It's | 1362 // Get rid of the assigned value (declarations are statements). It's |
| 1364 // safe to pop the value lying on top of the reference before unloading | 1363 // safe to pop the value lying on top of the reference before unloading |
| 1365 // the reference itself (which preserves the top of stack) because we | 1364 // the reference itself (which preserves the top of stack) because we |
| 1366 // know that it is a zero-sized reference. | 1365 // know that it is a zero-sized reference. |
| 1367 frame_->Pop(); | 1366 frame_->Drop(); |
| 1368 } | 1367 } |
| 1369 } | 1368 } |
| 1370 | 1369 |
| 1371 | 1370 |
| 1372 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1371 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1373 Comment cmnt(masm_, "[ ExpressionStatement"); | 1372 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1374 RecordStatementPosition(node); | 1373 RecordStatementPosition(node); |
| 1375 Expression* expression = node->expression(); | 1374 Expression* expression = node->expression(); |
| 1376 expression->MarkAsStatement(); | 1375 expression->MarkAsStatement(); |
| 1377 Load(expression); | 1376 Load(expression); |
| 1378 // Remove the lingering expression result from the top of stack. | 1377 // Remove the lingering expression result from the top of stack. |
| 1379 frame_->Pop(); | 1378 frame_->Drop(); |
| 1380 } | 1379 } |
| 1381 | 1380 |
| 1382 | 1381 |
| 1383 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1382 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1384 Comment cmnt(masm_, "// EmptyStatement"); | 1383 Comment cmnt(masm_, "// EmptyStatement"); |
| 1385 // nothing to do | 1384 // nothing to do |
| 1386 } | 1385 } |
| 1387 | 1386 |
| 1388 | 1387 |
| 1389 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1388 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1458 } else { | 1457 } else { |
| 1459 ASSERT(!has_then_stm && !has_else_stm); | 1458 ASSERT(!has_then_stm && !has_else_stm); |
| 1460 // if (cond) | 1459 // if (cond) |
| 1461 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1460 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
| 1462 if (frame_ != NULL) { | 1461 if (frame_ != NULL) { |
| 1463 if (has_cc()) { | 1462 if (has_cc()) { |
| 1464 cc_reg_ = no_condition; | 1463 cc_reg_ = no_condition; |
| 1465 } else { | 1464 } else { |
| 1466 // No cc value set up, that means the boolean was pushed. | 1465 // No cc value set up, that means the boolean was pushed. |
| 1467 // Pop it again, since it is not going to be used. | 1466 // Pop it again, since it is not going to be used. |
| 1468 frame_->Pop(); | 1467 frame_->Drop(); |
| 1469 } | 1468 } |
| 1470 } | 1469 } |
| 1471 } | 1470 } |
| 1472 | 1471 |
| 1473 // end | 1472 // end |
| 1474 if (exit.is_linked()) { | 1473 if (exit.is_linked()) { |
| 1475 exit.Bind(); | 1474 exit.Bind(); |
| 1476 } | 1475 } |
| 1477 } | 1476 } |
| 1478 | 1477 |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1677 next_test.Bind(); | 1676 next_test.Bind(); |
| 1678 next_test.Unuse(); | 1677 next_test.Unuse(); |
| 1679 // Duplicate TOS. | 1678 // Duplicate TOS. |
| 1680 __ mov(eax, frame_->Top()); | 1679 __ mov(eax, frame_->Top()); |
| 1681 frame_->Push(eax); | 1680 frame_->Push(eax); |
| 1682 Load(clause->label()); | 1681 Load(clause->label()); |
| 1683 Comparison(equal, true); | 1682 Comparison(equal, true); |
| 1684 Branch(false, &next_test); | 1683 Branch(false, &next_test); |
| 1685 | 1684 |
| 1686 // Before entering the body, remove the switch value from the stack. | 1685 // Before entering the body, remove the switch value from the stack. |
| 1687 frame_->Pop(); | 1686 frame_->Drop(); |
| 1688 | 1687 |
| 1689 // Label the body so that fall through is enabled. | 1688 // Label the body so that fall through is enabled. |
| 1690 if (i > 0 && cases->at(i - 1)->is_default()) { | 1689 if (i > 0 && cases->at(i - 1)->is_default()) { |
| 1691 default_exit.Bind(); | 1690 default_exit.Bind(); |
| 1692 } else { | 1691 } else { |
| 1693 fall_through.Bind(); | 1692 fall_through.Bind(); |
| 1694 fall_through.Unuse(); | 1693 fall_through.Unuse(); |
| 1695 } | 1694 } |
| 1696 VisitStatements(clause->statements()); | 1695 VisitStatements(clause->statements()); |
| 1697 | 1696 |
| 1698 // If control flow can fall through from the body jump to the | 1697 // If control flow can fall through from the body jump to the |
| 1699 // next body or end of the statement. | 1698 // next body or end of the statement. |
| 1700 if (frame_ != NULL) { | 1699 if (frame_ != NULL) { |
| 1701 if (i < length - 1 && cases->at(i + 1)->is_default()) { | 1700 if (i < length - 1 && cases->at(i + 1)->is_default()) { |
| 1702 default_entry.Jump(); | 1701 default_entry.Jump(); |
| 1703 } else { | 1702 } else { |
| 1704 fall_through.Jump(); | 1703 fall_through.Jump(); |
| 1705 } | 1704 } |
| 1706 } | 1705 } |
| 1707 } | 1706 } |
| 1708 } | 1707 } |
| 1709 | 1708 |
| 1710 // The final test removes the switch value. | 1709 // The final test removes the switch value. |
| 1711 next_test.Bind(); | 1710 next_test.Bind(); |
| 1712 frame_->Pop(); | 1711 frame_->Drop(); |
| 1713 | 1712 |
| 1714 // If there is a default clause, compile it. | 1713 // If there is a default clause, compile it. |
| 1715 if (default_clause != NULL) { | 1714 if (default_clause != NULL) { |
| 1716 Comment cmnt(masm_, "[ Default clause"); | 1715 Comment cmnt(masm_, "[ Default clause"); |
| 1717 default_entry.Bind(); | 1716 default_entry.Bind(); |
| 1718 VisitStatements(default_clause->statements()); | 1717 VisitStatements(default_clause->statements()); |
| 1719 // If control flow can fall out of the default and there is a case after | 1718 // If control flow can fall out of the default and there is a case after |
| 1720 // it, jump to that case's body. | 1719 // it, jump to that case's body. |
| 1721 if (frame_ != NULL && default_exit.is_bound()) { | 1720 if (frame_ != NULL && default_exit.is_bound()) { |
| 1722 default_exit.Jump(); | 1721 default_exit.Jump(); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2014 | 2013 |
| 2015 // Push the length of the array and the initial index onto the stack. | 2014 // Push the length of the array and the initial index onto the stack. |
| 2016 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 2015 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 2017 __ shl(eax, kSmiTagSize); | 2016 __ shl(eax, kSmiTagSize); |
| 2018 frame_->Push(eax); // <- slot 1 | 2017 frame_->Push(eax); // <- slot 1 |
| 2019 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 | 2018 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 2020 | 2019 |
| 2021 // Condition. | 2020 // Condition. |
| 2022 entry.Bind(); | 2021 entry.Bind(); |
| 2023 | 2022 |
| 2024 __ mov(eax, frame_->Element(0)); // load the current count | 2023 __ mov(eax, frame_->ElementAt(0)); // load the current count |
| 2025 __ cmp(eax, frame_->Element(1)); // compare to the array length | 2024 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length |
| 2026 cleanup.Branch(above_equal); | 2025 cleanup.Branch(above_equal); |
| 2027 | 2026 |
| 2028 // Get the i'th entry of the array. | 2027 // Get the i'th entry of the array. |
| 2029 __ mov(edx, frame_->Element(2)); | 2028 __ mov(edx, frame_->ElementAt(2)); |
| 2030 __ mov(ebx, Operand(edx, eax, times_2, | 2029 __ mov(ebx, Operand(edx, eax, times_2, |
| 2031 FixedArray::kHeaderSize - kHeapObjectTag)); | 2030 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 2032 | 2031 |
| 2033 // Get the expected map from the stack or a zero map in the | 2032 // Get the expected map from the stack or a zero map in the |
| 2034 // permanent slow case eax: current iteration count ebx: i'th entry | 2033 // permanent slow case eax: current iteration count ebx: i'th entry |
| 2035 // of the enum cache | 2034 // of the enum cache |
| 2036 __ mov(edx, frame_->Element(3)); | 2035 __ mov(edx, frame_->ElementAt(3)); |
| 2037 // Check if the expected map still matches that of the enumerable. | 2036 // Check if the expected map still matches that of the enumerable. |
| 2038 // If not, we have to filter the key. | 2037 // If not, we have to filter the key. |
| 2039 // eax: current iteration count | 2038 // eax: current iteration count |
| 2040 // ebx: i'th entry of the enum cache | 2039 // ebx: i'th entry of the enum cache |
| 2041 // edx: expected map value | 2040 // edx: expected map value |
| 2042 __ mov(ecx, frame_->Element(4)); | 2041 __ mov(ecx, frame_->ElementAt(4)); |
| 2043 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); | 2042 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 2044 __ cmp(ecx, Operand(edx)); | 2043 __ cmp(ecx, Operand(edx)); |
| 2045 end_del_check.Branch(equal); | 2044 end_del_check.Branch(equal); |
| 2046 | 2045 |
| 2047 // Convert the entry to a string (or null if it isn't a property anymore). | 2046 // Convert the entry to a string (or null if it isn't a property anymore). |
| 2048 frame_->Push(frame_->Element(4)); // push enumerable | 2047 frame_->Push(frame_->ElementAt(4)); // push enumerable |
| 2049 frame_->Push(ebx); // push entry | 2048 frame_->Push(ebx); // push entry |
| 2050 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); | 2049 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); |
| 2051 __ mov(ebx, Operand(eax)); | 2050 __ mov(ebx, Operand(eax)); |
| 2052 | 2051 |
| 2053 // If the property has been removed while iterating, we just skip it. | 2052 // If the property has been removed while iterating, we just skip it. |
| 2054 __ cmp(ebx, Factory::null_value()); | 2053 __ cmp(ebx, Factory::null_value()); |
| 2055 node->continue_target()->Branch(equal); | 2054 node->continue_target()->Branch(equal); |
| 2056 | 2055 |
| 2057 end_del_check.Bind(); | 2056 end_del_check.Bind(); |
| 2058 // Store the entry in the 'each' expression and take another spin in the loop. | 2057 // Store the entry in the 'each' expression and take another spin in the loop. |
| 2059 // edx: i'th entry of the enum cache (or string there of) | 2058 // edx: i'th entry of the enum cache (or string there of) |
| 2060 frame_->Push(ebx); | 2059 frame_->Push(ebx); |
| 2061 { Reference each(this, node->each()); | 2060 { Reference each(this, node->each()); |
| 2062 if (!each.is_illegal()) { | 2061 if (!each.is_illegal()) { |
| 2063 if (each.size() > 0) { | 2062 if (each.size() > 0) { |
| 2064 frame_->Push(frame_->Element(each.size())); | 2063 frame_->Push(frame_->ElementAt(each.size())); |
| 2065 } | 2064 } |
| 2066 // If the reference was to a slot we rely on the convenient property | 2065 // If the reference was to a slot we rely on the convenient property |
| 2067 // that it doesn't matter whether a value (eg, ebx pushed above) is | 2066 // that it doesn't matter whether a value (eg, ebx pushed above) is |
| 2068 // right on top of or right underneath a zero-sized reference. | 2067 // right on top of or right underneath a zero-sized reference. |
| 2069 each.SetValue(NOT_CONST_INIT); | 2068 each.SetValue(NOT_CONST_INIT); |
| 2070 if (each.size() > 0) { | 2069 if (each.size() > 0) { |
| 2071 // It's safe to pop the value lying on top of the reference before | 2070 // It's safe to pop the value lying on top of the reference before |
| 2072 // unloading the reference itself (which preserves the top of stack, | 2071 // unloading the reference itself (which preserves the top of stack, |
| 2073 // ie, now the topmost value of the non-zero sized reference), since | 2072 // ie, now the topmost value of the non-zero sized reference), since |
| 2074 // we will discard the top of stack after unloading the reference | 2073 // we will discard the top of stack after unloading the reference |
| 2075 // anyway. | 2074 // anyway. |
| 2076 frame_->Pop(); | 2075 frame_->Drop(); |
| 2077 } | 2076 } |
| 2078 } | 2077 } |
| 2079 } | 2078 } |
| 2080 // Discard the i'th entry pushed above or else the remainder of the | 2079 // Discard the i'th entry pushed above or else the remainder of the |
| 2081 // reference, whichever is currently on top of the stack. | 2080 // reference, whichever is currently on top of the stack. |
| 2082 frame_->Pop(); | 2081 frame_->Drop(); |
| 2083 | 2082 |
| 2084 // Body. | 2083 // Body. |
| 2085 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2084 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2086 Visit(node->body()); | 2085 Visit(node->body()); |
| 2087 | 2086 |
| 2088 // Next. | 2087 // Next. |
| 2089 node->continue_target()->Bind(); | 2088 node->continue_target()->Bind(); |
| 2090 frame_->Pop(eax); | 2089 frame_->Pop(eax); |
| 2091 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 2090 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 2092 frame_->Push(eax); | 2091 frame_->Push(eax); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 2117 // Store the caught exception in the catch variable. | 2116 // Store the caught exception in the catch variable. |
| 2118 { Reference ref(this, node->catch_var()); | 2117 { Reference ref(this, node->catch_var()); |
| 2119 ASSERT(ref.is_slot()); | 2118 ASSERT(ref.is_slot()); |
| 2120 // Load the exception to the top of the stack. Here we make use of the | 2119 // Load the exception to the top of the stack. Here we make use of the |
| 2121 // convenient property that it doesn't matter whether a value is | 2120 // convenient property that it doesn't matter whether a value is |
| 2122 // immediately on top of or underneath a zero-sized reference. | 2121 // immediately on top of or underneath a zero-sized reference. |
| 2123 ref.SetValue(NOT_CONST_INIT); | 2122 ref.SetValue(NOT_CONST_INIT); |
| 2124 } | 2123 } |
| 2125 | 2124 |
| 2126 // Remove the exception from the stack. | 2125 // Remove the exception from the stack. |
| 2127 frame_->Pop(); | 2126 frame_->Drop(); |
| 2128 | 2127 |
| 2129 VisitStatements(node->catch_block()->statements()); | 2128 VisitStatements(node->catch_block()->statements()); |
| 2130 if (frame_ != NULL) { | 2129 if (frame_ != NULL) { |
| 2131 exit.Jump(); | 2130 exit.Jump(); |
| 2132 } | 2131 } |
| 2133 | 2132 |
| 2134 | 2133 |
| 2135 // --- Try block --- | 2134 // --- Try block --- |
| 2136 try_block.Bind(); | 2135 try_block.Bind(); |
| 2137 | 2136 |
| (...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2639 case ObjectLiteral::Property::COMPUTED: { | 2638 case ObjectLiteral::Property::COMPUTED: { |
| 2640 Handle<Object> key(property->key()->handle()); | 2639 Handle<Object> key(property->key()->handle()); |
| 2641 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2640 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 2642 if (key->IsSymbol()) { | 2641 if (key->IsSymbol()) { |
| 2643 __ mov(eax, frame_->Top()); | 2642 __ mov(eax, frame_->Top()); |
| 2644 frame_->Push(eax); | 2643 frame_->Push(eax); |
| 2645 Load(property->value()); | 2644 Load(property->value()); |
| 2646 frame_->Pop(eax); | 2645 frame_->Pop(eax); |
| 2647 __ Set(ecx, Immediate(key)); | 2646 __ Set(ecx, Immediate(key)); |
| 2648 frame_->CallCode(ic, RelocInfo::CODE_TARGET, 0); | 2647 frame_->CallCode(ic, RelocInfo::CODE_TARGET, 0); |
| 2649 frame_->Pop(); | 2648 frame_->Drop(); |
| 2650 // Ignore result. | 2649 // Ignore result. |
| 2651 break; | 2650 break; |
| 2652 } | 2651 } |
| 2653 // Fall through | 2652 // Fall through |
| 2654 } | 2653 } |
| 2655 case ObjectLiteral::Property::PROTOTYPE: { | 2654 case ObjectLiteral::Property::PROTOTYPE: { |
| 2656 __ mov(eax, frame_->Top()); | 2655 __ mov(eax, frame_->Top()); |
| 2657 frame_->Push(eax); | 2656 frame_->Push(eax); |
| 2658 Load(property->key()); | 2657 Load(property->key()); |
| 2659 Load(property->value()); | 2658 Load(property->value()); |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2904 // ------------------------------------------- | 2903 // ------------------------------------------- |
| 2905 // JavaScript example: 'array[index](1, 2, 3)' | 2904 // JavaScript example: 'array[index](1, 2, 3)' |
| 2906 // ------------------------------------------- | 2905 // ------------------------------------------- |
| 2907 | 2906 |
| 2908 // Load the function to call from the property through a reference. | 2907 // Load the function to call from the property through a reference. |
| 2909 Reference ref(this, property); | 2908 Reference ref(this, property); |
| 2910 ref.GetValue(NOT_INSIDE_TYPEOF); | 2909 ref.GetValue(NOT_INSIDE_TYPEOF); |
| 2911 | 2910 |
| 2912 // Pass receiver to called function. | 2911 // Pass receiver to called function. |
| 2913 // The reference's size is non-negative. | 2912 // The reference's size is non-negative. |
| 2914 frame_->Push(frame_->Element(ref.size())); | 2913 frame_->Push(frame_->ElementAt(ref.size())); |
| 2915 | 2914 |
| 2916 // Call the function. | 2915 // Call the function. |
| 2917 CallWithArguments(args, node->position()); | 2916 CallWithArguments(args, node->position()); |
| 2918 } | 2917 } |
| 2919 | 2918 |
| 2920 } else { | 2919 } else { |
| 2921 // ---------------------------------- | 2920 // ---------------------------------- |
| 2922 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 2921 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
| 2923 // ---------------------------------- | 2922 // ---------------------------------- |
| 2924 | 2923 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 2955 Load(args->at(i)); | 2954 Load(args->at(i)); |
| 2956 } | 2955 } |
| 2957 | 2956 |
| 2958 // Constructors are called with the number of arguments in register | 2957 // Constructors are called with the number of arguments in register |
| 2959 // eax for now. Another option would be to have separate construct | 2958 // eax for now. Another option would be to have separate construct |
| 2960 // call trampolines per different arguments counts encountered. | 2959 // call trampolines per different arguments counts encountered. |
| 2961 __ Set(eax, Immediate(args->length())); | 2960 __ Set(eax, Immediate(args->length())); |
| 2962 | 2961 |
| 2963 // Load the function into temporary function slot as per calling | 2962 // Load the function into temporary function slot as per calling |
| 2964 // convention. | 2963 // convention. |
| 2965 __ mov(edi, frame_->Element(args->length() + 1)); | 2964 __ mov(edi, frame_->ElementAt(args->length() + 1)); |
| 2966 | 2965 |
| 2967 // Call the construct call builtin that handles allocation and | 2966 // Call the construct call builtin that handles allocation and |
| 2968 // constructor invocation. | 2967 // constructor invocation. |
| 2969 __ RecordPosition(node->position()); | 2968 __ RecordPosition(node->position()); |
| 2970 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 2969 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
| 2971 frame_->CallCode(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); | 2970 frame_->CallCode(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); |
| 2972 // Discard the function and "push" the newly created object. | 2971 // Discard the function and "push" the newly created object. |
| 2973 __ mov(frame_->Top(), eax); | 2972 __ mov(frame_->Top(), eax); |
| 2974 } | 2973 } |
| 2975 | 2974 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3167 __ mov(frame_->Top(), eax); | 3166 __ mov(frame_->Top(), eax); |
| 3168 leave.Bind(); | 3167 leave.Bind(); |
| 3169 } | 3168 } |
| 3170 | 3169 |
| 3171 | 3170 |
| 3172 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 3171 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 3173 ASSERT(args->length() == 2); | 3172 ASSERT(args->length() == 2); |
| 3174 JumpTarget leave(this); | 3173 JumpTarget leave(this); |
| 3175 Load(args->at(0)); // Load the object. | 3174 Load(args->at(0)); // Load the object. |
| 3176 Load(args->at(1)); // Load the value. | 3175 Load(args->at(1)); // Load the value. |
| 3177 __ mov(eax, frame_->Element(1)); | 3176 __ mov(eax, frame_->ElementAt(1)); |
| 3178 __ mov(ecx, frame_->Top()); | 3177 __ mov(ecx, frame_->Top()); |
| 3179 // if (object->IsSmi()) return object. | 3178 // if (object->IsSmi()) return object. |
| 3180 __ test(eax, Immediate(kSmiTagMask)); | 3179 __ test(eax, Immediate(kSmiTagMask)); |
| 3181 leave.Branch(zero, taken); | 3180 leave.Branch(zero, taken); |
| 3182 // It is a heap object - get map. | 3181 // It is a heap object - get map. |
| 3183 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 3182 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3184 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 3183 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 3185 // if (!object->IsJSValue()) return object. | 3184 // if (!object->IsJSValue()) return object. |
| 3186 __ cmp(ebx, JS_VALUE_TYPE); | 3185 __ cmp(ebx, JS_VALUE_TYPE); |
| 3187 leave.Branch(not_equal, not_taken); | 3186 leave.Branch(not_equal, not_taken); |
| 3188 // Store the value. | 3187 // Store the value. |
| 3189 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); | 3188 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); |
| 3190 // Update the write barrier. | 3189 // Update the write barrier. |
| 3191 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); | 3190 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); |
| 3192 // Leave. | 3191 // Leave. |
| 3193 leave.Bind(); | 3192 leave.Bind(); |
| 3194 __ mov(ecx, frame_->Top()); | 3193 __ mov(ecx, frame_->Top()); |
| 3195 frame_->Pop(); | 3194 frame_->Drop(); |
| 3196 __ mov(frame_->Top(), ecx); | 3195 __ mov(frame_->Top(), ecx); |
| 3197 } | 3196 } |
| 3198 | 3197 |
| 3199 | 3198 |
| 3200 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3199 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 3201 ASSERT(args->length() == 1); | 3200 ASSERT(args->length() == 1); |
| 3202 | 3201 |
| 3203 // Load the key onto the stack and set register eax to the formal | 3202 // Load the key onto the stack and set register eax to the formal |
| 3204 // parameters count for the currently executing function. | 3203 // parameters count for the currently executing function. |
| 3205 Load(args->at(0)); | 3204 Load(args->at(0)); |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3500 target.GetValue(NOT_INSIDE_TYPEOF); | 3499 target.GetValue(NOT_INSIDE_TYPEOF); |
| 3501 | 3500 |
| 3502 CountOperationDeferred* deferred = | 3501 CountOperationDeferred* deferred = |
| 3503 new CountOperationDeferred(this, is_postfix, is_increment, | 3502 new CountOperationDeferred(this, is_postfix, is_increment, |
| 3504 target.size() * kPointerSize); | 3503 target.size() * kPointerSize); |
| 3505 | 3504 |
| 3506 frame_->Pop(eax); // Load TOS into eax for calculations below | 3505 frame_->Pop(eax); // Load TOS into eax for calculations below |
| 3507 | 3506 |
| 3508 // Postfix: Store the old value as the result. | 3507 // Postfix: Store the old value as the result. |
| 3509 if (is_postfix) { | 3508 if (is_postfix) { |
| 3510 __ mov(frame_->Element(target.size()), eax); | 3509 __ mov(frame_->ElementAt(target.size()), eax); |
| 3511 } | 3510 } |
| 3512 | 3511 |
| 3513 // Perform optimistic increment/decrement. | 3512 // Perform optimistic increment/decrement. |
| 3514 if (is_increment) { | 3513 if (is_increment) { |
| 3515 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3514 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3516 } else { | 3515 } else { |
| 3517 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 3516 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3518 } | 3517 } |
| 3519 | 3518 |
| 3520 // If the count operation didn't overflow and the result is a | 3519 // If the count operation didn't overflow and the result is a |
| 3521 // valid smi, we're done. Otherwise, we jump to the deferred | 3520 // valid smi, we're done. Otherwise, we jump to the deferred |
| 3522 // slow-case code. | 3521 // slow-case code. |
| 3523 __ j(overflow, deferred->enter(), not_taken); | 3522 __ j(overflow, deferred->enter(), not_taken); |
| 3524 __ test(eax, Immediate(kSmiTagMask)); | 3523 __ test(eax, Immediate(kSmiTagMask)); |
| 3525 __ j(not_zero, deferred->enter(), not_taken); | 3524 __ j(not_zero, deferred->enter(), not_taken); |
| 3526 | 3525 |
| 3527 // Store the new value in the target if not const. | 3526 // Store the new value in the target if not const. |
| 3528 __ bind(deferred->exit()); | 3527 __ bind(deferred->exit()); |
| 3529 frame_->Push(eax); // Push the new value to TOS | 3528 frame_->Push(eax); // Push the new value to TOS |
| 3530 if (!is_const) target.SetValue(NOT_CONST_INIT); | 3529 if (!is_const) target.SetValue(NOT_CONST_INIT); |
| 3531 } | 3530 } |
| 3532 | 3531 |
| 3533 // Postfix: Discard the new value and use the old. | 3532 // Postfix: Discard the new value and use the old. |
| 3534 if (is_postfix) { | 3533 if (is_postfix) { |
| 3535 frame_->Pop(); | 3534 frame_->Drop(); |
| 3536 } | 3535 } |
| 3537 } | 3536 } |
| 3538 | 3537 |
| 3539 | 3538 |
| 3540 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 3539 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 3541 // Note that due to an optimization in comparison operations (typeof | 3540 // Note that due to an optimization in comparison operations (typeof |
| 3542 // compared to a string literal), we can evaluate a binary expression such | 3541 // compared to a string literal), we can evaluate a binary expression such |
| 3543 // as AND or OR and not leave a value on the frame or in the cc register. | 3542 // as AND or OR and not leave a value on the frame or in the cc register. |
| 3544 Comment cmnt(masm_, "[ BinaryOperation"); | 3543 Comment cmnt(masm_, "[ BinaryOperation"); |
| 3545 Token::Value op = node->op(); | 3544 Token::Value op = node->op(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3582 // 9.2, page 30. | 3581 // 9.2, page 30. |
| 3583 // | 3582 // |
| 3584 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3583 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3585 __ mov(eax, frame_->Top()); | 3584 __ mov(eax, frame_->Top()); |
| 3586 frame_->Push(eax); | 3585 frame_->Push(eax); |
| 3587 ToBoolean(&pop_and_continue, &exit); | 3586 ToBoolean(&pop_and_continue, &exit); |
| 3588 Branch(false, &exit); | 3587 Branch(false, &exit); |
| 3589 | 3588 |
| 3590 // Pop the result of evaluating the first part. | 3589 // Pop the result of evaluating the first part. |
| 3591 pop_and_continue.Bind(); | 3590 pop_and_continue.Bind(); |
| 3592 frame_->Pop(); | 3591 frame_->Drop(); |
| 3593 | 3592 |
| 3594 // Evaluate right side expression. | 3593 // Evaluate right side expression. |
| 3595 is_true.Bind(); | 3594 is_true.Bind(); |
| 3596 Load(node->right()); | 3595 Load(node->right()); |
| 3597 | 3596 |
| 3598 // Exit (always with a materialized value). | 3597 // Exit (always with a materialized value). |
| 3599 exit.Bind(); | 3598 exit.Bind(); |
| 3600 } | 3599 } |
| 3601 | 3600 |
| 3602 } else if (op == Token::OR) { | 3601 } else if (op == Token::OR) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 3625 // standard ToBoolean() conversion as described in ECMA-262, | 3624 // standard ToBoolean() conversion as described in ECMA-262, |
| 3626 // section 9.2, page 30. | 3625 // section 9.2, page 30. |
| 3627 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3626 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3628 __ mov(eax, frame_->Top()); | 3627 __ mov(eax, frame_->Top()); |
| 3629 frame_->Push(eax); | 3628 frame_->Push(eax); |
| 3630 ToBoolean(&exit, &pop_and_continue); | 3629 ToBoolean(&exit, &pop_and_continue); |
| 3631 Branch(true, &exit); | 3630 Branch(true, &exit); |
| 3632 | 3631 |
| 3633 // Pop the result of evaluating the first part. | 3632 // Pop the result of evaluating the first part. |
| 3634 pop_and_continue.Bind(); | 3633 pop_and_continue.Bind(); |
| 3635 frame_->Pop(); | 3634 frame_->Drop(); |
| 3636 | 3635 |
| 3637 // Evaluate right side expression. | 3636 // Evaluate right side expression. |
| 3638 is_false.Bind(); | 3637 is_false.Bind(); |
| 3639 Load(node->right()); | 3638 Load(node->right()); |
| 3640 | 3639 |
| 3641 // Exit (always with a materialized value). | 3640 // Exit (always with a materialized value). |
| 3642 exit.Bind(); | 3641 exit.Bind(); |
| 3643 } | 3642 } |
| 3644 | 3643 |
| 3645 } else { | 3644 } else { |
| (...skipping 1692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5338 | 5337 |
| 5339 // Slow-case: Go through the JavaScript implementation. | 5338 // Slow-case: Go through the JavaScript implementation. |
| 5340 __ bind(&slow); | 5339 __ bind(&slow); |
| 5341 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5340 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5342 } | 5341 } |
| 5343 | 5342 |
| 5344 | 5343 |
| 5345 #undef __ | 5344 #undef __ |
| 5346 | 5345 |
| 5347 } } // namespace v8::internal | 5346 } } // namespace v8::internal |
| OLD | NEW |