| 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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 for (int i = 0; i < scope_->num_parameters(); i++) { | 199 for (int i = 0; i < scope_->num_parameters(); i++) { |
| 200 Variable* par = scope_->parameter(i); | 200 Variable* par = scope_->parameter(i); |
| 201 Slot* slot = par->slot(); | 201 Slot* slot = par->slot(); |
| 202 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 202 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 203 // Save the arguments object pointer, if any. | 203 // Save the arguments object pointer, if any. |
| 204 if (arguments_object_allocated && !arguments_object_saved) { | 204 if (arguments_object_allocated && !arguments_object_saved) { |
| 205 frame_->Push(ecx); | 205 frame_->Push(ecx); |
| 206 arguments_object_saved = true; | 206 arguments_object_saved = true; |
| 207 } | 207 } |
| 208 ASSERT(!scope_->is_global_scope()); // no parameters in global scope | 208 ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
| 209 __ mov(eax, frame_->Parameter(i)); | 209 __ mov(eax, frame_->ParameterAt(i)); |
| 210 // Loads ecx with context; used below in RecordWrite. | 210 // Loads ecx with context; used below in RecordWrite. |
| 211 __ mov(SlotOperand(slot, ecx), eax); | 211 __ mov(SlotOperand(slot, ecx), eax); |
| 212 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 212 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 213 __ RecordWrite(ecx, offset, eax, ebx); | 213 __ RecordWrite(ecx, offset, eax, ebx); |
| 214 } | 214 } |
| 215 } | 215 } |
| 216 } | 216 } |
| 217 | 217 |
| 218 // This section stores the pointer to the arguments object that | 218 // This section stores the pointer to the arguments object that |
| 219 // was allocated and copied into above. If the address was not | 219 // was allocated and copied into above. If the address was not |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 // (such as the variable referring to a named function expression). | 313 // (such as the variable referring to a named function expression). |
| 314 // We need to implement assignments to read-only variables. | 314 // We need to implement assignments to read-only variables. |
| 315 // Ideally, we should do this during AST generation (by converting | 315 // Ideally, we should do this during AST generation (by converting |
| 316 // such assignments into expression statements); however, in general | 316 // such assignments into expression statements); however, in general |
| 317 // we may not be able to make the decision until past AST generation, | 317 // we may not be able to make the decision until past AST generation, |
| 318 // that is when the entire program is known. | 318 // that is when the entire program is known. |
| 319 ASSERT(slot != NULL); | 319 ASSERT(slot != NULL); |
| 320 int index = slot->index(); | 320 int index = slot->index(); |
| 321 switch (slot->type()) { | 321 switch (slot->type()) { |
| 322 case Slot::PARAMETER: | 322 case Slot::PARAMETER: |
| 323 return frame_->Parameter(index); | 323 return frame_->ParameterAt(index); |
| 324 | 324 |
| 325 case Slot::LOCAL: | 325 case Slot::LOCAL: |
| 326 return frame_->Local(index); | 326 return frame_->LocalAt(index); |
| 327 | 327 |
| 328 case Slot::CONTEXT: { | 328 case Slot::CONTEXT: { |
| 329 // Follow the context chain if necessary. | 329 // Follow the context chain if necessary. |
| 330 ASSERT(!tmp.is(esi)); // do not overwrite context register | 330 ASSERT(!tmp.is(esi)); // do not overwrite context register |
| 331 Register context = esi; | 331 Register context = esi; |
| 332 int chain_length = scope()->ContextChainLength(slot->var()->scope()); | 332 int chain_length = scope()->ContextChainLength(slot->var()->scope()); |
| 333 for (int i = chain_length; i-- > 0;) { | 333 for (int i = chain_length; i-- > 0;) { |
| 334 // Load the closure. | 334 // Load the closure. |
| 335 // (All contexts, even 'with' contexts, have a closure, | 335 // (All contexts, even 'with' contexts, have a closure, |
| 336 // and it is the same for all contexts inside a function. | 336 // and it is the same for all contexts inside a function. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 JumpTarget* false_target, | 370 JumpTarget* false_target, |
| 371 bool force_cc) { | 371 bool force_cc) { |
| 372 ASSERT(!has_cc()); | 372 ASSERT(!has_cc()); |
| 373 | 373 |
| 374 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 374 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 375 Visit(x); | 375 Visit(x); |
| 376 } | 376 } |
| 377 | 377 |
| 378 if (force_cc && frame_ != NULL && !has_cc()) { | 378 if (force_cc && frame_ != NULL && !has_cc()) { |
| 379 // Convert the TOS value to a boolean in the condition code register. | 379 // Convert the TOS value to a boolean in the condition code register. |
| 380 // Visiting an expression may possibly choose neither (a) to leave a | |
| 381 // value in the condition code register nor (b) to leave a value in TOS | |
| 382 // (eg, by compiling to only jumps to the targets). In that case the | |
| 383 // code generated by ToBoolean is wrong because it assumes the value of | |
| 384 // the expression in TOS. So long as there is always a value in TOS or | |
| 385 // the condition code register when control falls through to here (there | |
| 386 // is), the code generated by ToBoolean is dead and therefore safe. | |
| 387 ToBoolean(true_target, false_target); | 380 ToBoolean(true_target, false_target); |
| 388 } | 381 } |
| 389 | 382 |
| 390 ASSERT(!force_cc || frame_ == NULL || has_cc()); | 383 ASSERT(!force_cc || frame_ == NULL || has_cc()); |
| 391 } | 384 } |
| 392 | 385 |
| 393 | 386 |
| 394 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 387 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 395 JumpTarget true_target(this); | 388 JumpTarget true_target(this); |
| 396 JumpTarget false_target(this); | 389 JumpTarget false_target(this); |
| 397 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 390 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 398 | 391 |
| 399 if (has_cc()) { | 392 if (has_cc()) { |
| 400 ASSERT(frame_ != NULL); | 393 ASSERT(frame_ != NULL); |
| 401 // convert cc_reg_ into a bool | 394 // Convert cc_reg_ into a boolean value. |
| 402 JumpTarget loaded(this); | 395 JumpTarget loaded(this); |
| 403 JumpTarget materialize_true(this); | 396 JumpTarget materialize_true(this); |
| 404 materialize_true.Branch(cc_reg_); | 397 materialize_true.Branch(cc_reg_); |
| 405 frame_->Push(Immediate(Factory::false_value())); | 398 frame_->Push(Immediate(Factory::false_value())); |
| 406 loaded.Jump(); | 399 loaded.Jump(); |
| 407 materialize_true.Bind(); | 400 materialize_true.Bind(); |
| 408 frame_->Push(Immediate(Factory::true_value())); | 401 frame_->Push(Immediate(Factory::true_value())); |
| 409 loaded.Bind(); | 402 loaded.Bind(); |
| 410 cc_reg_ = no_condition; | 403 cc_reg_ = no_condition; |
| 411 } | 404 } |
| 412 | 405 |
| 413 if (true_target.is_linked() || false_target.is_linked()) { | 406 if (true_target.is_linked() || false_target.is_linked()) { |
| 414 // we have at least one condition value | 407 // We have at least one condition value that has been "translated" into |
| 415 // that has been "translated" into a branch, | 408 // a branch, thus it needs to be loaded explicitly. |
| 416 // thus it needs to be loaded explicitly again | |
| 417 JumpTarget loaded(this); | 409 JumpTarget loaded(this); |
| 418 if (frame_ != NULL) { | 410 if (frame_ != NULL) { |
| 419 loaded.Jump(); // don't lose current TOS | 411 loaded.Jump(); // Don't lose the current TOS. |
| 420 } | 412 } |
| 421 bool both = true_target.is_linked() && false_target.is_linked(); | 413 bool both = true_target.is_linked() && false_target.is_linked(); |
| 422 // reincarnate "true", if necessary | 414 // Load "true" if necessary. |
| 423 if (true_target.is_linked()) { | 415 if (true_target.is_linked()) { |
| 424 true_target.Bind(); | 416 true_target.Bind(); |
| 425 frame_->Push(Immediate(Factory::true_value())); | 417 frame_->Push(Immediate(Factory::true_value())); |
| 426 } | 418 } |
| 427 // if both "true" and "false" need to be reincarnated, | 419 // If both "true" and "false" need to be reincarnated jump across the |
| 428 // jump across code for "false" | 420 // code for "false". |
| 429 if (both) { | 421 if (both) { |
| 430 loaded.Jump(); | 422 loaded.Jump(); |
| 431 } | 423 } |
| 432 // reincarnate "false", if necessary | 424 // Load "false" if necessary. |
| 433 if (false_target.is_linked()) { | 425 if (false_target.is_linked()) { |
| 434 false_target.Bind(); | 426 false_target.Bind(); |
| 435 frame_->Push(Immediate(Factory::false_value())); | 427 frame_->Push(Immediate(Factory::false_value())); |
| 436 } | 428 } |
| 437 // everything is loaded at this point | 429 // A value is loaded on all paths reaching this point. |
| 438 loaded.Bind(); | 430 loaded.Bind(); |
| 439 } | 431 } |
| 432 ASSERT(frame_ != NULL); |
| 440 ASSERT(!has_cc()); | 433 ASSERT(!has_cc()); |
| 441 } | 434 } |
| 442 | 435 |
| 443 | 436 |
| 444 void CodeGenerator::LoadGlobal() { | 437 void CodeGenerator::LoadGlobal() { |
| 445 frame_->Push(GlobalObject()); | 438 frame_->Push(GlobalObject()); |
| 446 } | 439 } |
| 447 | 440 |
| 448 | 441 |
| 449 void CodeGenerator::LoadGlobalReceiver(Register scratch) { | 442 void CodeGenerator::LoadGlobalReceiver(Register scratch) { |
| (...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1233 Major MajorKey() { return CallFunction; } | 1226 Major MajorKey() { return CallFunction; } |
| 1234 int MinorKey() { return argc_; } | 1227 int MinorKey() { return argc_; } |
| 1235 }; | 1228 }; |
| 1236 | 1229 |
| 1237 | 1230 |
| 1238 // Call the function just below TOS on the stack with the given | 1231 // Call the function just below TOS on the stack with the given |
| 1239 // arguments. The receiver is the TOS. | 1232 // arguments. The receiver is the TOS. |
| 1240 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1233 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
| 1241 int position) { | 1234 int position) { |
| 1242 // Push the arguments ("left-to-right") on the stack. | 1235 // Push the arguments ("left-to-right") on the stack. |
| 1243 for (int i = 0; i < args->length(); i++) { | 1236 int arg_count = args->length(); |
| 1237 for (int i = 0; i < arg_count; i++) { |
| 1244 Load(args->at(i)); | 1238 Load(args->at(i)); |
| 1245 } | 1239 } |
| 1246 | 1240 |
| 1247 // Record the position for debugging purposes. | 1241 // Record the position for debugging purposes. |
| 1248 __ RecordPosition(position); | 1242 __ RecordPosition(position); |
| 1249 | 1243 |
| 1250 // Use the shared code stub to call the function. | 1244 // Use the shared code stub to call the function. |
| 1251 CallFunctionStub call_function(args->length()); | 1245 CallFunctionStub call_function(arg_count); |
| 1252 frame_->CallStub(&call_function, args->length() + 1); | 1246 frame_->CallStub(&call_function, arg_count + 1); |
| 1253 | 1247 |
| 1254 // Restore context and pop function from the stack. | 1248 // Restore context and pop function from the stack. |
| 1255 __ mov(esi, frame_->Context()); | 1249 __ mov(esi, frame_->Context()); |
| 1256 __ mov(frame_->Top(), eax); | 1250 __ mov(frame_->Top(), eax); |
| 1257 } | 1251 } |
| 1258 | 1252 |
| 1259 | 1253 |
| 1260 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { | 1254 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { |
| 1261 ASSERT(has_cc()); | 1255 ASSERT(has_cc()); |
| 1262 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1256 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1380 | 1374 |
| 1381 | 1375 |
| 1382 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1376 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1383 Comment cmnt(masm_, "// EmptyStatement"); | 1377 Comment cmnt(masm_, "// EmptyStatement"); |
| 1384 // nothing to do | 1378 // nothing to do |
| 1385 } | 1379 } |
| 1386 | 1380 |
| 1387 | 1381 |
| 1388 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1382 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1389 Comment cmnt(masm_, "[ IfStatement"); | 1383 Comment cmnt(masm_, "[ IfStatement"); |
| 1390 // Generate different code depending on which | 1384 // Generate different code depending on which parts of the if statement |
| 1391 // parts of the if statement are present or not. | 1385 // are present or not. |
| 1392 bool has_then_stm = node->HasThenStatement(); | 1386 bool has_then_stm = node->HasThenStatement(); |
| 1393 bool has_else_stm = node->HasElseStatement(); | 1387 bool has_else_stm = node->HasElseStatement(); |
| 1394 | 1388 |
| 1395 RecordStatementPosition(node); | 1389 RecordStatementPosition(node); |
| 1396 JumpTarget exit(this); | 1390 JumpTarget exit(this); |
| 1397 if (has_then_stm && has_else_stm) { | 1391 if (has_then_stm && has_else_stm) { |
| 1398 JumpTarget then(this); | 1392 JumpTarget then(this); |
| 1399 JumpTarget else_(this); | 1393 JumpTarget else_(this); |
| 1400 // if (cond) | 1394 // if (cond) |
| 1401 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1395 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1652 Load(node->tag()); | 1646 Load(node->tag()); |
| 1653 | 1647 |
| 1654 if (TryGenerateFastCaseSwitchStatement(node)) { | 1648 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1655 return; | 1649 return; |
| 1656 } | 1650 } |
| 1657 | 1651 |
| 1658 JumpTarget next_test(this); | 1652 JumpTarget next_test(this); |
| 1659 JumpTarget fall_through(this); | 1653 JumpTarget fall_through(this); |
| 1660 JumpTarget default_entry(this); | 1654 JumpTarget default_entry(this); |
| 1661 JumpTarget default_exit(this); | 1655 JumpTarget default_exit(this); |
| 1662 | |
| 1663 ZoneList<CaseClause*>* cases = node->cases(); | 1656 ZoneList<CaseClause*>* cases = node->cases(); |
| 1664 int length = cases->length(); | 1657 int length = cases->length(); |
| 1665 CaseClause* default_clause = NULL; | 1658 CaseClause* default_clause = NULL; |
| 1666 | 1659 |
| 1667 for (int i = 0; i < length; i++) { | 1660 for (int i = 0; i < length; i++) { |
| 1668 CaseClause* clause = cases->at(i); | 1661 CaseClause* clause = cases->at(i); |
| 1662 if (clause->is_default()) { |
| 1663 // Remember the default clause and compile it at the end. |
| 1664 default_clause = clause; |
| 1665 continue; |
| 1666 } |
| 1669 | 1667 |
| 1670 if (clause->is_default()) { | 1668 Comment cmnt(masm_, "[ Case clause"); |
| 1671 default_clause = clause; | 1669 // Compile the test. |
| 1670 next_test.Bind(); |
| 1671 next_test.Unuse(); |
| 1672 // Duplicate TOS. |
| 1673 __ mov(eax, frame_->Top()); |
| 1674 frame_->Push(eax); |
| 1675 Load(clause->label()); |
| 1676 Comparison(equal, true); |
| 1677 Branch(false, &next_test); |
| 1678 |
| 1679 // Before entering the body from the test, remove the switch value from |
| 1680 // the stack. |
| 1681 frame_->Drop(); |
| 1682 |
| 1683 // Label the body so that fall through is enabled. |
| 1684 if (i > 0 && cases->at(i - 1)->is_default()) { |
| 1685 default_exit.Bind(); |
| 1672 } else { | 1686 } else { |
| 1673 Comment cmnt(masm_, "[ Case clause"); | 1687 fall_through.Bind(); |
| 1688 fall_through.Unuse(); |
| 1689 } |
| 1690 VisitStatements(clause->statements()); |
| 1674 | 1691 |
| 1675 // Compile the test. | 1692 // If control flow can fall through from the body, jump to the next body |
| 1676 next_test.Bind(); | 1693 // or the end of the statement. |
| 1677 next_test.Unuse(); | 1694 if (frame_ != NULL) { |
| 1678 // Duplicate TOS. | 1695 if (i < length - 1 && cases->at(i + 1)->is_default()) { |
| 1679 __ mov(eax, frame_->Top()); | 1696 default_entry.Jump(); |
| 1680 frame_->Push(eax); | |
| 1681 Load(clause->label()); | |
| 1682 Comparison(equal, true); | |
| 1683 Branch(false, &next_test); | |
| 1684 | |
| 1685 // Before entering the body, remove the switch value from the stack. | |
| 1686 frame_->Drop(); | |
| 1687 | |
| 1688 // Label the body so that fall through is enabled. | |
| 1689 if (i > 0 && cases->at(i - 1)->is_default()) { | |
| 1690 default_exit.Bind(); | |
| 1691 } else { | 1697 } else { |
| 1692 fall_through.Bind(); | 1698 fall_through.Jump(); |
| 1693 fall_through.Unuse(); | |
| 1694 } | |
| 1695 VisitStatements(clause->statements()); | |
| 1696 | |
| 1697 // If control flow can fall through from the body jump to the | |
| 1698 // next body or end of the statement. | |
| 1699 if (frame_ != NULL) { | |
| 1700 if (i < length - 1 && cases->at(i + 1)->is_default()) { | |
| 1701 default_entry.Jump(); | |
| 1702 } else { | |
| 1703 fall_through.Jump(); | |
| 1704 } | |
| 1705 } | 1699 } |
| 1706 } | 1700 } |
| 1707 } | 1701 } |
| 1708 | 1702 |
| 1709 // The final test removes the switch value. | 1703 // The final "test" removes the switch value. |
| 1710 next_test.Bind(); | 1704 next_test.Bind(); |
| 1711 frame_->Drop(); | 1705 frame_->Drop(); |
| 1712 | 1706 |
| 1713 // If there is a default clause, compile it. | 1707 // If there is a default clause, compile it. |
| 1714 if (default_clause != NULL) { | 1708 if (default_clause != NULL) { |
| 1715 Comment cmnt(masm_, "[ Default clause"); | 1709 Comment cmnt(masm_, "[ Default clause"); |
| 1716 default_entry.Bind(); | 1710 default_entry.Bind(); |
| 1717 VisitStatements(default_clause->statements()); | 1711 VisitStatements(default_clause->statements()); |
| 1718 // If control flow can fall out of the default and there is a case after | 1712 // If control flow can fall out of the default and there is a case after |
| 1719 // it, jump to that case's body. | 1713 // it, jump to that case's body. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1752 info = ALWAYS_TRUE; | 1746 info = ALWAYS_TRUE; |
| 1753 } else if (lit->IsFalse()) { | 1747 } else if (lit->IsFalse()) { |
| 1754 info = ALWAYS_FALSE; | 1748 info = ALWAYS_FALSE; |
| 1755 } | 1749 } |
| 1756 } | 1750 } |
| 1757 } | 1751 } |
| 1758 | 1752 |
| 1759 switch (node->type()) { | 1753 switch (node->type()) { |
| 1760 case LoopStatement::DO_LOOP: { | 1754 case LoopStatement::DO_LOOP: { |
| 1761 JumpTarget body(this); | 1755 JumpTarget body(this); |
| 1762 | |
| 1763 IncrementLoopNesting(); | 1756 IncrementLoopNesting(); |
| 1764 // Label the body. | 1757 // Label the body. |
| 1765 if (info == ALWAYS_TRUE) { | 1758 if (info == ALWAYS_TRUE) { |
| 1766 node->continue_target()->Bind(); | 1759 node->continue_target()->Bind(); |
| 1767 } else if (info == ALWAYS_FALSE) { | 1760 } else if (info == ALWAYS_FALSE) { |
| 1768 // There is no need, we will never jump back. | 1761 // There is no need, we will never jump back. |
| 1769 } else { | 1762 } else { |
| 1770 ASSERT(info == DONT_KNOW); | 1763 ASSERT(info == DONT_KNOW); |
| 1771 body.Bind(); | 1764 body.Bind(); |
| 1772 } | 1765 } |
| 1773 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1766 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1774 Visit(node->body()); | 1767 Visit(node->body()); |
| 1775 | 1768 |
| 1769 // Compile the "test". |
| 1776 if (info == ALWAYS_TRUE) { | 1770 if (info == ALWAYS_TRUE) { |
| 1777 if (frame_ != NULL) { | 1771 if (frame_ != NULL) { |
| 1778 // If control flow can fall off the end of the body, jump back to | 1772 // If control flow can fall off the end of the body, jump back to |
| 1779 // the top. | 1773 // the top. |
| 1780 node->continue_target()->Jump(); | 1774 node->continue_target()->Jump(); |
| 1781 } | 1775 } |
| 1782 } else if (info == ALWAYS_FALSE) { | 1776 } else if (info == ALWAYS_FALSE) { |
| 1783 // If we have a continue in the body, we only have to bind its jump | 1777 // If we have a continue in the body, we only have to bind its jump |
| 1784 // target. | 1778 // target. |
| 1785 if (node->continue_target()->is_linked()) { | 1779 if (node->continue_target()->is_linked()) { |
| 1786 node->continue_target()->Bind(); | 1780 node->continue_target()->Bind(); |
| 1787 } | 1781 } |
| 1788 } else { | 1782 } else { |
| 1789 ASSERT(info == DONT_KNOW); | 1783 ASSERT(info == DONT_KNOW); |
| 1790 // We have to compile the test expression if we don't know its value | 1784 // We have to compile the test expression if it can be reached by |
| 1791 // and it can be reached by control flow falling out of the body or | 1785 // control flow falling out of the body or via continue. |
| 1792 // via continue. | |
| 1793 if (frame_ != NULL || node->continue_target()->is_linked()) { | 1786 if (frame_ != NULL || node->continue_target()->is_linked()) { |
| 1794 node->continue_target()->Bind(); | 1787 node->continue_target()->Bind(); |
| 1795 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, | 1788 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1796 &body, node->break_target(), true); | 1789 &body, node->break_target(), true); |
| 1797 if (frame_ != NULL) { | 1790 if (frame_ != NULL) { |
| 1798 // A NULL frame here indicates that control flow did not fall | 1791 // A NULL frame here indicates that control flow did not fall |
| 1799 // out of the test expression. | 1792 // out of the test expression. |
| 1800 Branch(true, &body); | 1793 Branch(true, &body); |
| 1801 } | 1794 } |
| 1802 } | 1795 } |
| 1803 } | 1796 } |
| 1804 break; | 1797 break; |
| 1805 } | 1798 } |
| 1806 | 1799 |
| 1807 case LoopStatement::WHILE_LOOP: { | 1800 case LoopStatement::WHILE_LOOP: { |
| 1808 | |
| 1809 JumpTarget body(this); | 1801 JumpTarget body(this); |
| 1810 | |
| 1811 IncrementLoopNesting(); | 1802 IncrementLoopNesting(); |
| 1812 // Generate the loop header. | 1803 // Generate the loop header. |
| 1813 if (info == ALWAYS_TRUE) { | 1804 if (info == ALWAYS_TRUE) { |
| 1814 // Merely label the body with the continue target. | 1805 // Merely label the body with the continue target. |
| 1815 node->continue_target()->Bind(); | 1806 node->continue_target()->Bind(); |
| 1816 } else if (info == ALWAYS_FALSE) { | 1807 } else if (info == ALWAYS_FALSE) { |
| 1817 // There is no need to even compile the test or body. | 1808 // There is no need to even compile the test or body. |
| 1818 break; | 1809 break; |
| 1819 } else { | 1810 } else { |
| 1820 // Compile the test labeled with the continue target and label the | 1811 // Compile the test labeled with the continue target and label the |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1919 | 1910 |
| 1920 // We keep stuff on the stack while the body is executing. | 1911 // We keep stuff on the stack while the body is executing. |
| 1921 // Record it, so that a break/continue crossing this statement | 1912 // Record it, so that a break/continue crossing this statement |
| 1922 // can restore the stack. | 1913 // can restore the stack. |
| 1923 const int kForInStackSize = 5 * kPointerSize; | 1914 const int kForInStackSize = 5 * kPointerSize; |
| 1924 break_stack_height_ += kForInStackSize; | 1915 break_stack_height_ += kForInStackSize; |
| 1925 node->set_break_stack_height(break_stack_height_); | 1916 node->set_break_stack_height(break_stack_height_); |
| 1926 node->break_target()->set_code_generator(this); | 1917 node->break_target()->set_code_generator(this); |
| 1927 node->continue_target()->set_code_generator(this); | 1918 node->continue_target()->set_code_generator(this); |
| 1928 | 1919 |
| 1920 JumpTarget primitive(this); |
| 1921 JumpTarget jsobject(this); |
| 1922 JumpTarget fixed_array(this); |
| 1929 JumpTarget entry(this); | 1923 JumpTarget entry(this); |
| 1924 JumpTarget end_del_check(this); |
| 1930 JumpTarget cleanup(this); | 1925 JumpTarget cleanup(this); |
| 1931 JumpTarget exit(this); | 1926 JumpTarget exit(this); |
| 1932 JumpTarget primitive(this); | |
| 1933 JumpTarget jsobject(this); | |
| 1934 JumpTarget end_del_check(this); | |
| 1935 JumpTarget fixed_array(this); | |
| 1936 | 1927 |
| 1937 // Get the object to enumerate over (converted to JSObject). | 1928 // Get the object to enumerate over (converted to JSObject). |
| 1938 Load(node->enumerable()); | 1929 Load(node->enumerable()); |
| 1939 | 1930 |
| 1940 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1931 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 1941 // to the specification. 12.6.4 mandates a call to ToObject. | 1932 // to the specification. 12.6.4 mandates a call to ToObject. |
| 1942 frame_->Pop(eax); | 1933 frame_->Pop(eax); |
| 1943 | 1934 |
| 1944 // eax: value to be iterated over | 1935 // eax: value to be iterated over |
| 1945 __ cmp(eax, Factory::undefined_value()); | 1936 __ cmp(eax, Factory::undefined_value()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1961 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 1952 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 1962 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 1953 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 1963 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 1954 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 1964 jsobject.Branch(above_equal); | 1955 jsobject.Branch(above_equal); |
| 1965 | 1956 |
| 1966 primitive.Bind(); | 1957 primitive.Bind(); |
| 1967 frame_->Push(eax); | 1958 frame_->Push(eax); |
| 1968 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); | 1959 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); |
| 1969 // function call returns the value in eax, which is where we want it below | 1960 // function call returns the value in eax, which is where we want it below |
| 1970 | 1961 |
| 1971 | |
| 1972 jsobject.Bind(); | 1962 jsobject.Bind(); |
| 1973 | |
| 1974 // Get the set of properties (as a FixedArray or Map). | 1963 // Get the set of properties (as a FixedArray or Map). |
| 1975 // eax: value to be iterated over | 1964 // eax: value to be iterated over |
| 1976 frame_->Push(eax); // push the object being iterated over (slot 4) | 1965 frame_->Push(eax); // push the object being iterated over (slot 4) |
| 1977 | 1966 |
| 1978 frame_->Push(eax); // push the Object (slot 4) for the runtime call | 1967 frame_->Push(eax); // push the Object (slot 4) for the runtime call |
| 1979 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 1968 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 1980 | 1969 |
| 1981 // If we got a Map, we can do a fast modification check. | 1970 // If we got a Map, we can do a fast modification check. |
| 1982 // Otherwise, we got a FixedArray, and we have to do a slow check. | 1971 // Otherwise, we got a FixedArray, and we have to do a slow check. |
| 1983 // eax: map or fixed array (result from call to | 1972 // eax: map or fixed array (result from call to |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1997 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 1986 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 1998 | 1987 |
| 1999 frame_->Push(eax); // <- slot 3 | 1988 frame_->Push(eax); // <- slot 3 |
| 2000 frame_->Push(edx); // <- slot 2 | 1989 frame_->Push(edx); // <- slot 2 |
| 2001 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); | 1990 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); |
| 2002 __ shl(eax, kSmiTagSize); | 1991 __ shl(eax, kSmiTagSize); |
| 2003 frame_->Push(eax); // <- slot 1 | 1992 frame_->Push(eax); // <- slot 1 |
| 2004 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 | 1993 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 2005 entry.Jump(); | 1994 entry.Jump(); |
| 2006 | 1995 |
| 2007 | |
| 2008 fixed_array.Bind(); | 1996 fixed_array.Bind(); |
| 2009 | |
| 2010 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) | 1997 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) |
| 2011 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3 | 1998 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3 |
| 2012 frame_->Push(eax); // <- slot 2 | 1999 frame_->Push(eax); // <- slot 2 |
| 2013 | 2000 |
| 2014 // Push the length of the array and the initial index onto the stack. | 2001 // Push the length of the array and the initial index onto the stack. |
| 2015 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 2002 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 2016 __ shl(eax, kSmiTagSize); | 2003 __ shl(eax, kSmiTagSize); |
| 2017 frame_->Push(eax); // <- slot 1 | 2004 frame_->Push(eax); // <- slot 1 |
| 2018 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 | 2005 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 2019 | 2006 |
| 2020 // Condition. | 2007 // Condition. |
| 2021 entry.Bind(); | 2008 entry.Bind(); |
| 2022 | |
| 2023 __ mov(eax, frame_->ElementAt(0)); // load the current count | 2009 __ mov(eax, frame_->ElementAt(0)); // load the current count |
| 2024 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length | 2010 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length |
| 2025 cleanup.Branch(above_equal); | 2011 cleanup.Branch(above_equal); |
| 2026 | 2012 |
| 2027 // Get the i'th entry of the array. | 2013 // Get the i'th entry of the array. |
| 2028 __ mov(edx, frame_->ElementAt(2)); | 2014 __ mov(edx, frame_->ElementAt(2)); |
| 2029 __ mov(ebx, Operand(edx, eax, times_2, | 2015 __ mov(ebx, Operand(edx, eax, times_2, |
| 2030 FixedArray::kHeaderSize - kHeapObjectTag)); | 2016 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 2031 | 2017 |
| 2032 // Get the expected map from the stack or a zero map in the | 2018 // Get the expected map from the stack or a zero map in the |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2047 frame_->Push(frame_->ElementAt(4)); // push enumerable | 2033 frame_->Push(frame_->ElementAt(4)); // push enumerable |
| 2048 frame_->Push(ebx); // push entry | 2034 frame_->Push(ebx); // push entry |
| 2049 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); | 2035 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); |
| 2050 __ mov(ebx, Operand(eax)); | 2036 __ mov(ebx, Operand(eax)); |
| 2051 | 2037 |
| 2052 // If the property has been removed while iterating, we just skip it. | 2038 // If the property has been removed while iterating, we just skip it. |
| 2053 __ cmp(ebx, Factory::null_value()); | 2039 __ cmp(ebx, Factory::null_value()); |
| 2054 node->continue_target()->Branch(equal); | 2040 node->continue_target()->Branch(equal); |
| 2055 | 2041 |
| 2056 end_del_check.Bind(); | 2042 end_del_check.Bind(); |
| 2057 // Store the entry in the 'each' expression and take another spin in the loop. | 2043 // Store the entry in the 'each' expression and take another spin in the |
| 2058 // edx: i'th entry of the enum cache (or string there of) | 2044 // loop. edx: i'th entry of the enum cache (or string there of) |
| 2059 frame_->Push(ebx); | 2045 frame_->Push(ebx); |
| 2060 { Reference each(this, node->each()); | 2046 { Reference each(this, node->each()); |
| 2061 if (!each.is_illegal()) { | 2047 if (!each.is_illegal()) { |
| 2062 if (each.size() > 0) { | 2048 if (each.size() > 0) { |
| 2063 frame_->Push(frame_->ElementAt(each.size())); | 2049 frame_->Push(frame_->ElementAt(each.size())); |
| 2064 } | 2050 } |
| 2065 // If the reference was to a slot we rely on the convenient property | 2051 // If the reference was to a slot we rely on the convenient property |
| 2066 // that it doesn't matter whether a value (eg, ebx pushed above) is | 2052 // that it doesn't matter whether a value (eg, ebx pushed above) is |
| 2067 // right on top of or right underneath a zero-sized reference. | 2053 // right on top of or right underneath a zero-sized reference. |
| 2068 each.SetValue(NOT_CONST_INIT); | 2054 each.SetValue(NOT_CONST_INIT); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2203 // break from (eg, for...in) may have left stuff on the stack. | 2189 // break from (eg, for...in) may have left stuff on the stack. |
| 2204 __ mov(edx, Operand::StaticVariable(handler_address)); | 2190 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2205 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2191 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2206 StackHandlerConstants::kAddressDisplacement; | 2192 StackHandlerConstants::kAddressDisplacement; |
| 2207 __ lea(esp, Operand(edx, kNextOffset)); | 2193 __ lea(esp, Operand(edx, kNextOffset)); |
| 2208 frame_->Forget(frame_->height() - handler_height); | 2194 frame_->Forget(frame_->height() - handler_height); |
| 2209 | 2195 |
| 2210 frame_->Pop(Operand::StaticVariable(handler_address)); | 2196 frame_->Pop(Operand::StaticVariable(handler_address)); |
| 2211 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2197 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2212 // next_sp popped. | 2198 // next_sp popped. |
| 2213 JumpTarget* original_target = shadows[i]->original_target(); | 2199 shadows[i]->original_target()->Jump(); |
| 2214 original_target->Jump(); | |
| 2215 } | 2200 } |
| 2216 } | 2201 } |
| 2217 | 2202 |
| 2218 exit.Bind(); | 2203 exit.Bind(); |
| 2219 } | 2204 } |
| 2220 | 2205 |
| 2221 | 2206 |
| 2222 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 2207 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2223 Comment cmnt(masm_, "[ TryFinally"); | 2208 Comment cmnt(masm_, "[ TryFinally"); |
| 2224 | 2209 |
| 2225 // State: Used to keep track of reason for entering the finally | 2210 // State: Used to keep track of reason for entering the finally |
| 2226 // block. Should probably be extended to hold information for | 2211 // block. Should probably be extended to hold information for |
| 2227 // break/continue from within the try block. | 2212 // break/continue from within the try block. |
| 2228 enum { FALLING, THROWING, JUMPING }; | 2213 enum { FALLING, THROWING, JUMPING }; |
| 2229 | 2214 |
| 2230 JumpTarget exit(this); | |
| 2231 JumpTarget unlink(this); | 2215 JumpTarget unlink(this); |
| 2232 JumpTarget try_block(this); | 2216 JumpTarget try_block(this); |
| 2233 JumpTarget finally_block(this); | 2217 JumpTarget finally_block(this); |
| 2234 | 2218 |
| 2235 try_block.Call(); | 2219 try_block.Call(); |
| 2236 | 2220 |
| 2237 frame_->Push(eax); | 2221 frame_->Push(eax); |
| 2238 // In case of thrown exceptions, this is where we continue. | 2222 // In case of thrown exceptions, this is where we continue. |
| 2239 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); | 2223 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); |
| 2240 finally_block.Jump(); | 2224 finally_block.Jump(); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2335 // that a break/continue crossing this statement can restore the | 2319 // that a break/continue crossing this statement can restore the |
| 2336 // stack. | 2320 // stack. |
| 2337 const int kFinallyStackSize = 2 * kPointerSize; | 2321 const int kFinallyStackSize = 2 * kPointerSize; |
| 2338 break_stack_height_ += kFinallyStackSize; | 2322 break_stack_height_ += kFinallyStackSize; |
| 2339 | 2323 |
| 2340 // Generate code for the statements in the finally block. | 2324 // Generate code for the statements in the finally block. |
| 2341 VisitStatements(node->finally_block()->statements()); | 2325 VisitStatements(node->finally_block()->statements()); |
| 2342 | 2326 |
| 2343 break_stack_height_ -= kFinallyStackSize; | 2327 break_stack_height_ -= kFinallyStackSize; |
| 2344 if (frame_ != NULL) { | 2328 if (frame_ != NULL) { |
| 2329 JumpTarget exit(this); |
| 2345 // Restore state and return value or faked TOS. | 2330 // Restore state and return value or faked TOS. |
| 2346 frame_->Pop(ecx); | 2331 frame_->Pop(ecx); |
| 2347 frame_->Pop(eax); | 2332 frame_->Pop(eax); |
| 2348 | 2333 |
| 2349 // Generate code to jump to the right destination for all used | 2334 // Generate code to jump to the right destination for all used |
| 2350 // (formerly) shadowing targets. | 2335 // (formerly) shadowing targets. |
| 2351 for (int i = 0; i <= nof_escapes; i++) { | 2336 for (int i = 0; i <= nof_escapes; i++) { |
| 2352 if (shadows[i]->is_bound()) { | 2337 if (shadows[i]->is_bound()) { |
| 2353 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); | 2338 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); |
| 2354 shadows[i]->original_target()->Branch(equal); | 2339 shadows[i]->original_target()->Branch(equal); |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2637 case ObjectLiteral::Property::CONSTANT: break; | 2622 case ObjectLiteral::Property::CONSTANT: break; |
| 2638 case ObjectLiteral::Property::COMPUTED: { | 2623 case ObjectLiteral::Property::COMPUTED: { |
| 2639 Handle<Object> key(property->key()->handle()); | 2624 Handle<Object> key(property->key()->handle()); |
| 2640 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2625 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 2641 if (key->IsSymbol()) { | 2626 if (key->IsSymbol()) { |
| 2642 __ mov(eax, frame_->Top()); | 2627 __ mov(eax, frame_->Top()); |
| 2643 frame_->Push(eax); | 2628 frame_->Push(eax); |
| 2644 Load(property->value()); | 2629 Load(property->value()); |
| 2645 frame_->Pop(eax); | 2630 frame_->Pop(eax); |
| 2646 __ Set(ecx, Immediate(key)); | 2631 __ Set(ecx, Immediate(key)); |
| 2647 frame_->CallCode(ic, RelocInfo::CODE_TARGET, 0); | 2632 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 2648 frame_->Drop(); | 2633 frame_->Drop(); |
| 2649 // Ignore result. | 2634 // Ignore result. |
| 2650 break; | 2635 break; |
| 2651 } | 2636 } |
| 2652 // Fall through | 2637 // Fall through |
| 2653 } | 2638 } |
| 2654 case ObjectLiteral::Property::PROTOTYPE: { | 2639 case ObjectLiteral::Property::PROTOTYPE: { |
| 2655 __ mov(eax, frame_->Top()); | 2640 __ mov(eax, frame_->Top()); |
| 2656 frame_->Push(eax); | 2641 frame_->Push(eax); |
| 2657 Load(property->key()); | 2642 Load(property->key()); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2835 | 2820 |
| 2836 // Push the name of the function and the receiver onto the stack. | 2821 // Push the name of the function and the receiver onto the stack. |
| 2837 frame_->Push(Immediate(var->name())); | 2822 frame_->Push(Immediate(var->name())); |
| 2838 | 2823 |
| 2839 // Pass the global object as the receiver and let the IC stub | 2824 // Pass the global object as the receiver and let the IC stub |
| 2840 // patch the stack to use the global proxy as 'this' in the | 2825 // patch the stack to use the global proxy as 'this' in the |
| 2841 // invoked function. | 2826 // invoked function. |
| 2842 LoadGlobal(); | 2827 LoadGlobal(); |
| 2843 | 2828 |
| 2844 // Load the arguments. | 2829 // Load the arguments. |
| 2845 for (int i = 0; i < args->length(); i++) { | 2830 int arg_count = args->length(); |
| 2831 for (int i = 0; i < arg_count; i++) { |
| 2846 Load(args->at(i)); | 2832 Load(args->at(i)); |
| 2847 } | 2833 } |
| 2848 | 2834 |
| 2849 // Setup the receiver register and call the IC initialization code. | 2835 // Setup the receiver register and call the IC initialization code. |
| 2850 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2836 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 2851 __ RecordPosition(node->position()); | 2837 __ RecordPosition(node->position()); |
| 2852 frame_->CallCode(stub, RelocInfo::CODE_TARGET_CONTEXT, args->length() + 1); | 2838 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, |
| 2839 arg_count + 1); |
| 2853 __ mov(esi, frame_->Context()); | 2840 __ mov(esi, frame_->Context()); |
| 2854 | 2841 |
| 2855 // Overwrite the function on the stack with the result. | 2842 // Overwrite the function on the stack with the result. |
| 2856 __ mov(frame_->Top(), eax); | 2843 __ mov(frame_->Top(), eax); |
| 2857 | 2844 |
| 2858 } else if (var != NULL && var->slot() != NULL && | 2845 } else if (var != NULL && var->slot() != NULL && |
| 2859 var->slot()->type() == Slot::LOOKUP) { | 2846 var->slot()->type() == Slot::LOOKUP) { |
| 2860 // ---------------------------------- | 2847 // ---------------------------------- |
| 2861 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj | 2848 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj |
| 2862 // ---------------------------------- | 2849 // ---------------------------------- |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2881 if (literal != NULL && literal->handle()->IsSymbol()) { | 2868 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 2882 // ------------------------------------------------------------------ | 2869 // ------------------------------------------------------------------ |
| 2883 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 2870 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
| 2884 // ------------------------------------------------------------------ | 2871 // ------------------------------------------------------------------ |
| 2885 | 2872 |
| 2886 // Push the name of the function and the receiver onto the stack. | 2873 // Push the name of the function and the receiver onto the stack. |
| 2887 frame_->Push(Immediate(literal->handle())); | 2874 frame_->Push(Immediate(literal->handle())); |
| 2888 Load(property->obj()); | 2875 Load(property->obj()); |
| 2889 | 2876 |
| 2890 // Load the arguments. | 2877 // Load the arguments. |
| 2891 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2878 int arg_count = args->length(); |
| 2879 for (int i = 0; i < arg_count; i++) { |
| 2880 Load(args->at(i)); |
| 2881 } |
| 2892 | 2882 |
| 2893 // Call the IC initialization code. | 2883 // Call the IC initialization code. |
| 2894 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2884 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 2895 __ RecordPosition(node->position()); | 2885 __ RecordPosition(node->position()); |
| 2896 frame_->CallCode(stub, RelocInfo::CODE_TARGET, args->length() + 1); | 2886 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 2897 __ mov(esi, frame_->Context()); | 2887 __ mov(esi, frame_->Context()); |
| 2898 | 2888 |
| 2899 // Overwrite the function on the stack with the result. | 2889 // Overwrite the function on the stack with the result. |
| 2900 __ mov(frame_->Top(), eax); | 2890 __ mov(frame_->Top(), eax); |
| 2901 | 2891 |
| 2902 } else { | 2892 } else { |
| 2903 // ------------------------------------------- | 2893 // ------------------------------------------- |
| 2904 // JavaScript example: 'array[index](1, 2, 3)' | 2894 // JavaScript example: 'array[index](1, 2, 3)' |
| 2905 // ------------------------------------------- | 2895 // ------------------------------------------- |
| 2906 | 2896 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2943 // evaluated. | 2933 // evaluated. |
| 2944 | 2934 |
| 2945 // Compute function to call and use the global object as the | 2935 // Compute function to call and use the global object as the |
| 2946 // receiver. There is no need to use the global proxy here because | 2936 // receiver. There is no need to use the global proxy here because |
| 2947 // it will always be replaced with a newly allocated object. | 2937 // it will always be replaced with a newly allocated object. |
| 2948 Load(node->expression()); | 2938 Load(node->expression()); |
| 2949 LoadGlobal(); | 2939 LoadGlobal(); |
| 2950 | 2940 |
| 2951 // Push the arguments ("left-to-right") on the stack. | 2941 // Push the arguments ("left-to-right") on the stack. |
| 2952 ZoneList<Expression*>* args = node->arguments(); | 2942 ZoneList<Expression*>* args = node->arguments(); |
| 2953 for (int i = 0; i < args->length(); i++) { | 2943 int arg_count = args->length(); |
| 2944 for (int i = 0; i < arg_count; i++) { |
| 2954 Load(args->at(i)); | 2945 Load(args->at(i)); |
| 2955 } | 2946 } |
| 2956 | 2947 |
| 2957 // Constructors are called with the number of arguments in register | 2948 // Constructors are called with the number of arguments in register |
| 2958 // eax for now. Another option would be to have separate construct | 2949 // eax for now. Another option would be to have separate construct |
| 2959 // call trampolines per different arguments counts encountered. | 2950 // call trampolines per different arguments counts encountered. |
| 2960 __ Set(eax, Immediate(args->length())); | 2951 __ Set(eax, Immediate(arg_count)); |
| 2961 | 2952 |
| 2962 // Load the function into temporary function slot as per calling | 2953 // Load the function into temporary function slot as per calling |
| 2963 // convention. | 2954 // convention. |
| 2964 __ mov(edi, frame_->ElementAt(args->length() + 1)); | 2955 __ mov(edi, frame_->ElementAt(arg_count + 1)); |
| 2965 | 2956 |
| 2966 // Call the construct call builtin that handles allocation and | 2957 // Call the construct call builtin that handles allocation and |
| 2967 // constructor invocation. | 2958 // constructor invocation. |
| 2968 __ RecordPosition(node->position()); | 2959 __ RecordPosition(node->position()); |
| 2969 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 2960 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
| 2970 frame_->CallCode(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); | 2961 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); |
| 2971 // Discard the function and "push" the newly created object. | 2962 // Discard the function and "push" the newly created object. |
| 2972 __ mov(frame_->Top(), eax); | 2963 __ mov(frame_->Top(), eax); |
| 2973 } | 2964 } |
| 2974 | 2965 |
| 2975 | 2966 |
| 2976 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2967 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 2977 ASSERT(args->length() == 1); | 2968 ASSERT(args->length() == 1); |
| 2978 Load(args->at(0)); | 2969 Load(args->at(0)); |
| 2979 frame_->Pop(eax); | 2970 frame_->Pop(eax); |
| 2980 __ test(eax, Immediate(kSmiTagMask)); | 2971 __ test(eax, Immediate(kSmiTagMask)); |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3235 | 3226 |
| 3236 if (function == NULL) { | 3227 if (function == NULL) { |
| 3237 // Prepare stack for calling JS runtime function. | 3228 // Prepare stack for calling JS runtime function. |
| 3238 frame_->Push(Immediate(node->name())); | 3229 frame_->Push(Immediate(node->name())); |
| 3239 // Push the builtins object found in the current global object. | 3230 // Push the builtins object found in the current global object. |
| 3240 __ mov(edx, GlobalObject()); | 3231 __ mov(edx, GlobalObject()); |
| 3241 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); | 3232 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); |
| 3242 } | 3233 } |
| 3243 | 3234 |
| 3244 // Push the arguments ("left-to-right"). | 3235 // Push the arguments ("left-to-right"). |
| 3245 for (int i = 0; i < args->length(); i++) { | 3236 int arg_count = args->length(); |
| 3237 for (int i = 0; i < arg_count; i++) { |
| 3246 Load(args->at(i)); | 3238 Load(args->at(i)); |
| 3247 } | 3239 } |
| 3248 | 3240 |
| 3249 if (function == NULL) { | 3241 if (function == NULL) { |
| 3250 // Call the JS runtime function. | 3242 // Call the JS runtime function. |
| 3251 Handle<Code> stub = ComputeCallInitialize(args->length()); | 3243 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 3252 __ Set(eax, Immediate(args->length())); | 3244 __ Set(eax, Immediate(args->length())); |
| 3253 frame_->CallCode(stub, RelocInfo::CODE_TARGET, args->length() + 1); | 3245 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 3254 __ mov(esi, frame_->Context()); | 3246 __ mov(esi, frame_->Context()); |
| 3255 __ mov(frame_->Top(), eax); | 3247 __ mov(frame_->Top(), eax); |
| 3256 } else { | 3248 } else { |
| 3257 // Call the C runtime function. | 3249 // Call the C runtime function. |
| 3258 frame_->CallRuntime(function, args->length()); | 3250 frame_->CallRuntime(function, arg_count); |
| 3259 frame_->Push(eax); | 3251 frame_->Push(eax); |
| 3260 } | 3252 } |
| 3261 } | 3253 } |
| 3262 | 3254 |
| 3263 | 3255 |
| 3264 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 3256 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 3265 // Note that because of NOT and an optimization in comparison of a typeof | 3257 // Note that because of NOT and an optimization in comparison of a typeof |
| 3266 // expression to a literal string, this function can fail to leave a value | 3258 // expression to a literal string, this function can fail to leave a value |
| 3267 // on top of the frame or in the cc register. | 3259 // on top of the frame or in the cc register. |
| 3268 Comment cmnt(masm_, "[ UnaryOperation"); | 3260 Comment cmnt(masm_, "[ UnaryOperation"); |
| (...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3961 // loads must not throw a reference error). | 3953 // loads must not throw a reference error). |
| 3962 Comment cmnt(masm, "[ Load from named Property"); | 3954 Comment cmnt(masm, "[ Load from named Property"); |
| 3963 Handle<String> name(GetName()); | 3955 Handle<String> name(GetName()); |
| 3964 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3956 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 3965 // Setup the name register. | 3957 // Setup the name register. |
| 3966 __ mov(ecx, name); | 3958 __ mov(ecx, name); |
| 3967 | 3959 |
| 3968 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3960 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3969 if (var != NULL) { | 3961 if (var != NULL) { |
| 3970 ASSERT(var->is_global()); | 3962 ASSERT(var->is_global()); |
| 3971 frame->CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 3963 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 3972 } else { | 3964 } else { |
| 3973 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); | 3965 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 3974 } | 3966 } |
| 3975 frame->Push(eax); // IC call leaves result in eax, push it out | 3967 frame->Push(eax); // IC call leaves result in eax, push it out |
| 3976 break; | 3968 break; |
| 3977 } | 3969 } |
| 3978 | 3970 |
| 3979 case KEYED: { | 3971 case KEYED: { |
| 3980 // TODO(1241834): Make sure that this it is safe to ignore the | 3972 // TODO(1241834): Make sure that this it is safe to ignore the |
| 3981 // distinction between expressions in a typeof and not in a typeof. | 3973 // distinction between expressions in a typeof and not in a typeof. |
| 3982 Comment cmnt(masm, "[ Load from keyed Property"); | 3974 Comment cmnt(masm, "[ Load from keyed Property"); |
| 3983 Property* property = expression_->AsProperty(); | 3975 Property* property = expression_->AsProperty(); |
| 3984 ASSERT(property != NULL); | 3976 ASSERT(property != NULL); |
| 3985 __ RecordPosition(property->position()); | 3977 __ RecordPosition(property->position()); |
| 3986 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 3978 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 3987 | 3979 |
| 3988 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3980 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3989 if (var != NULL) { | 3981 if (var != NULL) { |
| 3990 ASSERT(var->is_global()); | 3982 ASSERT(var->is_global()); |
| 3991 frame->CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 3983 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 3992 } else { | 3984 } else { |
| 3993 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); | 3985 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 3994 } | 3986 } |
| 3995 frame->Push(eax); // IC call leaves result in eax, push it out | 3987 frame->Push(eax); // IC call leaves result in eax, push it out |
| 3996 break; | 3988 break; |
| 3997 } | 3989 } |
| 3998 | 3990 |
| 3999 default: | 3991 default: |
| 4000 UNREACHABLE(); | 3992 UNREACHABLE(); |
| 4001 } | 3993 } |
| 4002 } | 3994 } |
| 4003 | 3995 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4087 | 4079 |
| 4088 case NAMED: { | 4080 case NAMED: { |
| 4089 Comment cmnt(masm, "[ Store to named Property"); | 4081 Comment cmnt(masm, "[ Store to named Property"); |
| 4090 // Call the appropriate IC code. | 4082 // Call the appropriate IC code. |
| 4091 Handle<String> name(GetName()); | 4083 Handle<String> name(GetName()); |
| 4092 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4084 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 4093 // TODO(1222589): Make the IC grab the values from the stack. | 4085 // TODO(1222589): Make the IC grab the values from the stack. |
| 4094 frame->Pop(eax); | 4086 frame->Pop(eax); |
| 4095 // Setup the name register. | 4087 // Setup the name register. |
| 4096 __ mov(ecx, name); | 4088 __ mov(ecx, name); |
| 4097 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); | 4089 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4098 frame->Push(eax); // IC call leaves result in eax, push it out | 4090 frame->Push(eax); // IC call leaves result in eax, push it out |
| 4099 break; | 4091 break; |
| 4100 } | 4092 } |
| 4101 | 4093 |
| 4102 case KEYED: { | 4094 case KEYED: { |
| 4103 Comment cmnt(masm, "[ Store to keyed Property"); | 4095 Comment cmnt(masm, "[ Store to keyed Property"); |
| 4104 Property* property = expression_->AsProperty(); | 4096 Property* property = expression_->AsProperty(); |
| 4105 ASSERT(property != NULL); | 4097 ASSERT(property != NULL); |
| 4106 __ RecordPosition(property->position()); | 4098 __ RecordPosition(property->position()); |
| 4107 // Call IC code. | 4099 // Call IC code. |
| 4108 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 4100 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 4109 // TODO(1222589): Make the IC grab the values from the stack. | 4101 // TODO(1222589): Make the IC grab the values from the stack. |
| 4110 frame->Pop(eax); | 4102 frame->Pop(eax); |
| 4111 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); | 4103 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4112 frame->Push(eax); // IC call leaves result in eax, push it out | 4104 frame->Push(eax); // IC call leaves result in eax, push it out |
| 4113 break; | 4105 break; |
| 4114 } | 4106 } |
| 4115 | 4107 |
| 4116 default: | 4108 default: |
| 4117 UNREACHABLE(); | 4109 UNREACHABLE(); |
| 4118 } | 4110 } |
| 4119 } | 4111 } |
| 4120 | 4112 |
| 4121 | 4113 |
| (...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5337 | 5329 |
| 5338 // Slow-case: Go through the JavaScript implementation. | 5330 // Slow-case: Go through the JavaScript implementation. |
| 5339 __ bind(&slow); | 5331 __ bind(&slow); |
| 5340 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5332 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5341 } | 5333 } |
| 5342 | 5334 |
| 5343 | 5335 |
| 5344 #undef __ | 5336 #undef __ |
| 5345 | 5337 |
| 5346 } } // namespace v8::internal | 5338 } } // namespace v8::internal |
| OLD | NEW |