| 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 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 bool arguments_object_saved = false; | 139 bool arguments_object_saved = false; |
| 140 | 140 |
| 141 // Allocate arguments object. | 141 // Allocate arguments object. |
| 142 // The arguments object pointer needs to be saved in ecx, since we need | 142 // The arguments object pointer needs to be saved in ecx, since we need |
| 143 // to store arguments into the context. | 143 // to store arguments into the context. |
| 144 if (scope_->arguments() != NULL) { | 144 if (scope_->arguments() != NULL) { |
| 145 ASSERT(scope_->arguments_shadow() != NULL); | 145 ASSERT(scope_->arguments_shadow() != NULL); |
| 146 Comment cmnt(masm_, "[ allocate arguments object"); | 146 Comment cmnt(masm_, "[ allocate arguments object"); |
| 147 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 147 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 148 __ lea(eax, frame_->Receiver()); | 148 __ lea(eax, frame_->Receiver()); |
| 149 frame_->Push(frame_->Function()); | 149 frame_->EmitPush(frame_->Function()); |
| 150 frame_->Push(eax); | 150 frame_->EmitPush(eax); |
| 151 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters()))); | 151 frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 152 frame_->CallStub(&stub, 3); | 152 frame_->CallStub(&stub, 3); |
| 153 __ mov(ecx, Operand(eax)); | 153 __ mov(ecx, Operand(eax)); |
| 154 arguments_object_allocated = true; | 154 arguments_object_allocated = true; |
| 155 } | 155 } |
| 156 | 156 |
| 157 // Allocate space for locals and initialize them. | 157 // Allocate space for locals and initialize them. |
| 158 frame_->AllocateStackSlots(scope_->num_stack_slots()); | 158 frame_->AllocateStackSlots(scope_->num_stack_slots()); |
| 159 | 159 |
| 160 if (scope_->num_heap_slots() > 0) { | 160 if (scope_->num_heap_slots() > 0) { |
| 161 Comment cmnt(masm_, "[ allocate local context"); | 161 Comment cmnt(masm_, "[ allocate local context"); |
| 162 // Save the arguments object pointer, if any. | 162 // Save the arguments object pointer, if any. |
| 163 if (arguments_object_allocated && !arguments_object_saved) { | 163 if (arguments_object_allocated && !arguments_object_saved) { |
| 164 frame_->Push(ecx); | 164 frame_->EmitPush(ecx); |
| 165 arguments_object_saved = true; | 165 arguments_object_saved = true; |
| 166 } | 166 } |
| 167 // Allocate local context. | 167 // Allocate local context. |
| 168 // Get outer context and create a new context based on it. | 168 // Get outer context and create a new context based on it. |
| 169 frame_->Push(frame_->Function()); | 169 frame_->EmitPush(frame_->Function()); |
| 170 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result | 170 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
| 171 | 171 |
| 172 if (kDebug) { | 172 if (kDebug) { |
| 173 JumpTarget verified_true(this); | 173 JumpTarget verified_true(this); |
| 174 // Verify eax and esi are the same in debug mode | 174 // Verify eax and esi are the same in debug mode |
| 175 __ cmp(eax, Operand(esi)); | 175 __ cmp(eax, Operand(esi)); |
| 176 verified_true.Branch(equal); | 176 verified_true.Branch(equal); |
| 177 __ int3(); | 177 __ int3(); |
| 178 verified_true.Bind(); | 178 verified_true.Bind(); |
| 179 } | 179 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 195 // case so we don't check for it, instead we rely on the copying | 195 // case so we don't check for it, instead we rely on the copying |
| 196 // order: such a parameter is copied repeatedly into the same | 196 // order: such a parameter is copied repeatedly into the same |
| 197 // context location and thus the last value is what is seen inside | 197 // context location and thus the last value is what is seen inside |
| 198 // the function. | 198 // the function. |
| 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_->EmitPush(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_->ParameterAt(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 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 233 // If the newly-allocated arguments object is already on the | 233 // If the newly-allocated arguments object is already on the |
| 234 // stack, we make use of the convenient property that references | 234 // stack, we make use of the convenient property that references |
| 235 // representing slots take up no space on the expression stack | 235 // representing slots take up no space on the expression stack |
| 236 // (ie, it doesn't matter that the stored value is actually below | 236 // (ie, it doesn't matter that the stored value is actually below |
| 237 // the reference). | 237 // the reference). |
| 238 // | 238 // |
| 239 // If the newly-allocated argument object is not already on | 239 // If the newly-allocated argument object is not already on |
| 240 // the stack, we rely on the property that loading a | 240 // the stack, we rely on the property that loading a |
| 241 // zero-sized reference will not clobber the ecx register. | 241 // zero-sized reference will not clobber the ecx register. |
| 242 if (!arguments_object_saved) { | 242 if (!arguments_object_saved) { |
| 243 frame_->Push(ecx); | 243 frame_->EmitPush(ecx); |
| 244 } | 244 } |
| 245 arguments_ref.SetValue(NOT_CONST_INIT); | 245 arguments_ref.SetValue(NOT_CONST_INIT); |
| 246 } | 246 } |
| 247 shadow_ref.SetValue(NOT_CONST_INIT); | 247 shadow_ref.SetValue(NOT_CONST_INIT); |
| 248 } | 248 } |
| 249 frame_->Drop(); // Value is no longer needed. | 249 frame_->Drop(); // Value is no longer needed. |
| 250 } | 250 } |
| 251 | 251 |
| 252 // Generate code to 'execute' declarations and initialize functions | 252 // Generate code to 'execute' declarations and initialize functions |
| 253 // (source elements). In case of an illegal redeclaration we need to | 253 // (source elements). In case of an illegal redeclaration we need to |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 JumpTarget true_target(this); | 388 JumpTarget true_target(this); |
| 389 JumpTarget false_target(this); | 389 JumpTarget false_target(this); |
| 390 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 390 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 391 | 391 |
| 392 if (has_cc()) { | 392 if (has_cc()) { |
| 393 ASSERT(frame_ != NULL); | 393 ASSERT(frame_ != NULL); |
| 394 // Convert cc_reg_ into a boolean value. | 394 // Convert cc_reg_ into a boolean value. |
| 395 JumpTarget loaded(this); | 395 JumpTarget loaded(this); |
| 396 JumpTarget materialize_true(this); | 396 JumpTarget materialize_true(this); |
| 397 materialize_true.Branch(cc_reg_); | 397 materialize_true.Branch(cc_reg_); |
| 398 frame_->Push(Immediate(Factory::false_value())); | 398 frame_->EmitPush(Immediate(Factory::false_value())); |
| 399 loaded.Jump(); | 399 loaded.Jump(); |
| 400 materialize_true.Bind(); | 400 materialize_true.Bind(); |
| 401 frame_->Push(Immediate(Factory::true_value())); | 401 frame_->EmitPush(Immediate(Factory::true_value())); |
| 402 loaded.Bind(); | 402 loaded.Bind(); |
| 403 cc_reg_ = no_condition; | 403 cc_reg_ = no_condition; |
| 404 } | 404 } |
| 405 | 405 |
| 406 if (true_target.is_linked() || false_target.is_linked()) { | 406 if (true_target.is_linked() || false_target.is_linked()) { |
| 407 // We have at least one condition value that has been "translated" into | 407 // We have at least one condition value that has been "translated" into |
| 408 // a branch, thus it needs to be loaded explicitly. | 408 // a branch, thus it needs to be loaded explicitly. |
| 409 JumpTarget loaded(this); | 409 JumpTarget loaded(this); |
| 410 if (frame_ != NULL) { | 410 if (frame_ != NULL) { |
| 411 loaded.Jump(); // Don't lose the current TOS. | 411 loaded.Jump(); // Don't lose the current TOS. |
| 412 } | 412 } |
| 413 bool both = true_target.is_linked() && false_target.is_linked(); | 413 bool both = true_target.is_linked() && false_target.is_linked(); |
| 414 // Load "true" if necessary. | 414 // Load "true" if necessary. |
| 415 if (true_target.is_linked()) { | 415 if (true_target.is_linked()) { |
| 416 true_target.Bind(); | 416 true_target.Bind(); |
| 417 frame_->Push(Immediate(Factory::true_value())); | 417 frame_->EmitPush(Immediate(Factory::true_value())); |
| 418 } | 418 } |
| 419 // If both "true" and "false" need to be reincarnated jump across the | 419 // If both "true" and "false" need to be reincarnated jump across the |
| 420 // code for "false". | 420 // code for "false". |
| 421 if (both) { | 421 if (both) { |
| 422 loaded.Jump(); | 422 loaded.Jump(); |
| 423 } | 423 } |
| 424 // Load "false" if necessary. | 424 // Load "false" if necessary. |
| 425 if (false_target.is_linked()) { | 425 if (false_target.is_linked()) { |
| 426 false_target.Bind(); | 426 false_target.Bind(); |
| 427 frame_->Push(Immediate(Factory::false_value())); | 427 frame_->EmitPush(Immediate(Factory::false_value())); |
| 428 } | 428 } |
| 429 // A value is loaded on all paths reaching this point. | 429 // A value is loaded on all paths reaching this point. |
| 430 loaded.Bind(); | 430 loaded.Bind(); |
| 431 } | 431 } |
| 432 ASSERT(frame_ != NULL); | 432 ASSERT(frame_ != NULL); |
| 433 ASSERT(!has_cc()); | 433 ASSERT(!has_cc()); |
| 434 } | 434 } |
| 435 | 435 |
| 436 | 436 |
| 437 void CodeGenerator::LoadGlobal() { | 437 void CodeGenerator::LoadGlobal() { |
| 438 frame_->Push(GlobalObject()); | 438 frame_->EmitPush(GlobalObject()); |
| 439 } | 439 } |
| 440 | 440 |
| 441 | 441 |
| 442 void CodeGenerator::LoadGlobalReceiver(Register scratch) { | 442 void CodeGenerator::LoadGlobalReceiver(Register scratch) { |
| 443 __ mov(scratch, GlobalObject()); | 443 __ mov(scratch, GlobalObject()); |
| 444 frame_->Push(FieldOperand(scratch, GlobalObject::kGlobalReceiverOffset)); | 444 frame_->EmitPush(FieldOperand(scratch, GlobalObject::kGlobalReceiverOffset)); |
| 445 } | 445 } |
| 446 | 446 |
| 447 | 447 |
| 448 // TODO(1241834): Get rid of this function in favor of just using Load, now | 448 // TODO(1241834): Get rid of this function in favor of just using Load, now |
| 449 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global | 449 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
| 450 // variables w/o reference errors elsewhere. | 450 // variables w/o reference errors elsewhere. |
| 451 void CodeGenerator::LoadTypeofExpression(Expression* x) { | 451 void CodeGenerator::LoadTypeofExpression(Expression* x) { |
| 452 Variable* variable = x->AsVariableProxy()->AsVariable(); | 452 Variable* variable = x->AsVariableProxy()->AsVariable(); |
| 453 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 453 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
| 454 // NOTE: This is somewhat nasty. We force the compiler to load | 454 // NOTE: This is somewhat nasty. We force the compiler to load |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 void CodeGenerator::UnloadReference(Reference* ref) { | 522 void CodeGenerator::UnloadReference(Reference* ref) { |
| 523 // Pop a reference from the stack while preserving TOS. | 523 // Pop a reference from the stack while preserving TOS. |
| 524 Comment cmnt(masm_, "[ UnloadReference"); | 524 Comment cmnt(masm_, "[ UnloadReference"); |
| 525 int size = ref->size(); | 525 int size = ref->size(); |
| 526 if (size == 1) { | 526 if (size == 1) { |
| 527 frame_->Pop(eax); | 527 frame_->Pop(eax); |
| 528 __ mov(frame_->Top(), eax); | 528 __ mov(frame_->Top(), eax); |
| 529 } else if (size > 1) { | 529 } else if (size > 1) { |
| 530 frame_->Pop(eax); | 530 frame_->Pop(eax); |
| 531 frame_->Drop(size); | 531 frame_->Drop(size); |
| 532 frame_->Push(eax); | 532 frame_->EmitPush(eax); |
| 533 } | 533 } |
| 534 } | 534 } |
| 535 | 535 |
| 536 | 536 |
| 537 class ToBooleanStub: public CodeStub { | 537 class ToBooleanStub: public CodeStub { |
| 538 public: | 538 public: |
| 539 ToBooleanStub() { } | 539 ToBooleanStub() { } |
| 540 | 540 |
| 541 void Generate(MacroAssembler* masm); | 541 void Generate(MacroAssembler* masm); |
| 542 | 542 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 570 false_target->Branch(equal); | 570 false_target->Branch(equal); |
| 571 | 571 |
| 572 // Smi => false iff zero. | 572 // Smi => false iff zero. |
| 573 ASSERT(kSmiTag == 0); | 573 ASSERT(kSmiTag == 0); |
| 574 __ test(eax, Operand(eax)); | 574 __ test(eax, Operand(eax)); |
| 575 false_target->Branch(zero); | 575 false_target->Branch(zero); |
| 576 __ test(eax, Immediate(kSmiTagMask)); | 576 __ test(eax, Immediate(kSmiTagMask)); |
| 577 true_target->Branch(zero); | 577 true_target->Branch(zero); |
| 578 | 578 |
| 579 // Call the stub for all other cases. | 579 // Call the stub for all other cases. |
| 580 frame_->Push(eax); // Undo the pop(eax) from above. | 580 frame_->EmitPush(eax); // Undo the pop(eax) from above. |
| 581 ToBooleanStub stub; | 581 ToBooleanStub stub; |
| 582 frame_->CallStub(&stub, 1); | 582 frame_->CallStub(&stub, 1); |
| 583 // Convert the result (eax) to condition code. | 583 // Convert the result (eax) to condition code. |
| 584 __ test(eax, Operand(eax)); | 584 __ test(eax, Operand(eax)); |
| 585 | 585 |
| 586 ASSERT(not_equal == not_zero); | 586 ASSERT(not_equal == not_zero); |
| 587 cc_reg_ = not_equal; | 587 cc_reg_ = not_equal; |
| 588 } | 588 } |
| 589 | 589 |
| 590 | 590 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 706 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 706 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 707 StaticType* type, | 707 StaticType* type, |
| 708 OverwriteMode overwrite_mode) { | 708 OverwriteMode overwrite_mode) { |
| 709 Comment cmnt(masm_, "[ BinaryOperation"); | 709 Comment cmnt(masm_, "[ BinaryOperation"); |
| 710 Comment cmnt_token(masm_, Token::String(op)); | 710 Comment cmnt_token(masm_, Token::String(op)); |
| 711 | 711 |
| 712 if (op == Token::COMMA) { | 712 if (op == Token::COMMA) { |
| 713 // Simply discard left value. | 713 // Simply discard left value. |
| 714 frame_->Pop(eax); | 714 frame_->Pop(eax); |
| 715 frame_->Drop(); | 715 frame_->Drop(); |
| 716 frame_->Push(eax); | 716 frame_->EmitPush(eax); |
| 717 return; | 717 return; |
| 718 } | 718 } |
| 719 | 719 |
| 720 // Set the flags based on the operation, type and loop nesting level. | 720 // Set the flags based on the operation, type and loop nesting level. |
| 721 GenericBinaryFlags flags; | 721 GenericBinaryFlags flags; |
| 722 switch (op) { | 722 switch (op) { |
| 723 case Token::BIT_OR: | 723 case Token::BIT_OR: |
| 724 case Token::BIT_AND: | 724 case Token::BIT_AND: |
| 725 case Token::BIT_XOR: | 725 case Token::BIT_XOR: |
| 726 case Token::SHL: | 726 case Token::SHL: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 754 // Put result back on the stack. It seems somewhat weird to let | 754 // Put result back on the stack. It seems somewhat weird to let |
| 755 // the deferred code jump back before the assignment to the frame | 755 // the deferred code jump back before the assignment to the frame |
| 756 // top, but this is just to let the peephole optimizer get rid of | 756 // top, but this is just to let the peephole optimizer get rid of |
| 757 // more code. | 757 // more code. |
| 758 __ bind(deferred->exit()); | 758 __ bind(deferred->exit()); |
| 759 __ mov(frame_->Top(), eax); | 759 __ mov(frame_->Top(), eax); |
| 760 } else { | 760 } else { |
| 761 // Call the stub and push the result to the stack. | 761 // Call the stub and push the result to the stack. |
| 762 GenericBinaryOpStub stub(op, overwrite_mode, flags); | 762 GenericBinaryOpStub stub(op, overwrite_mode, flags); |
| 763 frame_->CallStub(&stub, 2); | 763 frame_->CallStub(&stub, 2); |
| 764 frame_->Push(eax); | 764 frame_->EmitPush(eax); |
| 765 } | 765 } |
| 766 } | 766 } |
| 767 | 767 |
| 768 | 768 |
| 769 class DeferredInlinedSmiOperation: public DeferredCode { | 769 class DeferredInlinedSmiOperation: public DeferredCode { |
| 770 public: | 770 public: |
| 771 DeferredInlinedSmiOperation(CodeGenerator* generator, | 771 DeferredInlinedSmiOperation(CodeGenerator* generator, |
| 772 Token::Value op, int value, | 772 Token::Value op, int value, |
| 773 OverwriteMode overwrite_mode) : | 773 OverwriteMode overwrite_mode) : |
| 774 DeferredCode(generator), op_(op), value_(value), | 774 DeferredCode(generator), op_(op), value_(value), |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 937 } else { | 937 } else { |
| 938 deferred = new DeferredInlinedSmiAddReversed(this, int_value, | 938 deferred = new DeferredInlinedSmiAddReversed(this, int_value, |
| 939 overwrite_mode); | 939 overwrite_mode); |
| 940 } | 940 } |
| 941 frame_->Pop(eax); | 941 frame_->Pop(eax); |
| 942 __ add(Operand(eax), Immediate(value)); | 942 __ add(Operand(eax), Immediate(value)); |
| 943 __ j(overflow, deferred->enter(), not_taken); | 943 __ j(overflow, deferred->enter(), not_taken); |
| 944 __ test(eax, Immediate(kSmiTagMask)); | 944 __ test(eax, Immediate(kSmiTagMask)); |
| 945 __ j(not_zero, deferred->enter(), not_taken); | 945 __ j(not_zero, deferred->enter(), not_taken); |
| 946 __ bind(deferred->exit()); | 946 __ bind(deferred->exit()); |
| 947 frame_->Push(eax); | 947 frame_->EmitPush(eax); |
| 948 break; | 948 break; |
| 949 } | 949 } |
| 950 | 950 |
| 951 case Token::SUB: { | 951 case Token::SUB: { |
| 952 DeferredCode* deferred = NULL; | 952 DeferredCode* deferred = NULL; |
| 953 frame_->Pop(eax); | 953 frame_->Pop(eax); |
| 954 if (!reversed) { | 954 if (!reversed) { |
| 955 deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode); | 955 deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode); |
| 956 __ sub(Operand(eax), Immediate(value)); | 956 __ sub(Operand(eax), Immediate(value)); |
| 957 } else { | 957 } else { |
| 958 deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode); | 958 deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode); |
| 959 __ mov(edx, Operand(eax)); | 959 __ mov(edx, Operand(eax)); |
| 960 __ mov(eax, Immediate(value)); | 960 __ mov(eax, Immediate(value)); |
| 961 __ sub(eax, Operand(edx)); | 961 __ sub(eax, Operand(edx)); |
| 962 } | 962 } |
| 963 __ j(overflow, deferred->enter(), not_taken); | 963 __ j(overflow, deferred->enter(), not_taken); |
| 964 __ test(eax, Immediate(kSmiTagMask)); | 964 __ test(eax, Immediate(kSmiTagMask)); |
| 965 __ j(not_zero, deferred->enter(), not_taken); | 965 __ j(not_zero, deferred->enter(), not_taken); |
| 966 __ bind(deferred->exit()); | 966 __ bind(deferred->exit()); |
| 967 frame_->Push(eax); | 967 frame_->EmitPush(eax); |
| 968 break; | 968 break; |
| 969 } | 969 } |
| 970 | 970 |
| 971 case Token::SAR: { | 971 case Token::SAR: { |
| 972 if (reversed) { | 972 if (reversed) { |
| 973 frame_->Pop(eax); | 973 frame_->Pop(eax); |
| 974 frame_->Push(Immediate(value)); | 974 frame_->EmitPush(Immediate(value)); |
| 975 frame_->Push(eax); | 975 frame_->EmitPush(eax); |
| 976 GenericBinaryOperation(op, type, overwrite_mode); | 976 GenericBinaryOperation(op, type, overwrite_mode); |
| 977 } else { | 977 } else { |
| 978 int shift_value = int_value & 0x1f; // only least significant 5 bits | 978 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 979 DeferredCode* deferred = | 979 DeferredCode* deferred = |
| 980 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, | 980 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, |
| 981 overwrite_mode); | 981 overwrite_mode); |
| 982 frame_->Pop(eax); | 982 frame_->Pop(eax); |
| 983 __ test(eax, Immediate(kSmiTagMask)); | 983 __ test(eax, Immediate(kSmiTagMask)); |
| 984 __ j(not_zero, deferred->enter(), not_taken); | 984 __ j(not_zero, deferred->enter(), not_taken); |
| 985 __ sar(eax, shift_value); | 985 __ sar(eax, shift_value); |
| 986 __ and_(eax, ~kSmiTagMask); | 986 __ and_(eax, ~kSmiTagMask); |
| 987 __ bind(deferred->exit()); | 987 __ bind(deferred->exit()); |
| 988 frame_->Push(eax); | 988 frame_->EmitPush(eax); |
| 989 } | 989 } |
| 990 break; | 990 break; |
| 991 } | 991 } |
| 992 | 992 |
| 993 case Token::SHR: { | 993 case Token::SHR: { |
| 994 if (reversed) { | 994 if (reversed) { |
| 995 frame_->Pop(eax); | 995 frame_->Pop(eax); |
| 996 frame_->Push(Immediate(value)); | 996 frame_->EmitPush(Immediate(value)); |
| 997 frame_->Push(eax); | 997 frame_->EmitPush(eax); |
| 998 GenericBinaryOperation(op, type, overwrite_mode); | 998 GenericBinaryOperation(op, type, overwrite_mode); |
| 999 } else { | 999 } else { |
| 1000 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1000 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1001 DeferredCode* deferred = | 1001 DeferredCode* deferred = |
| 1002 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, | 1002 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, |
| 1003 overwrite_mode); | 1003 overwrite_mode); |
| 1004 frame_->Pop(eax); | 1004 frame_->Pop(eax); |
| 1005 __ test(eax, Immediate(kSmiTagMask)); | 1005 __ test(eax, Immediate(kSmiTagMask)); |
| 1006 __ mov(ebx, Operand(eax)); | 1006 __ mov(ebx, Operand(eax)); |
| 1007 __ j(not_zero, deferred->enter(), not_taken); | 1007 __ j(not_zero, deferred->enter(), not_taken); |
| 1008 __ sar(ebx, kSmiTagSize); | 1008 __ sar(ebx, kSmiTagSize); |
| 1009 __ shr(ebx, shift_value); | 1009 __ shr(ebx, shift_value); |
| 1010 __ test(ebx, Immediate(0xc0000000)); | 1010 __ test(ebx, Immediate(0xc0000000)); |
| 1011 __ j(not_zero, deferred->enter(), not_taken); | 1011 __ j(not_zero, deferred->enter(), not_taken); |
| 1012 // tag result and store it in TOS (eax) | 1012 // tag result and store it in TOS (eax) |
| 1013 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1013 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 1014 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); | 1014 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); |
| 1015 __ bind(deferred->exit()); | 1015 __ bind(deferred->exit()); |
| 1016 frame_->Push(eax); | 1016 frame_->EmitPush(eax); |
| 1017 } | 1017 } |
| 1018 break; | 1018 break; |
| 1019 } | 1019 } |
| 1020 | 1020 |
| 1021 case Token::SHL: { | 1021 case Token::SHL: { |
| 1022 if (reversed) { | 1022 if (reversed) { |
| 1023 frame_->Pop(eax); | 1023 frame_->Pop(eax); |
| 1024 frame_->Push(Immediate(value)); | 1024 frame_->EmitPush(Immediate(value)); |
| 1025 frame_->Push(eax); | 1025 frame_->EmitPush(eax); |
| 1026 GenericBinaryOperation(op, type, overwrite_mode); | 1026 GenericBinaryOperation(op, type, overwrite_mode); |
| 1027 } else { | 1027 } else { |
| 1028 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1028 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1029 DeferredCode* deferred = | 1029 DeferredCode* deferred = |
| 1030 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, | 1030 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, |
| 1031 overwrite_mode); | 1031 overwrite_mode); |
| 1032 frame_->Pop(eax); | 1032 frame_->Pop(eax); |
| 1033 __ test(eax, Immediate(kSmiTagMask)); | 1033 __ test(eax, Immediate(kSmiTagMask)); |
| 1034 __ mov(ebx, Operand(eax)); | 1034 __ mov(ebx, Operand(eax)); |
| 1035 __ j(not_zero, deferred->enter(), not_taken); | 1035 __ j(not_zero, deferred->enter(), not_taken); |
| 1036 __ sar(ebx, kSmiTagSize); | 1036 __ sar(ebx, kSmiTagSize); |
| 1037 __ shl(ebx, shift_value); | 1037 __ shl(ebx, shift_value); |
| 1038 __ lea(ecx, Operand(ebx, 0x40000000)); | 1038 __ lea(ecx, Operand(ebx, 0x40000000)); |
| 1039 __ test(ecx, Immediate(0x80000000)); | 1039 __ test(ecx, Immediate(0x80000000)); |
| 1040 __ j(not_zero, deferred->enter(), not_taken); | 1040 __ j(not_zero, deferred->enter(), not_taken); |
| 1041 // tag result and store it in TOS (eax) | 1041 // tag result and store it in TOS (eax) |
| 1042 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1042 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 1043 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); | 1043 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); |
| 1044 __ bind(deferred->exit()); | 1044 __ bind(deferred->exit()); |
| 1045 frame_->Push(eax); | 1045 frame_->EmitPush(eax); |
| 1046 } | 1046 } |
| 1047 break; | 1047 break; |
| 1048 } | 1048 } |
| 1049 | 1049 |
| 1050 case Token::BIT_OR: | 1050 case Token::BIT_OR: |
| 1051 case Token::BIT_XOR: | 1051 case Token::BIT_XOR: |
| 1052 case Token::BIT_AND: { | 1052 case Token::BIT_AND: { |
| 1053 DeferredCode* deferred = NULL; | 1053 DeferredCode* deferred = NULL; |
| 1054 if (!reversed) { | 1054 if (!reversed) { |
| 1055 deferred = new DeferredInlinedSmiOperation(this, op, int_value, | 1055 deferred = new DeferredInlinedSmiOperation(this, op, int_value, |
| 1056 overwrite_mode); | 1056 overwrite_mode); |
| 1057 } else { | 1057 } else { |
| 1058 deferred = new DeferredInlinedSmiOperationReversed(this, op, int_value, | 1058 deferred = new DeferredInlinedSmiOperationReversed(this, op, int_value, |
| 1059 overwrite_mode); | 1059 overwrite_mode); |
| 1060 } | 1060 } |
| 1061 frame_->Pop(eax); | 1061 frame_->Pop(eax); |
| 1062 __ test(eax, Immediate(kSmiTagMask)); | 1062 __ test(eax, Immediate(kSmiTagMask)); |
| 1063 __ j(not_zero, deferred->enter(), not_taken); | 1063 __ j(not_zero, deferred->enter(), not_taken); |
| 1064 if (op == Token::BIT_AND) { | 1064 if (op == Token::BIT_AND) { |
| 1065 __ and_(Operand(eax), Immediate(value)); | 1065 __ and_(Operand(eax), Immediate(value)); |
| 1066 } else if (op == Token::BIT_XOR) { | 1066 } else if (op == Token::BIT_XOR) { |
| 1067 __ xor_(Operand(eax), Immediate(value)); | 1067 __ xor_(Operand(eax), Immediate(value)); |
| 1068 } else { | 1068 } else { |
| 1069 ASSERT(op == Token::BIT_OR); | 1069 ASSERT(op == Token::BIT_OR); |
| 1070 __ or_(Operand(eax), Immediate(value)); | 1070 __ or_(Operand(eax), Immediate(value)); |
| 1071 } | 1071 } |
| 1072 __ bind(deferred->exit()); | 1072 __ bind(deferred->exit()); |
| 1073 frame_->Push(eax); | 1073 frame_->EmitPush(eax); |
| 1074 break; | 1074 break; |
| 1075 } | 1075 } |
| 1076 | 1076 |
| 1077 default: { | 1077 default: { |
| 1078 if (!reversed) { | 1078 if (!reversed) { |
| 1079 frame_->Push(Immediate(value)); | 1079 frame_->EmitPush(Immediate(value)); |
| 1080 } else { | 1080 } else { |
| 1081 frame_->Pop(eax); | 1081 frame_->Pop(eax); |
| 1082 frame_->Push(Immediate(value)); | 1082 frame_->EmitPush(Immediate(value)); |
| 1083 frame_->Push(eax); | 1083 frame_->EmitPush(eax); |
| 1084 } | 1084 } |
| 1085 GenericBinaryOperation(op, type, overwrite_mode); | 1085 GenericBinaryOperation(op, type, overwrite_mode); |
| 1086 break; | 1086 break; |
| 1087 } | 1087 } |
| 1088 } | 1088 } |
| 1089 } | 1089 } |
| 1090 | 1090 |
| 1091 | 1091 |
| 1092 class CompareStub: public CodeStub { | 1092 class CompareStub: public CodeStub { |
| 1093 public: | 1093 public: |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1286 node->set_break_stack_height(break_stack_height_); | 1286 node->set_break_stack_height(break_stack_height_); |
| 1287 node->break_target()->set_code_generator(this); | 1287 node->break_target()->set_code_generator(this); |
| 1288 VisitStatements(node->statements()); | 1288 VisitStatements(node->statements()); |
| 1289 if (node->break_target()->is_linked()) { | 1289 if (node->break_target()->is_linked()) { |
| 1290 node->break_target()->Bind(); | 1290 node->break_target()->Bind(); |
| 1291 } | 1291 } |
| 1292 } | 1292 } |
| 1293 | 1293 |
| 1294 | 1294 |
| 1295 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1295 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1296 frame_->Push(Immediate(pairs)); | 1296 frame_->EmitPush(Immediate(pairs)); |
| 1297 frame_->Push(esi); | 1297 frame_->EmitPush(esi); |
| 1298 frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1298 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1299 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1299 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1300 // Return value is ignored. | 1300 // Return value is ignored. |
| 1301 } | 1301 } |
| 1302 | 1302 |
| 1303 | 1303 |
| 1304 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1304 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1305 Comment cmnt(masm_, "[ Declaration"); | 1305 Comment cmnt(masm_, "[ Declaration"); |
| 1306 Variable* var = node->proxy()->var(); | 1306 Variable* var = node->proxy()->var(); |
| 1307 ASSERT(var != NULL); // must have been resolved | 1307 ASSERT(var != NULL); // must have been resolved |
| 1308 Slot* slot = var->slot(); | 1308 Slot* slot = var->slot(); |
| 1309 | 1309 |
| 1310 // If it was not possible to allocate the variable at compile time, | 1310 // If it was not possible to allocate the variable at compile time, |
| 1311 // we need to "declare" it at runtime to make sure it actually | 1311 // we need to "declare" it at runtime to make sure it actually |
| 1312 // exists in the local context. | 1312 // exists in the local context. |
| 1313 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1313 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1314 // Variables with a "LOOKUP" slot were introduced as non-locals | 1314 // Variables with a "LOOKUP" slot were introduced as non-locals |
| 1315 // during variable resolution and must have mode DYNAMIC. | 1315 // during variable resolution and must have mode DYNAMIC. |
| 1316 ASSERT(var->mode() == Variable::DYNAMIC); | 1316 ASSERT(var->mode() == Variable::DYNAMIC); |
| 1317 // For now, just do a runtime call. | 1317 // For now, just do a runtime call. |
| 1318 frame_->Push(esi); | 1318 frame_->EmitPush(esi); |
| 1319 frame_->Push(Immediate(var->name())); | 1319 frame_->EmitPush(Immediate(var->name())); |
| 1320 // Declaration nodes are always introduced in one of two modes. | 1320 // Declaration nodes are always introduced in one of two modes. |
| 1321 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 1321 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
| 1322 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1322 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| 1323 frame_->Push(Immediate(Smi::FromInt(attr))); | 1323 frame_->EmitPush(Immediate(Smi::FromInt(attr))); |
| 1324 // Push initial value, if any. | 1324 // Push initial value, if any. |
| 1325 // Note: For variables we must not push an initial value (such as | 1325 // Note: For variables we must not push an initial value (such as |
| 1326 // 'undefined') because we may have a (legal) redeclaration and we | 1326 // 'undefined') because we may have a (legal) redeclaration and we |
| 1327 // must not destroy the current value. | 1327 // must not destroy the current value. |
| 1328 if (node->mode() == Variable::CONST) { | 1328 if (node->mode() == Variable::CONST) { |
| 1329 frame_->Push(Immediate(Factory::the_hole_value())); | 1329 frame_->EmitPush(Immediate(Factory::the_hole_value())); |
| 1330 } else if (node->fun() != NULL) { | 1330 } else if (node->fun() != NULL) { |
| 1331 Load(node->fun()); | 1331 Load(node->fun()); |
| 1332 } else { | 1332 } else { |
| 1333 frame_->Push(Immediate(0)); // no initial value! | 1333 frame_->EmitPush(Immediate(0)); // no initial value! |
| 1334 } | 1334 } |
| 1335 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 1335 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 1336 // Ignore the return value (declarations are statements). | 1336 // Ignore the return value (declarations are statements). |
| 1337 return; | 1337 return; |
| 1338 } | 1338 } |
| 1339 | 1339 |
| 1340 ASSERT(!var->is_global()); | 1340 ASSERT(!var->is_global()); |
| 1341 | 1341 |
| 1342 // If we have a function or a constant, we need to initialize the variable. | 1342 // If we have a function or a constant, we need to initialize the variable. |
| 1343 Expression* val = NULL; | 1343 Expression* val = NULL; |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 | 1502 |
| 1503 // If we're inside a try statement or the return instruction | 1503 // If we're inside a try statement or the return instruction |
| 1504 // sequence has been generated, we just jump to that | 1504 // sequence has been generated, we just jump to that |
| 1505 // point. Otherwise, we generate the return instruction sequence and | 1505 // point. Otherwise, we generate the return instruction sequence and |
| 1506 // bind the function return label. | 1506 // bind the function return label. |
| 1507 if (is_inside_try_ || function_return_.is_bound()) { | 1507 if (is_inside_try_ || function_return_.is_bound()) { |
| 1508 function_return_.Jump(); | 1508 function_return_.Jump(); |
| 1509 } else { | 1509 } else { |
| 1510 function_return_.Bind(); | 1510 function_return_.Bind(); |
| 1511 if (FLAG_trace) { | 1511 if (FLAG_trace) { |
| 1512 frame_->Push(eax); // undo the pop(eax) from above | 1512 frame_->EmitPush(eax); // undo the pop(eax) from above |
| 1513 frame_->CallRuntime(Runtime::kTraceExit, 1); | 1513 frame_->CallRuntime(Runtime::kTraceExit, 1); |
| 1514 } | 1514 } |
| 1515 | 1515 |
| 1516 // Add a label for checking the size of the code used for returning. | 1516 // Add a label for checking the size of the code used for returning. |
| 1517 Label check_exit_codesize; | 1517 Label check_exit_codesize; |
| 1518 __ bind(&check_exit_codesize); | 1518 __ bind(&check_exit_codesize); |
| 1519 | 1519 |
| 1520 // Leave the frame and return popping the arguments and the | 1520 // Leave the frame and return popping the arguments and the |
| 1521 // receiver. | 1521 // receiver. |
| 1522 frame_->Exit(); | 1522 frame_->Exit(); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1664 default_clause = clause; | 1664 default_clause = clause; |
| 1665 continue; | 1665 continue; |
| 1666 } | 1666 } |
| 1667 | 1667 |
| 1668 Comment cmnt(masm_, "[ Case clause"); | 1668 Comment cmnt(masm_, "[ Case clause"); |
| 1669 // Compile the test. | 1669 // Compile the test. |
| 1670 next_test.Bind(); | 1670 next_test.Bind(); |
| 1671 next_test.Unuse(); | 1671 next_test.Unuse(); |
| 1672 // Duplicate TOS. | 1672 // Duplicate TOS. |
| 1673 __ mov(eax, frame_->Top()); | 1673 __ mov(eax, frame_->Top()); |
| 1674 frame_->Push(eax); | 1674 frame_->EmitPush(eax); |
| 1675 Load(clause->label()); | 1675 Load(clause->label()); |
| 1676 Comparison(equal, true); | 1676 Comparison(equal, true); |
| 1677 Branch(false, &next_test); | 1677 Branch(false, &next_test); |
| 1678 | 1678 |
| 1679 // Before entering the body from the test, remove the switch value from | 1679 // Before entering the body from the test, remove the switch value from |
| 1680 // the stack. | 1680 // the stack. |
| 1681 frame_->Drop(); | 1681 frame_->Drop(); |
| 1682 | 1682 |
| 1683 // Label the body so that fall through is enabled. | 1683 // Label the body so that fall through is enabled. |
| 1684 if (i > 0 && cases->at(i - 1)->is_default()) { | 1684 if (i > 0 && cases->at(i - 1)->is_default()) { |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1948 // Check if enumerable is already a JSObject | 1948 // Check if enumerable is already a JSObject |
| 1949 // eax: value to be iterated over | 1949 // eax: value to be iterated over |
| 1950 __ test(eax, Immediate(kSmiTagMask)); | 1950 __ test(eax, Immediate(kSmiTagMask)); |
| 1951 primitive.Branch(zero); | 1951 primitive.Branch(zero); |
| 1952 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 1952 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 1953 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 1953 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 1954 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 1954 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 1955 jsobject.Branch(above_equal); | 1955 jsobject.Branch(above_equal); |
| 1956 | 1956 |
| 1957 primitive.Bind(); | 1957 primitive.Bind(); |
| 1958 frame_->Push(eax); | 1958 frame_->EmitPush(eax); |
| 1959 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); | 1959 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); |
| 1960 // 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 |
| 1961 | 1961 |
| 1962 jsobject.Bind(); | 1962 jsobject.Bind(); |
| 1963 // Get the set of properties (as a FixedArray or Map). | 1963 // Get the set of properties (as a FixedArray or Map). |
| 1964 // eax: value to be iterated over | 1964 // eax: value to be iterated over |
| 1965 frame_->Push(eax); // push the object being iterated over (slot 4) | 1965 frame_->EmitPush(eax); // push the object being iterated over (slot 4) |
| 1966 | 1966 |
| 1967 frame_->Push(eax); // push the Object (slot 4) for the runtime call | 1967 frame_->EmitPush(eax); // push the Object (slot 4) for the runtime call |
| 1968 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 1968 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 1969 | 1969 |
| 1970 // 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. |
| 1971 // 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. |
| 1972 // eax: map or fixed array (result from call to | 1972 // eax: map or fixed array (result from call to |
| 1973 // Runtime::kGetPropertyNamesFast) | 1973 // Runtime::kGetPropertyNamesFast) |
| 1974 __ mov(edx, Operand(eax)); | 1974 __ mov(edx, Operand(eax)); |
| 1975 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 1975 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 1976 __ cmp(ecx, Factory::meta_map()); | 1976 __ cmp(ecx, Factory::meta_map()); |
| 1977 fixed_array.Branch(not_equal); | 1977 fixed_array.Branch(not_equal); |
| 1978 | 1978 |
| 1979 // Get enum cache | 1979 // Get enum cache |
| 1980 // eax: map (result from call to Runtime::kGetPropertyNamesFast) | 1980 // eax: map (result from call to Runtime::kGetPropertyNamesFast) |
| 1981 __ mov(ecx, Operand(eax)); | 1981 __ mov(ecx, Operand(eax)); |
| 1982 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); | 1982 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); |
| 1983 // Get the bridge array held in the enumeration index field. | 1983 // Get the bridge array held in the enumeration index field. |
| 1984 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 1984 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 1985 // Get the cache from the bridge array. | 1985 // Get the cache from the bridge array. |
| 1986 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 1986 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 1987 | 1987 |
| 1988 frame_->Push(eax); // <- slot 3 | 1988 frame_->EmitPush(eax); // <- slot 3 |
| 1989 frame_->Push(edx); // <- slot 2 | 1989 frame_->EmitPush(edx); // <- slot 2 |
| 1990 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); | 1990 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); |
| 1991 __ shl(eax, kSmiTagSize); | 1991 __ shl(eax, kSmiTagSize); |
| 1992 frame_->Push(eax); // <- slot 1 | 1992 frame_->EmitPush(eax); // <- slot 1 |
| 1993 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 | 1993 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 1994 entry.Jump(); | 1994 entry.Jump(); |
| 1995 | 1995 |
| 1996 fixed_array.Bind(); | 1996 fixed_array.Bind(); |
| 1997 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) | 1997 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) |
| 1998 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3 | 1998 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 3 |
| 1999 frame_->Push(eax); // <- slot 2 | 1999 frame_->EmitPush(eax); // <- slot 2 |
| 2000 | 2000 |
| 2001 // 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. |
| 2002 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 2002 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 2003 __ shl(eax, kSmiTagSize); | 2003 __ shl(eax, kSmiTagSize); |
| 2004 frame_->Push(eax); // <- slot 1 | 2004 frame_->EmitPush(eax); // <- slot 1 |
| 2005 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 | 2005 frame_->EmitPush(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 2006 | 2006 |
| 2007 // Condition. | 2007 // Condition. |
| 2008 entry.Bind(); | 2008 entry.Bind(); |
| 2009 __ mov(eax, frame_->ElementAt(0)); // load the current count | 2009 __ mov(eax, frame_->ElementAt(0)); // load the current count |
| 2010 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length | 2010 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length |
| 2011 cleanup.Branch(above_equal); | 2011 cleanup.Branch(above_equal); |
| 2012 | 2012 |
| 2013 // Get the i'th entry of the array. | 2013 // Get the i'th entry of the array. |
| 2014 __ mov(edx, frame_->ElementAt(2)); | 2014 __ mov(edx, frame_->ElementAt(2)); |
| 2015 __ mov(ebx, Operand(edx, eax, times_2, | 2015 __ mov(ebx, Operand(edx, eax, times_2, |
| 2016 FixedArray::kHeaderSize - kHeapObjectTag)); | 2016 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 2017 | 2017 |
| 2018 // 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 |
| 2019 // permanent slow case eax: current iteration count ebx: i'th entry | 2019 // permanent slow case eax: current iteration count ebx: i'th entry |
| 2020 // of the enum cache | 2020 // of the enum cache |
| 2021 __ mov(edx, frame_->ElementAt(3)); | 2021 __ mov(edx, frame_->ElementAt(3)); |
| 2022 // Check if the expected map still matches that of the enumerable. | 2022 // Check if the expected map still matches that of the enumerable. |
| 2023 // If not, we have to filter the key. | 2023 // If not, we have to filter the key. |
| 2024 // eax: current iteration count | 2024 // eax: current iteration count |
| 2025 // ebx: i'th entry of the enum cache | 2025 // ebx: i'th entry of the enum cache |
| 2026 // edx: expected map value | 2026 // edx: expected map value |
| 2027 __ mov(ecx, frame_->ElementAt(4)); | 2027 __ mov(ecx, frame_->ElementAt(4)); |
| 2028 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); | 2028 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 2029 __ cmp(ecx, Operand(edx)); | 2029 __ cmp(ecx, Operand(edx)); |
| 2030 end_del_check.Branch(equal); | 2030 end_del_check.Branch(equal); |
| 2031 | 2031 |
| 2032 // Convert the entry to a string (or null if it isn't a property anymore). | 2032 // Convert the entry to a string (or null if it isn't a property anymore). |
| 2033 frame_->Push(frame_->ElementAt(4)); // push enumerable | 2033 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable |
| 2034 frame_->Push(ebx); // push entry | 2034 frame_->EmitPush(ebx); // push entry |
| 2035 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); | 2035 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); |
| 2036 __ mov(ebx, Operand(eax)); | 2036 __ mov(ebx, Operand(eax)); |
| 2037 | 2037 |
| 2038 // 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. |
| 2039 __ cmp(ebx, Factory::null_value()); | 2039 __ cmp(ebx, Factory::null_value()); |
| 2040 node->continue_target()->Branch(equal); | 2040 node->continue_target()->Branch(equal); |
| 2041 | 2041 |
| 2042 end_del_check.Bind(); | 2042 end_del_check.Bind(); |
| 2043 // Store the entry in the 'each' expression and take another spin in the | 2043 // Store the entry in the 'each' expression and take another spin in the |
| 2044 // loop. 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) |
| 2045 frame_->Push(ebx); | 2045 frame_->EmitPush(ebx); |
| 2046 { Reference each(this, node->each()); | 2046 { Reference each(this, node->each()); |
| 2047 if (!each.is_illegal()) { | 2047 if (!each.is_illegal()) { |
| 2048 if (each.size() > 0) { | 2048 if (each.size() > 0) { |
| 2049 frame_->Push(frame_->ElementAt(each.size())); | 2049 frame_->EmitPush(frame_->ElementAt(each.size())); |
| 2050 } | 2050 } |
| 2051 // 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 |
| 2052 // 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 |
| 2053 // right on top of or right underneath a zero-sized reference. | 2053 // right on top of or right underneath a zero-sized reference. |
| 2054 each.SetValue(NOT_CONST_INIT); | 2054 each.SetValue(NOT_CONST_INIT); |
| 2055 if (each.size() > 0) { | 2055 if (each.size() > 0) { |
| 2056 // It's safe to pop the value lying on top of the reference before | 2056 // It's safe to pop the value lying on top of the reference before |
| 2057 // unloading the reference itself (which preserves the top of stack, | 2057 // unloading the reference itself (which preserves the top of stack, |
| 2058 // ie, now the topmost value of the non-zero sized reference), since | 2058 // ie, now the topmost value of the non-zero sized reference), since |
| 2059 // we will discard the top of stack after unloading the reference | 2059 // we will discard the top of stack after unloading the reference |
| 2060 // anyway. | 2060 // anyway. |
| 2061 frame_->Drop(); | 2061 frame_->Drop(); |
| 2062 } | 2062 } |
| 2063 } | 2063 } |
| 2064 } | 2064 } |
| 2065 // Discard the i'th entry pushed above or else the remainder of the | 2065 // Discard the i'th entry pushed above or else the remainder of the |
| 2066 // reference, whichever is currently on top of the stack. | 2066 // reference, whichever is currently on top of the stack. |
| 2067 frame_->Drop(); | 2067 frame_->Drop(); |
| 2068 | 2068 |
| 2069 // Body. | 2069 // Body. |
| 2070 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2070 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2071 Visit(node->body()); | 2071 Visit(node->body()); |
| 2072 | 2072 |
| 2073 // Next. | 2073 // Next. |
| 2074 node->continue_target()->Bind(); | 2074 node->continue_target()->Bind(); |
| 2075 frame_->Pop(eax); | 2075 frame_->Pop(eax); |
| 2076 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 2076 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 2077 frame_->Push(eax); | 2077 frame_->EmitPush(eax); |
| 2078 entry.Jump(); | 2078 entry.Jump(); |
| 2079 | 2079 |
| 2080 // Cleanup. | 2080 // Cleanup. |
| 2081 cleanup.Bind(); | 2081 cleanup.Bind(); |
| 2082 node->break_target()->Bind(); | 2082 node->break_target()->Bind(); |
| 2083 frame_->Drop(5); | 2083 frame_->Drop(5); |
| 2084 | 2084 |
| 2085 // Exit. | 2085 // Exit. |
| 2086 exit.Bind(); | 2086 exit.Bind(); |
| 2087 | 2087 |
| 2088 break_stack_height_ -= kForInStackSize; | 2088 break_stack_height_ -= kForInStackSize; |
| 2089 } | 2089 } |
| 2090 | 2090 |
| 2091 | 2091 |
| 2092 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2092 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 2093 Comment cmnt(masm_, "[ TryCatch"); | 2093 Comment cmnt(masm_, "[ TryCatch"); |
| 2094 | 2094 |
| 2095 JumpTarget try_block(this); | 2095 JumpTarget try_block(this); |
| 2096 JumpTarget exit(this); | 2096 JumpTarget exit(this); |
| 2097 | 2097 |
| 2098 try_block.Call(); | 2098 try_block.Call(); |
| 2099 // --- Catch block --- | 2099 // --- Catch block --- |
| 2100 frame_->Push(eax); | 2100 frame_->EmitPush(eax); |
| 2101 | 2101 |
| 2102 // Store the caught exception in the catch variable. | 2102 // Store the caught exception in the catch variable. |
| 2103 { Reference ref(this, node->catch_var()); | 2103 { Reference ref(this, node->catch_var()); |
| 2104 ASSERT(ref.is_slot()); | 2104 ASSERT(ref.is_slot()); |
| 2105 // Load the exception to the top of the stack. Here we make use of the | 2105 // Load the exception to the top of the stack. Here we make use of the |
| 2106 // convenient property that it doesn't matter whether a value is | 2106 // convenient property that it doesn't matter whether a value is |
| 2107 // immediately on top of or underneath a zero-sized reference. | 2107 // immediately on top of or underneath a zero-sized reference. |
| 2108 ref.SetValue(NOT_CONST_INIT); | 2108 ref.SetValue(NOT_CONST_INIT); |
| 2109 } | 2109 } |
| 2110 | 2110 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2211 // block. Should probably be extended to hold information for | 2211 // block. Should probably be extended to hold information for |
| 2212 // break/continue from within the try block. | 2212 // break/continue from within the try block. |
| 2213 enum { FALLING, THROWING, JUMPING }; | 2213 enum { FALLING, THROWING, JUMPING }; |
| 2214 | 2214 |
| 2215 JumpTarget unlink(this); | 2215 JumpTarget unlink(this); |
| 2216 JumpTarget try_block(this); | 2216 JumpTarget try_block(this); |
| 2217 JumpTarget finally_block(this); | 2217 JumpTarget finally_block(this); |
| 2218 | 2218 |
| 2219 try_block.Call(); | 2219 try_block.Call(); |
| 2220 | 2220 |
| 2221 frame_->Push(eax); | 2221 frame_->EmitPush(eax); |
| 2222 // In case of thrown exceptions, this is where we continue. | 2222 // In case of thrown exceptions, this is where we continue. |
| 2223 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); | 2223 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); |
| 2224 finally_block.Jump(); | 2224 finally_block.Jump(); |
| 2225 | 2225 |
| 2226 | 2226 |
| 2227 // --- Try block --- | 2227 // --- Try block --- |
| 2228 try_block.Bind(); | 2228 try_block.Bind(); |
| 2229 | 2229 |
| 2230 frame_->PushTryHandler(TRY_FINALLY_HANDLER); | 2230 frame_->PushTryHandler(TRY_FINALLY_HANDLER); |
| 2231 int handler_height = frame_->height(); | 2231 int handler_height = frame_->height(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2258 int nof_unlinks = 0; | 2258 int nof_unlinks = 0; |
| 2259 for (int i = 0; i <= nof_escapes; i++) { | 2259 for (int i = 0; i <= nof_escapes; i++) { |
| 2260 shadows[i]->StopShadowing(); | 2260 shadows[i]->StopShadowing(); |
| 2261 if (shadows[i]->is_linked()) nof_unlinks++; | 2261 if (shadows[i]->is_linked()) nof_unlinks++; |
| 2262 } | 2262 } |
| 2263 function_return_is_shadowed_ = function_return_was_shadowed; | 2263 function_return_is_shadowed_ = function_return_was_shadowed; |
| 2264 | 2264 |
| 2265 // If we can fall off the end of the try block, set the state on the stack | 2265 // If we can fall off the end of the try block, set the state on the stack |
| 2266 // to FALLING. | 2266 // to FALLING. |
| 2267 if (frame_ != NULL) { | 2267 if (frame_ != NULL) { |
| 2268 frame_->Push(Immediate(Factory::undefined_value())); // fake TOS | 2268 frame_->EmitPush(Immediate(Factory::undefined_value())); // fake TOS |
| 2269 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); | 2269 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); |
| 2270 if (nof_unlinks > 0) { | 2270 if (nof_unlinks > 0) { |
| 2271 unlink.Jump(); | 2271 unlink.Jump(); |
| 2272 } | 2272 } |
| 2273 } | 2273 } |
| 2274 | 2274 |
| 2275 // Generate code to set the state for the (formerly) shadowing targets that | 2275 // Generate code to set the state for the (formerly) shadowing targets that |
| 2276 // have been jumped to. | 2276 // have been jumped to. |
| 2277 for (int i = 0; i <= nof_escapes; i++) { | 2277 for (int i = 0; i <= nof_escapes; i++) { |
| 2278 if (shadows[i]->is_linked()) { | 2278 if (shadows[i]->is_linked()) { |
| 2279 shadows[i]->Bind(); | 2279 shadows[i]->Bind(); |
| 2280 if (shadows[i]->original_target() == &function_return_) { | 2280 if (shadows[i]->original_target() == &function_return_) { |
| 2281 // If this target shadowed the function return, materialize the | 2281 // If this target shadowed the function return, materialize the |
| 2282 // return value on the stack. | 2282 // return value on the stack. |
| 2283 frame_->Push(eax); | 2283 frame_->EmitPush(eax); |
| 2284 } else { | 2284 } else { |
| 2285 // Fake TOS for targets that shadowed breaks and continues. | 2285 // Fake TOS for targets that shadowed breaks and continues. |
| 2286 frame_->Push(Immediate(Factory::undefined_value())); | 2286 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 2287 } | 2287 } |
| 2288 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); | 2288 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); |
| 2289 unlink.Jump(); | 2289 unlink.Jump(); |
| 2290 } | 2290 } |
| 2291 } | 2291 } |
| 2292 | 2292 |
| 2293 // Unlink from try chain; be careful not to destroy the TOS. | 2293 // Unlink from try chain; be careful not to destroy the TOS. |
| 2294 unlink.Bind(); | 2294 unlink.Bind(); |
| 2295 // Reload sp from the top handler, because some statements that we | 2295 // Reload sp from the top handler, because some statements that we |
| 2296 // break from (eg, for...in) may have left stuff on the stack. | 2296 // break from (eg, for...in) may have left stuff on the stack. |
| 2297 // Preserve the TOS in a register across stack manipulation. | 2297 // Preserve the TOS in a register across stack manipulation. |
| 2298 frame_->Pop(eax); | 2298 frame_->Pop(eax); |
| 2299 ExternalReference handler_address(Top::k_handler_address); | 2299 ExternalReference handler_address(Top::k_handler_address); |
| 2300 __ mov(edx, Operand::StaticVariable(handler_address)); | 2300 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2301 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2301 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2302 StackHandlerConstants::kAddressDisplacement; | 2302 StackHandlerConstants::kAddressDisplacement; |
| 2303 __ lea(esp, Operand(edx, kNextOffset)); | 2303 __ lea(esp, Operand(edx, kNextOffset)); |
| 2304 frame_->Forget(frame_->height() - handler_height); | 2304 frame_->Forget(frame_->height() - handler_height); |
| 2305 | 2305 |
| 2306 frame_->Pop(Operand::StaticVariable(handler_address)); | 2306 frame_->Pop(Operand::StaticVariable(handler_address)); |
| 2307 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2307 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2308 // Next_sp popped. | 2308 // Next_sp popped. |
| 2309 frame_->Push(eax); | 2309 frame_->EmitPush(eax); |
| 2310 | 2310 |
| 2311 // --- Finally block --- | 2311 // --- Finally block --- |
| 2312 finally_block.Bind(); | 2312 finally_block.Bind(); |
| 2313 | 2313 |
| 2314 // Push the state on the stack. | 2314 // Push the state on the stack. |
| 2315 frame_->Push(ecx); | 2315 frame_->EmitPush(ecx); |
| 2316 | 2316 |
| 2317 // We keep two elements on the stack - the (possibly faked) result | 2317 // We keep two elements on the stack - the (possibly faked) result |
| 2318 // and the state - while evaluating the finally block. Record it, so | 2318 // and the state - while evaluating the finally block. Record it, so |
| 2319 // that a break/continue crossing this statement can restore the | 2319 // that a break/continue crossing this statement can restore the |
| 2320 // stack. | 2320 // stack. |
| 2321 const int kFinallyStackSize = 2 * kPointerSize; | 2321 const int kFinallyStackSize = 2 * kPointerSize; |
| 2322 break_stack_height_ += kFinallyStackSize; | 2322 break_stack_height_ += kFinallyStackSize; |
| 2323 | 2323 |
| 2324 // Generate code for the statements in the finally block. | 2324 // Generate code for the statements in the finally block. |
| 2325 VisitStatements(node->finally_block()->statements()); | 2325 VisitStatements(node->finally_block()->statements()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2338 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); | 2338 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); |
| 2339 shadows[i]->original_target()->Branch(equal); | 2339 shadows[i]->original_target()->Branch(equal); |
| 2340 } | 2340 } |
| 2341 } | 2341 } |
| 2342 | 2342 |
| 2343 // Check if we need to rethrow the exception. | 2343 // Check if we need to rethrow the exception. |
| 2344 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); | 2344 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); |
| 2345 exit.Branch(not_equal); | 2345 exit.Branch(not_equal); |
| 2346 | 2346 |
| 2347 // Rethrow exception. | 2347 // Rethrow exception. |
| 2348 frame_->Push(eax); // undo pop from above | 2348 frame_->EmitPush(eax); // undo pop from above |
| 2349 frame_->CallRuntime(Runtime::kReThrow, 1); | 2349 frame_->CallRuntime(Runtime::kReThrow, 1); |
| 2350 | 2350 |
| 2351 // Done. | 2351 // Done. |
| 2352 exit.Bind(); | 2352 exit.Bind(); |
| 2353 } | 2353 } |
| 2354 } | 2354 } |
| 2355 | 2355 |
| 2356 | 2356 |
| 2357 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2357 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2358 Comment cmnt(masm_, "[ DebuggerStatement"); | 2358 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2359 RecordStatementPosition(node); | 2359 RecordStatementPosition(node); |
| 2360 frame_->CallRuntime(Runtime::kDebugBreak, 0); | 2360 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
| 2361 // Ignore the return value. | 2361 // Ignore the return value. |
| 2362 } | 2362 } |
| 2363 | 2363 |
| 2364 | 2364 |
| 2365 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2365 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2366 ASSERT(boilerplate->IsBoilerplate()); | 2366 ASSERT(boilerplate->IsBoilerplate()); |
| 2367 | 2367 |
| 2368 // Push the boilerplate on the stack. | 2368 // Push the boilerplate on the stack. |
| 2369 frame_->Push(Immediate(boilerplate)); | 2369 frame_->EmitPush(Immediate(boilerplate)); |
| 2370 | 2370 |
| 2371 // Create a new closure. | 2371 // Create a new closure. |
| 2372 frame_->Push(esi); | 2372 frame_->EmitPush(esi); |
| 2373 frame_->CallRuntime(Runtime::kNewClosure, 2); | 2373 frame_->CallRuntime(Runtime::kNewClosure, 2); |
| 2374 frame_->Push(eax); | 2374 frame_->EmitPush(eax); |
| 2375 } | 2375 } |
| 2376 | 2376 |
| 2377 | 2377 |
| 2378 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2378 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2379 Comment cmnt(masm_, "[ FunctionLiteral"); | 2379 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2380 | 2380 |
| 2381 // Build the function boilerplate and instantiate it. | 2381 // Build the function boilerplate and instantiate it. |
| 2382 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2382 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2383 // Check for stack-overflow exception. | 2383 // Check for stack-overflow exception. |
| 2384 if (HasStackOverflow()) return; | 2384 if (HasStackOverflow()) return; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2413 } | 2413 } |
| 2414 exit.Bind(); | 2414 exit.Bind(); |
| 2415 } | 2415 } |
| 2416 | 2416 |
| 2417 | 2417 |
| 2418 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2418 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2419 if (slot->type() == Slot::LOOKUP) { | 2419 if (slot->type() == Slot::LOOKUP) { |
| 2420 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2420 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2421 | 2421 |
| 2422 // For now, just do a runtime call. | 2422 // For now, just do a runtime call. |
| 2423 frame_->Push(esi); | 2423 frame_->EmitPush(esi); |
| 2424 frame_->Push(Immediate(slot->var()->name())); | 2424 frame_->EmitPush(Immediate(slot->var()->name())); |
| 2425 | 2425 |
| 2426 if (typeof_state == INSIDE_TYPEOF) { | 2426 if (typeof_state == INSIDE_TYPEOF) { |
| 2427 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2427 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 2428 } else { | 2428 } else { |
| 2429 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2429 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2430 } | 2430 } |
| 2431 frame_->Push(eax); | 2431 frame_->EmitPush(eax); |
| 2432 | 2432 |
| 2433 } else { | 2433 } else { |
| 2434 // Note: We would like to keep the assert below, but it fires because of | 2434 // Note: We would like to keep the assert below, but it fires because of |
| 2435 // some nasty code in LoadTypeofExpression() which should be removed... | 2435 // some nasty code in LoadTypeofExpression() which should be removed... |
| 2436 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2436 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 2437 if (slot->var()->mode() == Variable::CONST) { | 2437 if (slot->var()->mode() == Variable::CONST) { |
| 2438 // Const slots may contain 'the hole' value (the constant hasn't been | 2438 // Const slots may contain 'the hole' value (the constant hasn't been |
| 2439 // initialized yet) which needs to be converted into the 'undefined' | 2439 // initialized yet) which needs to be converted into the 'undefined' |
| 2440 // value. | 2440 // value. |
| 2441 Comment cmnt(masm_, "[ Load const"); | 2441 Comment cmnt(masm_, "[ Load const"); |
| 2442 JumpTarget exit(this); | 2442 JumpTarget exit(this); |
| 2443 __ mov(eax, SlotOperand(slot, ecx)); | 2443 __ mov(eax, SlotOperand(slot, ecx)); |
| 2444 __ cmp(eax, Factory::the_hole_value()); | 2444 __ cmp(eax, Factory::the_hole_value()); |
| 2445 exit.Branch(not_equal); | 2445 exit.Branch(not_equal); |
| 2446 __ mov(eax, Factory::undefined_value()); | 2446 __ mov(eax, Factory::undefined_value()); |
| 2447 exit.Bind(); | 2447 exit.Bind(); |
| 2448 frame_->Push(eax); | 2448 frame_->EmitPush(eax); |
| 2449 } else { | 2449 } else { |
| 2450 frame_->Push(SlotOperand(slot, ecx)); | 2450 frame_->EmitPush(SlotOperand(slot, ecx)); |
| 2451 } | 2451 } |
| 2452 } | 2452 } |
| 2453 } | 2453 } |
| 2454 | 2454 |
| 2455 | 2455 |
| 2456 void CodeGenerator::VisitSlot(Slot* node) { | 2456 void CodeGenerator::VisitSlot(Slot* node) { |
| 2457 Comment cmnt(masm_, "[ Slot"); | 2457 Comment cmnt(masm_, "[ Slot"); |
| 2458 LoadFromSlot(node, typeof_state()); | 2458 LoadFromSlot(node, typeof_state()); |
| 2459 } | 2459 } |
| 2460 | 2460 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2482 | 2482 |
| 2483 | 2483 |
| 2484 void CodeGenerator::VisitLiteral(Literal* node) { | 2484 void CodeGenerator::VisitLiteral(Literal* node) { |
| 2485 Comment cmnt(masm_, "[ Literal"); | 2485 Comment cmnt(masm_, "[ Literal"); |
| 2486 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 2486 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
| 2487 // To prevent long attacker-controlled byte sequences in code, larger | 2487 // To prevent long attacker-controlled byte sequences in code, larger |
| 2488 // Smis are loaded in two steps. | 2488 // Smis are loaded in two steps. |
| 2489 int bits = reinterpret_cast<int>(*node->handle()); | 2489 int bits = reinterpret_cast<int>(*node->handle()); |
| 2490 __ mov(eax, bits & 0x0000FFFF); | 2490 __ mov(eax, bits & 0x0000FFFF); |
| 2491 __ xor_(eax, bits & 0xFFFF0000); | 2491 __ xor_(eax, bits & 0xFFFF0000); |
| 2492 frame_->Push(eax); | 2492 frame_->EmitPush(eax); |
| 2493 } else { | 2493 } else { |
| 2494 frame_->Push(Immediate(node->handle())); | 2494 frame_->EmitPush(Immediate(node->handle())); |
| 2495 } | 2495 } |
| 2496 } | 2496 } |
| 2497 | 2497 |
| 2498 | 2498 |
| 2499 class RegExpDeferred: public DeferredCode { | 2499 class RegExpDeferred: public DeferredCode { |
| 2500 public: | 2500 public: |
| 2501 RegExpDeferred(CodeGenerator* generator, RegExpLiteral* node) | 2501 RegExpDeferred(CodeGenerator* generator, RegExpLiteral* node) |
| 2502 : DeferredCode(generator), node_(node) { | 2502 : DeferredCode(generator), node_(node) { |
| 2503 set_comment("[ RegExpDeferred"); | 2503 set_comment("[ RegExpDeferred"); |
| 2504 } | 2504 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2542 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2542 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
| 2543 __ mov(ebx, FieldOperand(ecx, literal_offset)); | 2543 __ mov(ebx, FieldOperand(ecx, literal_offset)); |
| 2544 | 2544 |
| 2545 // Check whether we need to materialize the RegExp object. | 2545 // Check whether we need to materialize the RegExp object. |
| 2546 // If so, jump to the deferred code. | 2546 // If so, jump to the deferred code. |
| 2547 __ cmp(ebx, Factory::undefined_value()); | 2547 __ cmp(ebx, Factory::undefined_value()); |
| 2548 __ j(equal, deferred->enter(), not_taken); | 2548 __ j(equal, deferred->enter(), not_taken); |
| 2549 __ bind(deferred->exit()); | 2549 __ bind(deferred->exit()); |
| 2550 | 2550 |
| 2551 // Push the literal. | 2551 // Push the literal. |
| 2552 frame_->Push(ebx); | 2552 frame_->EmitPush(ebx); |
| 2553 } | 2553 } |
| 2554 | 2554 |
| 2555 | 2555 |
| 2556 // This deferred code stub will be used for creating the boilerplate | 2556 // This deferred code stub will be used for creating the boilerplate |
| 2557 // by calling Runtime_CreateObjectLiteral. | 2557 // by calling Runtime_CreateObjectLiteral. |
| 2558 // Each created boilerplate is stored in the JSFunction and they are | 2558 // Each created boilerplate is stored in the JSFunction and they are |
| 2559 // therefore context dependent. | 2559 // therefore context dependent. |
| 2560 class ObjectLiteralDeferred: public DeferredCode { | 2560 class ObjectLiteralDeferred: public DeferredCode { |
| 2561 public: | 2561 public: |
| 2562 ObjectLiteralDeferred(CodeGenerator* generator, | 2562 ObjectLiteralDeferred(CodeGenerator* generator, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2602 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2602 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
| 2603 __ mov(ebx, FieldOperand(ecx, literal_offset)); | 2603 __ mov(ebx, FieldOperand(ecx, literal_offset)); |
| 2604 | 2604 |
| 2605 // Check whether we need to materialize the object literal boilerplate. | 2605 // Check whether we need to materialize the object literal boilerplate. |
| 2606 // If so, jump to the deferred code. | 2606 // If so, jump to the deferred code. |
| 2607 __ cmp(ebx, Factory::undefined_value()); | 2607 __ cmp(ebx, Factory::undefined_value()); |
| 2608 __ j(equal, deferred->enter(), not_taken); | 2608 __ j(equal, deferred->enter(), not_taken); |
| 2609 __ bind(deferred->exit()); | 2609 __ bind(deferred->exit()); |
| 2610 | 2610 |
| 2611 // Push the literal. | 2611 // Push the literal. |
| 2612 frame_->Push(ebx); | 2612 frame_->EmitPush(ebx); |
| 2613 // Clone the boilerplate object. | 2613 // Clone the boilerplate object. |
| 2614 frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); | 2614 frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); |
| 2615 // Push the new cloned literal object as the result. | 2615 // Push the new cloned literal object as the result. |
| 2616 frame_->Push(eax); | 2616 frame_->EmitPush(eax); |
| 2617 | 2617 |
| 2618 | 2618 |
| 2619 for (int i = 0; i < node->properties()->length(); i++) { | 2619 for (int i = 0; i < node->properties()->length(); i++) { |
| 2620 ObjectLiteral::Property* property = node->properties()->at(i); | 2620 ObjectLiteral::Property* property = node->properties()->at(i); |
| 2621 switch (property->kind()) { | 2621 switch (property->kind()) { |
| 2622 case ObjectLiteral::Property::CONSTANT: break; | 2622 case ObjectLiteral::Property::CONSTANT: break; |
| 2623 case ObjectLiteral::Property::COMPUTED: { | 2623 case ObjectLiteral::Property::COMPUTED: { |
| 2624 Handle<Object> key(property->key()->handle()); | 2624 Handle<Object> key(property->key()->handle()); |
| 2625 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2625 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 2626 if (key->IsSymbol()) { | 2626 if (key->IsSymbol()) { |
| 2627 __ mov(eax, frame_->Top()); | 2627 __ mov(eax, frame_->Top()); |
| 2628 frame_->Push(eax); | 2628 frame_->EmitPush(eax); |
| 2629 Load(property->value()); | 2629 Load(property->value()); |
| 2630 frame_->Pop(eax); | 2630 frame_->Pop(eax); |
| 2631 __ Set(ecx, Immediate(key)); | 2631 __ Set(ecx, Immediate(key)); |
| 2632 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 2632 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 2633 frame_->Drop(); | 2633 frame_->Drop(); |
| 2634 // Ignore result. | 2634 // Ignore result. |
| 2635 break; | 2635 break; |
| 2636 } | 2636 } |
| 2637 // Fall through | 2637 // Fall through |
| 2638 } | 2638 } |
| 2639 case ObjectLiteral::Property::PROTOTYPE: { | 2639 case ObjectLiteral::Property::PROTOTYPE: { |
| 2640 __ mov(eax, frame_->Top()); | 2640 __ mov(eax, frame_->Top()); |
| 2641 frame_->Push(eax); | 2641 frame_->EmitPush(eax); |
| 2642 Load(property->key()); | 2642 Load(property->key()); |
| 2643 Load(property->value()); | 2643 Load(property->value()); |
| 2644 frame_->CallRuntime(Runtime::kSetProperty, 3); | 2644 frame_->CallRuntime(Runtime::kSetProperty, 3); |
| 2645 // Ignore result. | 2645 // Ignore result. |
| 2646 break; | 2646 break; |
| 2647 } | 2647 } |
| 2648 case ObjectLiteral::Property::SETTER: { | 2648 case ObjectLiteral::Property::SETTER: { |
| 2649 // Duplicate the resulting object on the stack. The runtime | 2649 // Duplicate the resulting object on the stack. The runtime |
| 2650 // function will pop the three arguments passed in. | 2650 // function will pop the three arguments passed in. |
| 2651 __ mov(eax, frame_->Top()); | 2651 __ mov(eax, frame_->Top()); |
| 2652 frame_->Push(eax); | 2652 frame_->EmitPush(eax); |
| 2653 Load(property->key()); | 2653 Load(property->key()); |
| 2654 frame_->Push(Immediate(Smi::FromInt(1))); | 2654 frame_->EmitPush(Immediate(Smi::FromInt(1))); |
| 2655 Load(property->value()); | 2655 Load(property->value()); |
| 2656 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 2656 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2657 // Ignore result. | 2657 // Ignore result. |
| 2658 break; | 2658 break; |
| 2659 } | 2659 } |
| 2660 case ObjectLiteral::Property::GETTER: { | 2660 case ObjectLiteral::Property::GETTER: { |
| 2661 // Duplicate the resulting object on the stack. The runtime | 2661 // Duplicate the resulting object on the stack. The runtime |
| 2662 // function will pop the three arguments passed in. | 2662 // function will pop the three arguments passed in. |
| 2663 __ mov(eax, frame_->Top()); | 2663 __ mov(eax, frame_->Top()); |
| 2664 frame_->Push(eax); | 2664 frame_->EmitPush(eax); |
| 2665 Load(property->key()); | 2665 Load(property->key()); |
| 2666 frame_->Push(Immediate(Smi::FromInt(0))); | 2666 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 2667 Load(property->value()); | 2667 Load(property->value()); |
| 2668 frame_->CallRuntime(Runtime::kDefineAccessor, 4); | 2668 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2669 // Ignore result. | 2669 // Ignore result. |
| 2670 break; | 2670 break; |
| 2671 } | 2671 } |
| 2672 default: UNREACHABLE(); | 2672 default: UNREACHABLE(); |
| 2673 } | 2673 } |
| 2674 } | 2674 } |
| 2675 } | 2675 } |
| 2676 | 2676 |
| 2677 | 2677 |
| 2678 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2678 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 2679 Comment cmnt(masm_, "[ ArrayLiteral"); | 2679 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 2680 | 2680 |
| 2681 // Call runtime to create the array literal. | 2681 // Call runtime to create the array literal. |
| 2682 frame_->Push(Immediate(node->literals())); | 2682 frame_->EmitPush(Immediate(node->literals())); |
| 2683 // Load the function of this frame. | 2683 // Load the function of this frame. |
| 2684 __ mov(ecx, frame_->Function()); | 2684 __ mov(ecx, frame_->Function()); |
| 2685 // Load the literals array of the function. | 2685 // Load the literals array of the function. |
| 2686 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2686 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| 2687 frame_->Push(ecx); | 2687 frame_->EmitPush(ecx); |
| 2688 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2688 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| 2689 | 2689 |
| 2690 // Push the resulting array literal on the stack. | 2690 // Push the resulting array literal on the stack. |
| 2691 frame_->Push(eax); | 2691 frame_->EmitPush(eax); |
| 2692 | 2692 |
| 2693 // Generate code to set the elements in the array that are not | 2693 // Generate code to set the elements in the array that are not |
| 2694 // literals. | 2694 // literals. |
| 2695 for (int i = 0; i < node->values()->length(); i++) { | 2695 for (int i = 0; i < node->values()->length(); i++) { |
| 2696 Expression* value = node->values()->at(i); | 2696 Expression* value = node->values()->at(i); |
| 2697 | 2697 |
| 2698 // If value is literal the property value is already | 2698 // If value is literal the property value is already |
| 2699 // set in the boilerplate object. | 2699 // set in the boilerplate object. |
| 2700 if (value->AsLiteral() == NULL) { | 2700 if (value->AsLiteral() == NULL) { |
| 2701 // The property must be set by generated code. | 2701 // The property must be set by generated code. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2727 | 2727 |
| 2728 | 2728 |
| 2729 void CodeGenerator::VisitAssignment(Assignment* node) { | 2729 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 2730 Comment cmnt(masm_, "[ Assignment"); | 2730 Comment cmnt(masm_, "[ Assignment"); |
| 2731 | 2731 |
| 2732 RecordStatementPosition(node); | 2732 RecordStatementPosition(node); |
| 2733 { Reference target(this, node->target()); | 2733 { Reference target(this, node->target()); |
| 2734 if (target.is_illegal()) { | 2734 if (target.is_illegal()) { |
| 2735 // Fool the virtual frame into thinking that we left the assignment's | 2735 // Fool the virtual frame into thinking that we left the assignment's |
| 2736 // value on the frame. | 2736 // value on the frame. |
| 2737 frame_->Push(Immediate(Smi::FromInt(0))); | 2737 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 2738 return; | 2738 return; |
| 2739 } | 2739 } |
| 2740 | 2740 |
| 2741 if (node->op() == Token::ASSIGN || | 2741 if (node->op() == Token::ASSIGN || |
| 2742 node->op() == Token::INIT_VAR || | 2742 node->op() == Token::INIT_VAR || |
| 2743 node->op() == Token::INIT_CONST) { | 2743 node->op() == Token::INIT_CONST) { |
| 2744 Load(node->value()); | 2744 Load(node->value()); |
| 2745 | 2745 |
| 2746 } else { | 2746 } else { |
| 2747 target.GetValue(NOT_INSIDE_TYPEOF); | 2747 target.GetValue(NOT_INSIDE_TYPEOF); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2774 } | 2774 } |
| 2775 } | 2775 } |
| 2776 | 2776 |
| 2777 | 2777 |
| 2778 void CodeGenerator::VisitThrow(Throw* node) { | 2778 void CodeGenerator::VisitThrow(Throw* node) { |
| 2779 Comment cmnt(masm_, "[ Throw"); | 2779 Comment cmnt(masm_, "[ Throw"); |
| 2780 | 2780 |
| 2781 Load(node->exception()); | 2781 Load(node->exception()); |
| 2782 __ RecordPosition(node->position()); | 2782 __ RecordPosition(node->position()); |
| 2783 frame_->CallRuntime(Runtime::kThrow, 1); | 2783 frame_->CallRuntime(Runtime::kThrow, 1); |
| 2784 frame_->Push(eax); | 2784 frame_->EmitPush(eax); |
| 2785 } | 2785 } |
| 2786 | 2786 |
| 2787 | 2787 |
| 2788 void CodeGenerator::VisitProperty(Property* node) { | 2788 void CodeGenerator::VisitProperty(Property* node) { |
| 2789 Comment cmnt(masm_, "[ Property"); | 2789 Comment cmnt(masm_, "[ Property"); |
| 2790 Reference property(this, node); | 2790 Reference property(this, node); |
| 2791 property.GetValue(typeof_state()); | 2791 property.GetValue(typeof_state()); |
| 2792 } | 2792 } |
| 2793 | 2793 |
| 2794 | 2794 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2812 // automatically handles this by loading the arguments before the function | 2812 // automatically handles this by loading the arguments before the function |
| 2813 // is resolved in cache misses (this also holds for megamorphic calls). | 2813 // is resolved in cache misses (this also holds for megamorphic calls). |
| 2814 // ------------------------------------------------------------------------ | 2814 // ------------------------------------------------------------------------ |
| 2815 | 2815 |
| 2816 if (var != NULL && !var->is_this() && var->is_global()) { | 2816 if (var != NULL && !var->is_this() && var->is_global()) { |
| 2817 // ---------------------------------- | 2817 // ---------------------------------- |
| 2818 // JavaScript example: 'foo(1, 2, 3)' // foo is global | 2818 // JavaScript example: 'foo(1, 2, 3)' // foo is global |
| 2819 // ---------------------------------- | 2819 // ---------------------------------- |
| 2820 | 2820 |
| 2821 // 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. |
| 2822 frame_->Push(Immediate(var->name())); | 2822 frame_->EmitPush(Immediate(var->name())); |
| 2823 | 2823 |
| 2824 // 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 |
| 2825 // 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 |
| 2826 // invoked function. | 2826 // invoked function. |
| 2827 LoadGlobal(); | 2827 LoadGlobal(); |
| 2828 | 2828 |
| 2829 // Load the arguments. | 2829 // Load the arguments. |
| 2830 int arg_count = args->length(); | 2830 int arg_count = args->length(); |
| 2831 for (int i = 0; i < arg_count; i++) { | 2831 for (int i = 0; i < arg_count; i++) { |
| 2832 Load(args->at(i)); | 2832 Load(args->at(i)); |
| 2833 } | 2833 } |
| 2834 | 2834 |
| 2835 // Setup the receiver register and call the IC initialization code. | 2835 // Setup the receiver register and call the IC initialization code. |
| 2836 Handle<Code> stub = ComputeCallInitialize(arg_count); | 2836 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 2837 __ RecordPosition(node->position()); | 2837 __ RecordPosition(node->position()); |
| 2838 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, | 2838 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, |
| 2839 arg_count + 1); | 2839 arg_count + 1); |
| 2840 __ mov(esi, frame_->Context()); | 2840 __ mov(esi, frame_->Context()); |
| 2841 | 2841 |
| 2842 // Overwrite the function on the stack with the result. | 2842 // Overwrite the function on the stack with the result. |
| 2843 __ mov(frame_->Top(), eax); | 2843 __ mov(frame_->Top(), eax); |
| 2844 | 2844 |
| 2845 } else if (var != NULL && var->slot() != NULL && | 2845 } else if (var != NULL && var->slot() != NULL && |
| 2846 var->slot()->type() == Slot::LOOKUP) { | 2846 var->slot()->type() == Slot::LOOKUP) { |
| 2847 // ---------------------------------- | 2847 // ---------------------------------- |
| 2848 // 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 |
| 2849 // ---------------------------------- | 2849 // ---------------------------------- |
| 2850 | 2850 |
| 2851 // Load the function | 2851 // Load the function |
| 2852 frame_->Push(esi); | 2852 frame_->EmitPush(esi); |
| 2853 frame_->Push(Immediate(var->name())); | 2853 frame_->EmitPush(Immediate(var->name())); |
| 2854 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2854 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2855 // eax: slot value; edx: receiver | 2855 // eax: slot value; edx: receiver |
| 2856 | 2856 |
| 2857 // Load the receiver. | 2857 // Load the receiver. |
| 2858 frame_->Push(eax); | 2858 frame_->EmitPush(eax); |
| 2859 frame_->Push(edx); | 2859 frame_->EmitPush(edx); |
| 2860 | 2860 |
| 2861 // Call the function. | 2861 // Call the function. |
| 2862 CallWithArguments(args, node->position()); | 2862 CallWithArguments(args, node->position()); |
| 2863 | 2863 |
| 2864 } else if (property != NULL) { | 2864 } else if (property != NULL) { |
| 2865 // Check if the key is a literal string. | 2865 // Check if the key is a literal string. |
| 2866 Literal* literal = property->key()->AsLiteral(); | 2866 Literal* literal = property->key()->AsLiteral(); |
| 2867 | 2867 |
| 2868 if (literal != NULL && literal->handle()->IsSymbol()) { | 2868 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 2869 // ------------------------------------------------------------------ | 2869 // ------------------------------------------------------------------ |
| 2870 // 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)' |
| 2871 // ------------------------------------------------------------------ | 2871 // ------------------------------------------------------------------ |
| 2872 | 2872 |
| 2873 // 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. |
| 2874 frame_->Push(Immediate(literal->handle())); | 2874 frame_->EmitPush(Immediate(literal->handle())); |
| 2875 Load(property->obj()); | 2875 Load(property->obj()); |
| 2876 | 2876 |
| 2877 // Load the arguments. | 2877 // Load the arguments. |
| 2878 int arg_count = args->length(); | 2878 int arg_count = args->length(); |
| 2879 for (int i = 0; i < arg_count; i++) { | 2879 for (int i = 0; i < arg_count; i++) { |
| 2880 Load(args->at(i)); | 2880 Load(args->at(i)); |
| 2881 } | 2881 } |
| 2882 | 2882 |
| 2883 // Call the IC initialization code. | 2883 // Call the IC initialization code. |
| 2884 Handle<Code> stub = ComputeCallInitialize(arg_count); | 2884 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 2885 __ RecordPosition(node->position()); | 2885 __ RecordPosition(node->position()); |
| 2886 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); | 2886 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 2887 __ mov(esi, frame_->Context()); | 2887 __ mov(esi, frame_->Context()); |
| 2888 | 2888 |
| 2889 // Overwrite the function on the stack with the result. | 2889 // Overwrite the function on the stack with the result. |
| 2890 __ mov(frame_->Top(), eax); | 2890 __ mov(frame_->Top(), eax); |
| 2891 | 2891 |
| 2892 } else { | 2892 } else { |
| 2893 // ------------------------------------------- | 2893 // ------------------------------------------- |
| 2894 // JavaScript example: 'array[index](1, 2, 3)' | 2894 // JavaScript example: 'array[index](1, 2, 3)' |
| 2895 // ------------------------------------------- | 2895 // ------------------------------------------- |
| 2896 | 2896 |
| 2897 // Load the function to call from the property through a reference. | 2897 // Load the function to call from the property through a reference. |
| 2898 Reference ref(this, property); | 2898 Reference ref(this, property); |
| 2899 ref.GetValue(NOT_INSIDE_TYPEOF); | 2899 ref.GetValue(NOT_INSIDE_TYPEOF); |
| 2900 | 2900 |
| 2901 // Pass receiver to called function. | 2901 // Pass receiver to called function. |
| 2902 // The reference's size is non-negative. | 2902 // The reference's size is non-negative. |
| 2903 frame_->Push(frame_->ElementAt(ref.size())); | 2903 frame_->EmitPush(frame_->ElementAt(ref.size())); |
| 2904 | 2904 |
| 2905 // Call the function. | 2905 // Call the function. |
| 2906 CallWithArguments(args, node->position()); | 2906 CallWithArguments(args, node->position()); |
| 2907 } | 2907 } |
| 2908 | 2908 |
| 2909 } else { | 2909 } else { |
| 2910 // ---------------------------------- | 2910 // ---------------------------------- |
| 2911 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 2911 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
| 2912 // ---------------------------------- | 2912 // ---------------------------------- |
| 2913 | 2913 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3061 got_char_code.Jump(); | 3061 got_char_code.Jump(); |
| 3062 | 3062 |
| 3063 // ASCII string. | 3063 // ASCII string. |
| 3064 ascii_string.Bind(); | 3064 ascii_string.Bind(); |
| 3065 // Load the byte. | 3065 // Load the byte. |
| 3066 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 3066 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |
| 3067 | 3067 |
| 3068 got_char_code.Bind(); | 3068 got_char_code.Bind(); |
| 3069 ASSERT(kSmiTag == 0); | 3069 ASSERT(kSmiTag == 0); |
| 3070 __ shl(eax, kSmiTagSize); | 3070 __ shl(eax, kSmiTagSize); |
| 3071 frame_->Push(eax); | 3071 frame_->EmitPush(eax); |
| 3072 end.Jump(); | 3072 end.Jump(); |
| 3073 | 3073 |
| 3074 // Handle non-flat strings. | 3074 // Handle non-flat strings. |
| 3075 not_a_flat_string.Bind(); | 3075 not_a_flat_string.Bind(); |
| 3076 __ and_(edi, kStringRepresentationMask); | 3076 __ and_(edi, kStringRepresentationMask); |
| 3077 __ cmp(edi, kConsStringTag); | 3077 __ cmp(edi, kConsStringTag); |
| 3078 not_a_cons_string_either.Branch(not_equal, not_taken); | 3078 not_a_cons_string_either.Branch(not_equal, not_taken); |
| 3079 | 3079 |
| 3080 // ConsString. | 3080 // ConsString. |
| 3081 // Get the first of the two strings. | 3081 // Get the first of the two strings. |
| 3082 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); | 3082 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); |
| 3083 try_again_with_new_string.Jump(); | 3083 try_again_with_new_string.Jump(); |
| 3084 | 3084 |
| 3085 not_a_cons_string_either.Bind(); | 3085 not_a_cons_string_either.Bind(); |
| 3086 __ cmp(edi, kSlicedStringTag); | 3086 __ cmp(edi, kSlicedStringTag); |
| 3087 slow_case.Branch(not_equal, not_taken); | 3087 slow_case.Branch(not_equal, not_taken); |
| 3088 | 3088 |
| 3089 // SlicedString. | 3089 // SlicedString. |
| 3090 // Add the offset to the index. | 3090 // Add the offset to the index. |
| 3091 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset)); | 3091 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset)); |
| 3092 slow_case.Branch(overflow); | 3092 slow_case.Branch(overflow); |
| 3093 // Get the underlying string. | 3093 // Get the underlying string. |
| 3094 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); | 3094 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); |
| 3095 try_again_with_new_string.Jump(); | 3095 try_again_with_new_string.Jump(); |
| 3096 | 3096 |
| 3097 slow_case.Bind(); | 3097 slow_case.Bind(); |
| 3098 frame_->Push(Immediate(Factory::undefined_value())); | 3098 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3099 | 3099 |
| 3100 end.Bind(); | 3100 end.Bind(); |
| 3101 } | 3101 } |
| 3102 | 3102 |
| 3103 | 3103 |
| 3104 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3104 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3105 ASSERT(args->length() == 1); | 3105 ASSERT(args->length() == 1); |
| 3106 Load(args->at(0)); | 3106 Load(args->at(0)); |
| 3107 JumpTarget answer(this); | 3107 JumpTarget answer(this); |
| 3108 // We need the CC bits to come out as not_equal in the case where the | 3108 // We need the CC bits to come out as not_equal in the case where the |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3128 ASSERT(args->length() == 0); | 3128 ASSERT(args->length() == 0); |
| 3129 | 3129 |
| 3130 // Seed the result with the formal parameters count, which will be | 3130 // Seed the result with the formal parameters count, which will be |
| 3131 // used in case no arguments adaptor frame is found below the | 3131 // used in case no arguments adaptor frame is found below the |
| 3132 // current frame. | 3132 // current frame. |
| 3133 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3133 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 3134 | 3134 |
| 3135 // Call the shared stub to get to the arguments.length. | 3135 // Call the shared stub to get to the arguments.length. |
| 3136 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 3136 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 3137 frame_->CallStub(&stub, 0); | 3137 frame_->CallStub(&stub, 0); |
| 3138 frame_->Push(eax); | 3138 frame_->EmitPush(eax); |
| 3139 } | 3139 } |
| 3140 | 3140 |
| 3141 | 3141 |
| 3142 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3142 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 3143 ASSERT(args->length() == 1); | 3143 ASSERT(args->length() == 1); |
| 3144 JumpTarget leave(this); | 3144 JumpTarget leave(this); |
| 3145 Load(args->at(0)); // Load the object. | 3145 Load(args->at(0)); // Load the object. |
| 3146 __ mov(eax, frame_->Top()); | 3146 __ mov(eax, frame_->Top()); |
| 3147 // if (object->IsSmi()) return object. | 3147 // if (object->IsSmi()) return object. |
| 3148 __ test(eax, Immediate(kSmiTagMask)); | 3148 __ test(eax, Immediate(kSmiTagMask)); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3219 if (CheckForInlineRuntimeCall(node)) { | 3219 if (CheckForInlineRuntimeCall(node)) { |
| 3220 return; | 3220 return; |
| 3221 } | 3221 } |
| 3222 | 3222 |
| 3223 ZoneList<Expression*>* args = node->arguments(); | 3223 ZoneList<Expression*>* args = node->arguments(); |
| 3224 Comment cmnt(masm_, "[ CallRuntime"); | 3224 Comment cmnt(masm_, "[ CallRuntime"); |
| 3225 Runtime::Function* function = node->function(); | 3225 Runtime::Function* function = node->function(); |
| 3226 | 3226 |
| 3227 if (function == NULL) { | 3227 if (function == NULL) { |
| 3228 // Prepare stack for calling JS runtime function. | 3228 // Prepare stack for calling JS runtime function. |
| 3229 frame_->Push(Immediate(node->name())); | 3229 frame_->EmitPush(Immediate(node->name())); |
| 3230 // Push the builtins object found in the current global object. | 3230 // Push the builtins object found in the current global object. |
| 3231 __ mov(edx, GlobalObject()); | 3231 __ mov(edx, GlobalObject()); |
| 3232 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); | 3232 frame_->EmitPush(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); |
| 3233 } | 3233 } |
| 3234 | 3234 |
| 3235 // Push the arguments ("left-to-right"). | 3235 // Push the arguments ("left-to-right"). |
| 3236 int arg_count = args->length(); | 3236 int arg_count = args->length(); |
| 3237 for (int i = 0; i < arg_count; i++) { | 3237 for (int i = 0; i < arg_count; i++) { |
| 3238 Load(args->at(i)); | 3238 Load(args->at(i)); |
| 3239 } | 3239 } |
| 3240 | 3240 |
| 3241 if (function == NULL) { | 3241 if (function == NULL) { |
| 3242 // Call the JS runtime function. | 3242 // Call the JS runtime function. |
| 3243 Handle<Code> stub = ComputeCallInitialize(arg_count); | 3243 Handle<Code> stub = ComputeCallInitialize(arg_count); |
| 3244 __ Set(eax, Immediate(args->length())); | 3244 __ Set(eax, Immediate(args->length())); |
| 3245 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); | 3245 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); |
| 3246 __ mov(esi, frame_->Context()); | 3246 __ mov(esi, frame_->Context()); |
| 3247 __ mov(frame_->Top(), eax); | 3247 __ mov(frame_->Top(), eax); |
| 3248 } else { | 3248 } else { |
| 3249 // Call the C runtime function. | 3249 // Call the C runtime function. |
| 3250 frame_->CallRuntime(function, arg_count); | 3250 frame_->CallRuntime(function, arg_count); |
| 3251 frame_->Push(eax); | 3251 frame_->EmitPush(eax); |
| 3252 } | 3252 } |
| 3253 } | 3253 } |
| 3254 | 3254 |
| 3255 | 3255 |
| 3256 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 3256 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 3257 // 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 |
| 3258 // 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 |
| 3259 // on top of the frame or in the cc register. | 3259 // on top of the frame or in the cc register. |
| 3260 Comment cmnt(masm_, "[ UnaryOperation"); | 3260 Comment cmnt(masm_, "[ UnaryOperation"); |
| 3261 | 3261 |
| 3262 Token::Value op = node->op(); | 3262 Token::Value op = node->op(); |
| 3263 | 3263 |
| 3264 if (op == Token::NOT) { | 3264 if (op == Token::NOT) { |
| 3265 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, | 3265 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
| 3266 false_target(), true_target(), true); | 3266 false_target(), true_target(), true); |
| 3267 cc_reg_ = NegateCondition(cc_reg_); | 3267 cc_reg_ = NegateCondition(cc_reg_); |
| 3268 | 3268 |
| 3269 } else if (op == Token::DELETE) { | 3269 } else if (op == Token::DELETE) { |
| 3270 Property* property = node->expression()->AsProperty(); | 3270 Property* property = node->expression()->AsProperty(); |
| 3271 if (property != NULL) { | 3271 if (property != NULL) { |
| 3272 Load(property->obj()); | 3272 Load(property->obj()); |
| 3273 Load(property->key()); | 3273 Load(property->key()); |
| 3274 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3274 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3275 frame_->Push(eax); | 3275 frame_->EmitPush(eax); |
| 3276 return; | 3276 return; |
| 3277 } | 3277 } |
| 3278 | 3278 |
| 3279 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 3279 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 3280 if (variable != NULL) { | 3280 if (variable != NULL) { |
| 3281 Slot* slot = variable->slot(); | 3281 Slot* slot = variable->slot(); |
| 3282 if (variable->is_global()) { | 3282 if (variable->is_global()) { |
| 3283 LoadGlobal(); | 3283 LoadGlobal(); |
| 3284 frame_->Push(Immediate(variable->name())); | 3284 frame_->EmitPush(Immediate(variable->name())); |
| 3285 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3285 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3286 frame_->Push(eax); | 3286 frame_->EmitPush(eax); |
| 3287 return; | 3287 return; |
| 3288 | 3288 |
| 3289 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 3289 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 3290 // lookup the context holding the named variable | 3290 // lookup the context holding the named variable |
| 3291 frame_->Push(esi); | 3291 frame_->EmitPush(esi); |
| 3292 frame_->Push(Immediate(variable->name())); | 3292 frame_->EmitPush(Immediate(variable->name())); |
| 3293 frame_->CallRuntime(Runtime::kLookupContext, 2); | 3293 frame_->CallRuntime(Runtime::kLookupContext, 2); |
| 3294 // eax: context | 3294 // eax: context |
| 3295 frame_->Push(eax); | 3295 frame_->EmitPush(eax); |
| 3296 frame_->Push(Immediate(variable->name())); | 3296 frame_->EmitPush(Immediate(variable->name())); |
| 3297 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 3297 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3298 frame_->Push(eax); | 3298 frame_->EmitPush(eax); |
| 3299 return; | 3299 return; |
| 3300 } | 3300 } |
| 3301 | 3301 |
| 3302 // Default: Result of deleting non-global, not dynamically | 3302 // Default: Result of deleting non-global, not dynamically |
| 3303 // introduced variables is false. | 3303 // introduced variables is false. |
| 3304 frame_->Push(Immediate(Factory::false_value())); | 3304 frame_->EmitPush(Immediate(Factory::false_value())); |
| 3305 | 3305 |
| 3306 } else { | 3306 } else { |
| 3307 // Default: Result of deleting expressions is true. | 3307 // Default: Result of deleting expressions is true. |
| 3308 Load(node->expression()); // may have side-effects | 3308 Load(node->expression()); // may have side-effects |
| 3309 __ Set(frame_->Top(), Immediate(Factory::true_value())); | 3309 __ Set(frame_->Top(), Immediate(Factory::true_value())); |
| 3310 } | 3310 } |
| 3311 | 3311 |
| 3312 } else if (op == Token::TYPEOF) { | 3312 } else if (op == Token::TYPEOF) { |
| 3313 // Special case for loading the typeof expression; see comment on | 3313 // Special case for loading the typeof expression; see comment on |
| 3314 // LoadTypeofExpression(). | 3314 // LoadTypeofExpression(). |
| 3315 LoadTypeofExpression(node->expression()); | 3315 LoadTypeofExpression(node->expression()); |
| 3316 frame_->CallRuntime(Runtime::kTypeof, 1); | 3316 frame_->CallRuntime(Runtime::kTypeof, 1); |
| 3317 frame_->Push(eax); | 3317 frame_->EmitPush(eax); |
| 3318 | 3318 |
| 3319 } else { | 3319 } else { |
| 3320 Load(node->expression()); | 3320 Load(node->expression()); |
| 3321 switch (op) { | 3321 switch (op) { |
| 3322 case Token::NOT: | 3322 case Token::NOT: |
| 3323 case Token::DELETE: | 3323 case Token::DELETE: |
| 3324 case Token::TYPEOF: | 3324 case Token::TYPEOF: |
| 3325 UNREACHABLE(); // handled above | 3325 UNREACHABLE(); // handled above |
| 3326 break; | 3326 break; |
| 3327 | 3327 |
| 3328 case Token::SUB: { | 3328 case Token::SUB: { |
| 3329 UnarySubStub stub; | 3329 UnarySubStub stub; |
| 3330 // TODO(1222589): remove dependency of TOS being cached inside stub | 3330 // TODO(1222589): remove dependency of TOS being cached inside stub |
| 3331 frame_->Pop(eax); | 3331 frame_->Pop(eax); |
| 3332 frame_->CallStub(&stub, 0); | 3332 frame_->CallStub(&stub, 0); |
| 3333 frame_->Push(eax); | 3333 frame_->EmitPush(eax); |
| 3334 break; | 3334 break; |
| 3335 } | 3335 } |
| 3336 | 3336 |
| 3337 case Token::BIT_NOT: { | 3337 case Token::BIT_NOT: { |
| 3338 // Smi check. | 3338 // Smi check. |
| 3339 JumpTarget smi_label(this); | 3339 JumpTarget smi_label(this); |
| 3340 JumpTarget continue_label(this); | 3340 JumpTarget continue_label(this); |
| 3341 frame_->Pop(eax); | 3341 frame_->Pop(eax); |
| 3342 __ test(eax, Immediate(kSmiTagMask)); | 3342 __ test(eax, Immediate(kSmiTagMask)); |
| 3343 smi_label.Branch(zero, taken); | 3343 smi_label.Branch(zero, taken); |
| 3344 | 3344 |
| 3345 frame_->Push(eax); // undo popping of TOS | 3345 frame_->EmitPush(eax); // undo popping of TOS |
| 3346 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION, 1); | 3346 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION, 1); |
| 3347 | 3347 |
| 3348 continue_label.Jump(); | 3348 continue_label.Jump(); |
| 3349 smi_label.Bind(); | 3349 smi_label.Bind(); |
| 3350 __ not_(eax); | 3350 __ not_(eax); |
| 3351 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. | 3351 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. |
| 3352 continue_label.Bind(); | 3352 continue_label.Bind(); |
| 3353 frame_->Push(eax); | 3353 frame_->EmitPush(eax); |
| 3354 break; | 3354 break; |
| 3355 } | 3355 } |
| 3356 | 3356 |
| 3357 case Token::VOID: | 3357 case Token::VOID: |
| 3358 __ mov(frame_->Top(), Factory::undefined_value()); | 3358 __ mov(frame_->Top(), Factory::undefined_value()); |
| 3359 break; | 3359 break; |
| 3360 | 3360 |
| 3361 case Token::ADD: { | 3361 case Token::ADD: { |
| 3362 // Smi check. | 3362 // Smi check. |
| 3363 JumpTarget continue_label(this); | 3363 JumpTarget continue_label(this); |
| 3364 frame_->Pop(eax); | 3364 frame_->Pop(eax); |
| 3365 __ test(eax, Immediate(kSmiTagMask)); | 3365 __ test(eax, Immediate(kSmiTagMask)); |
| 3366 continue_label.Branch(zero); | 3366 continue_label.Branch(zero); |
| 3367 | 3367 |
| 3368 frame_->Push(eax); | 3368 frame_->EmitPush(eax); |
| 3369 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1); | 3369 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1); |
| 3370 | 3370 |
| 3371 continue_label.Bind(); | 3371 continue_label.Bind(); |
| 3372 frame_->Push(eax); | 3372 frame_->EmitPush(eax); |
| 3373 break; | 3373 break; |
| 3374 } | 3374 } |
| 3375 | 3375 |
| 3376 default: | 3376 default: |
| 3377 UNREACHABLE(); | 3377 UNREACHABLE(); |
| 3378 } | 3378 } |
| 3379 } | 3379 } |
| 3380 } | 3380 } |
| 3381 | 3381 |
| 3382 | 3382 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3469 Comment cmnt(masm_, "[ CountOperation"); | 3469 Comment cmnt(masm_, "[ CountOperation"); |
| 3470 | 3470 |
| 3471 bool is_postfix = node->is_postfix(); | 3471 bool is_postfix = node->is_postfix(); |
| 3472 bool is_increment = node->op() == Token::INC; | 3472 bool is_increment = node->op() == Token::INC; |
| 3473 | 3473 |
| 3474 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 3474 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 3475 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3475 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 3476 | 3476 |
| 3477 // Postfix: Make room for the result. | 3477 // Postfix: Make room for the result. |
| 3478 if (is_postfix) { | 3478 if (is_postfix) { |
| 3479 frame_->Push(Immediate(0)); | 3479 frame_->EmitPush(Immediate(0)); |
| 3480 } | 3480 } |
| 3481 | 3481 |
| 3482 { Reference target(this, node->expression()); | 3482 { Reference target(this, node->expression()); |
| 3483 if (target.is_illegal()) { | 3483 if (target.is_illegal()) { |
| 3484 // Spoof the virtual frame to have the expected height (one higher | 3484 // Spoof the virtual frame to have the expected height (one higher |
| 3485 // than on entry). | 3485 // than on entry). |
| 3486 if (!is_postfix) { | 3486 if (!is_postfix) { |
| 3487 frame_->Push(Immediate(Smi::FromInt(0))); | 3487 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 3488 } | 3488 } |
| 3489 return; | 3489 return; |
| 3490 } | 3490 } |
| 3491 target.GetValue(NOT_INSIDE_TYPEOF); | 3491 target.GetValue(NOT_INSIDE_TYPEOF); |
| 3492 | 3492 |
| 3493 CountOperationDeferred* deferred = | 3493 CountOperationDeferred* deferred = |
| 3494 new CountOperationDeferred(this, is_postfix, is_increment, | 3494 new CountOperationDeferred(this, is_postfix, is_increment, |
| 3495 target.size() * kPointerSize); | 3495 target.size() * kPointerSize); |
| 3496 | 3496 |
| 3497 frame_->Pop(eax); // Load TOS into eax for calculations below | 3497 frame_->Pop(eax); // Load TOS into eax for calculations below |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3510 | 3510 |
| 3511 // If the count operation didn't overflow and the result is a | 3511 // If the count operation didn't overflow and the result is a |
| 3512 // valid smi, we're done. Otherwise, we jump to the deferred | 3512 // valid smi, we're done. Otherwise, we jump to the deferred |
| 3513 // slow-case code. | 3513 // slow-case code. |
| 3514 __ j(overflow, deferred->enter(), not_taken); | 3514 __ j(overflow, deferred->enter(), not_taken); |
| 3515 __ test(eax, Immediate(kSmiTagMask)); | 3515 __ test(eax, Immediate(kSmiTagMask)); |
| 3516 __ j(not_zero, deferred->enter(), not_taken); | 3516 __ j(not_zero, deferred->enter(), not_taken); |
| 3517 | 3517 |
| 3518 // Store the new value in the target if not const. | 3518 // Store the new value in the target if not const. |
| 3519 __ bind(deferred->exit()); | 3519 __ bind(deferred->exit()); |
| 3520 frame_->Push(eax); // Push the new value to TOS | 3520 frame_->EmitPush(eax); // Push the new value to TOS |
| 3521 if (!is_const) target.SetValue(NOT_CONST_INIT); | 3521 if (!is_const) target.SetValue(NOT_CONST_INIT); |
| 3522 } | 3522 } |
| 3523 | 3523 |
| 3524 // Postfix: Discard the new value and use the old. | 3524 // Postfix: Discard the new value and use the old. |
| 3525 if (is_postfix) { | 3525 if (is_postfix) { |
| 3526 frame_->Drop(); | 3526 frame_->Drop(); |
| 3527 } | 3527 } |
| 3528 } | 3528 } |
| 3529 | 3529 |
| 3530 | 3530 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3567 // We have a materialized value on the frame. | 3567 // We have a materialized value on the frame. |
| 3568 JumpTarget pop_and_continue(this); | 3568 JumpTarget pop_and_continue(this); |
| 3569 JumpTarget exit(this); | 3569 JumpTarget exit(this); |
| 3570 | 3570 |
| 3571 // Avoid popping the result if it converts to 'false' using the | 3571 // Avoid popping the result if it converts to 'false' using the |
| 3572 // standard ToBoolean() conversion as described in ECMA-262, section | 3572 // standard ToBoolean() conversion as described in ECMA-262, section |
| 3573 // 9.2, page 30. | 3573 // 9.2, page 30. |
| 3574 // | 3574 // |
| 3575 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3575 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3576 __ mov(eax, frame_->Top()); | 3576 __ mov(eax, frame_->Top()); |
| 3577 frame_->Push(eax); | 3577 frame_->EmitPush(eax); |
| 3578 ToBoolean(&pop_and_continue, &exit); | 3578 ToBoolean(&pop_and_continue, &exit); |
| 3579 Branch(false, &exit); | 3579 Branch(false, &exit); |
| 3580 | 3580 |
| 3581 // Pop the result of evaluating the first part. | 3581 // Pop the result of evaluating the first part. |
| 3582 pop_and_continue.Bind(); | 3582 pop_and_continue.Bind(); |
| 3583 frame_->Drop(); | 3583 frame_->Drop(); |
| 3584 | 3584 |
| 3585 // Evaluate right side expression. | 3585 // Evaluate right side expression. |
| 3586 is_true.Bind(); | 3586 is_true.Bind(); |
| 3587 Load(node->right()); | 3587 Load(node->right()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3610 } else { | 3610 } else { |
| 3611 // We have a materialized value on the frame. | 3611 // We have a materialized value on the frame. |
| 3612 JumpTarget pop_and_continue(this); | 3612 JumpTarget pop_and_continue(this); |
| 3613 JumpTarget exit(this); | 3613 JumpTarget exit(this); |
| 3614 | 3614 |
| 3615 // Avoid popping the result if it converts to 'true' using the | 3615 // Avoid popping the result if it converts to 'true' using the |
| 3616 // standard ToBoolean() conversion as described in ECMA-262, | 3616 // standard ToBoolean() conversion as described in ECMA-262, |
| 3617 // section 9.2, page 30. | 3617 // section 9.2, page 30. |
| 3618 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3618 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3619 __ mov(eax, frame_->Top()); | 3619 __ mov(eax, frame_->Top()); |
| 3620 frame_->Push(eax); | 3620 frame_->EmitPush(eax); |
| 3621 ToBoolean(&exit, &pop_and_continue); | 3621 ToBoolean(&exit, &pop_and_continue); |
| 3622 Branch(true, &exit); | 3622 Branch(true, &exit); |
| 3623 | 3623 |
| 3624 // Pop the result of evaluating the first part. | 3624 // Pop the result of evaluating the first part. |
| 3625 pop_and_continue.Bind(); | 3625 pop_and_continue.Bind(); |
| 3626 frame_->Drop(); | 3626 frame_->Drop(); |
| 3627 | 3627 |
| 3628 // Evaluate right side expression. | 3628 // Evaluate right side expression. |
| 3629 is_false.Bind(); | 3629 is_false.Bind(); |
| 3630 Load(node->right()); | 3630 Load(node->right()); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3661 } else { | 3661 } else { |
| 3662 Load(node->left()); | 3662 Load(node->left()); |
| 3663 Load(node->right()); | 3663 Load(node->right()); |
| 3664 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); | 3664 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
| 3665 } | 3665 } |
| 3666 } | 3666 } |
| 3667 } | 3667 } |
| 3668 | 3668 |
| 3669 | 3669 |
| 3670 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3670 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3671 frame_->Push(frame_->Function()); | 3671 frame_->EmitPush(frame_->Function()); |
| 3672 } | 3672 } |
| 3673 | 3673 |
| 3674 | 3674 |
| 3675 class InstanceofStub: public CodeStub { | 3675 class InstanceofStub: public CodeStub { |
| 3676 public: | 3676 public: |
| 3677 InstanceofStub() { } | 3677 InstanceofStub() { } |
| 3678 | 3678 |
| 3679 void Generate(MacroAssembler* masm); | 3679 void Generate(MacroAssembler* masm); |
| 3680 | 3680 |
| 3681 private: | 3681 private: |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3844 case Token::LTE: | 3844 case Token::LTE: |
| 3845 cc = less_equal; | 3845 cc = less_equal; |
| 3846 break; | 3846 break; |
| 3847 case Token::GTE: | 3847 case Token::GTE: |
| 3848 cc = greater_equal; | 3848 cc = greater_equal; |
| 3849 break; | 3849 break; |
| 3850 case Token::IN: { | 3850 case Token::IN: { |
| 3851 Load(left); | 3851 Load(left); |
| 3852 Load(right); | 3852 Load(right); |
| 3853 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); | 3853 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); |
| 3854 frame_->Push(eax); // push the result | 3854 frame_->EmitPush(eax); // push the result |
| 3855 return; | 3855 return; |
| 3856 } | 3856 } |
| 3857 case Token::INSTANCEOF: { | 3857 case Token::INSTANCEOF: { |
| 3858 Load(left); | 3858 Load(left); |
| 3859 Load(right); | 3859 Load(right); |
| 3860 InstanceofStub stub; | 3860 InstanceofStub stub; |
| 3861 frame_->CallStub(&stub, 2); | 3861 frame_->CallStub(&stub, 2); |
| 3862 __ test(eax, Operand(eax)); | 3862 __ test(eax, Operand(eax)); |
| 3863 cc_reg_ = zero; | 3863 cc_reg_ = zero; |
| 3864 return; | 3864 return; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3949 // Setup the name register. | 3949 // Setup the name register. |
| 3950 __ mov(ecx, name); | 3950 __ mov(ecx, name); |
| 3951 | 3951 |
| 3952 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3952 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3953 if (var != NULL) { | 3953 if (var != NULL) { |
| 3954 ASSERT(var->is_global()); | 3954 ASSERT(var->is_global()); |
| 3955 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 3955 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 3956 } else { | 3956 } else { |
| 3957 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 3957 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 3958 } | 3958 } |
| 3959 frame->Push(eax); // IC call leaves result in eax, push it out | 3959 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 3960 break; | 3960 break; |
| 3961 } | 3961 } |
| 3962 | 3962 |
| 3963 case KEYED: { | 3963 case KEYED: { |
| 3964 // TODO(1241834): Make sure that this it is safe to ignore the | 3964 // TODO(1241834): Make sure that this it is safe to ignore the |
| 3965 // distinction between expressions in a typeof and not in a typeof. | 3965 // distinction between expressions in a typeof and not in a typeof. |
| 3966 Comment cmnt(masm, "[ Load from keyed Property"); | 3966 Comment cmnt(masm, "[ Load from keyed Property"); |
| 3967 Property* property = expression_->AsProperty(); | 3967 Property* property = expression_->AsProperty(); |
| 3968 ASSERT(property != NULL); | 3968 ASSERT(property != NULL); |
| 3969 __ RecordPosition(property->position()); | 3969 __ RecordPosition(property->position()); |
| 3970 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 3970 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 3971 | 3971 |
| 3972 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3972 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3973 if (var != NULL) { | 3973 if (var != NULL) { |
| 3974 ASSERT(var->is_global()); | 3974 ASSERT(var->is_global()); |
| 3975 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 3975 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 3976 } else { | 3976 } else { |
| 3977 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 3977 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 3978 } | 3978 } |
| 3979 frame->Push(eax); // IC call leaves result in eax, push it out | 3979 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 3980 break; | 3980 break; |
| 3981 } | 3981 } |
| 3982 | 3982 |
| 3983 default: | 3983 default: |
| 3984 UNREACHABLE(); | 3984 UNREACHABLE(); |
| 3985 } | 3985 } |
| 3986 } | 3986 } |
| 3987 | 3987 |
| 3988 | 3988 |
| 3989 void Reference::SetValue(InitState init_state) { | 3989 void Reference::SetValue(InitState init_state) { |
| 3990 ASSERT(!is_illegal()); | 3990 ASSERT(!is_illegal()); |
| 3991 ASSERT(!cgen_->has_cc()); | 3991 ASSERT(!cgen_->has_cc()); |
| 3992 MacroAssembler* masm = cgen_->masm(); | 3992 MacroAssembler* masm = cgen_->masm(); |
| 3993 VirtualFrame* frame = cgen_->frame(); | 3993 VirtualFrame* frame = cgen_->frame(); |
| 3994 switch (type_) { | 3994 switch (type_) { |
| 3995 case SLOT: { | 3995 case SLOT: { |
| 3996 Comment cmnt(masm, "[ Store to Slot"); | 3996 Comment cmnt(masm, "[ Store to Slot"); |
| 3997 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 3997 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 3998 ASSERT(slot != NULL); | 3998 ASSERT(slot != NULL); |
| 3999 if (slot->type() == Slot::LOOKUP) { | 3999 if (slot->type() == Slot::LOOKUP) { |
| 4000 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 4000 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 4001 | 4001 |
| 4002 // For now, just do a runtime call. | 4002 // For now, just do a runtime call. |
| 4003 frame->Push(esi); | 4003 frame->EmitPush(esi); |
| 4004 frame->Push(Immediate(slot->var()->name())); | 4004 frame->EmitPush(Immediate(slot->var()->name())); |
| 4005 | 4005 |
| 4006 if (init_state == CONST_INIT) { | 4006 if (init_state == CONST_INIT) { |
| 4007 // Same as the case for a normal store, but ignores attribute | 4007 // Same as the case for a normal store, but ignores attribute |
| 4008 // (e.g. READ_ONLY) of context slot so that we can initialize | 4008 // (e.g. READ_ONLY) of context slot so that we can initialize |
| 4009 // const properties (introduced via eval("const foo = (some | 4009 // const properties (introduced via eval("const foo = (some |
| 4010 // expr);")). Also, uses the current function context instead of | 4010 // expr);")). Also, uses the current function context instead of |
| 4011 // the top context. | 4011 // the top context. |
| 4012 // | 4012 // |
| 4013 // Note that we must declare the foo upon entry of eval(), via a | 4013 // Note that we must declare the foo upon entry of eval(), via a |
| 4014 // context slot declaration, but we cannot initialize it at the | 4014 // context slot declaration, but we cannot initialize it at the |
| 4015 // same time, because the const declaration may be at the end of | 4015 // same time, because the const declaration may be at the end of |
| 4016 // the eval code (sigh...) and the const variable may have been | 4016 // the eval code (sigh...) and the const variable may have been |
| 4017 // used before (where its value is 'undefined'). Thus, we can only | 4017 // used before (where its value is 'undefined'). Thus, we can only |
| 4018 // do the initialization when we actually encounter the expression | 4018 // do the initialization when we actually encounter the expression |
| 4019 // and when the expression operands are defined and valid, and | 4019 // and when the expression operands are defined and valid, and |
| 4020 // thus we need the split into 2 operations: declaration of the | 4020 // thus we need the split into 2 operations: declaration of the |
| 4021 // context slot followed by initialization. | 4021 // context slot followed by initialization. |
| 4022 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 4022 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 4023 } else { | 4023 } else { |
| 4024 frame->CallRuntime(Runtime::kStoreContextSlot, 3); | 4024 frame->CallRuntime(Runtime::kStoreContextSlot, 3); |
| 4025 } | 4025 } |
| 4026 // Storing a variable must keep the (new) value on the expression | 4026 // Storing a variable must keep the (new) value on the expression |
| 4027 // stack. This is necessary for compiling chained assignment | 4027 // stack. This is necessary for compiling chained assignment |
| 4028 // expressions. | 4028 // expressions. |
| 4029 frame->Push(eax); | 4029 frame->EmitPush(eax); |
| 4030 | 4030 |
| 4031 } else { | 4031 } else { |
| 4032 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 4032 ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 4033 | 4033 |
| 4034 JumpTarget exit(cgen_); | 4034 JumpTarget exit(cgen_); |
| 4035 if (init_state == CONST_INIT) { | 4035 if (init_state == CONST_INIT) { |
| 4036 ASSERT(slot->var()->mode() == Variable::CONST); | 4036 ASSERT(slot->var()->mode() == Variable::CONST); |
| 4037 // Only the first const initialization must be executed (the slot | 4037 // Only the first const initialization must be executed (the slot |
| 4038 // still contains 'the hole' value). When the assignment is | 4038 // still contains 'the hole' value). When the assignment is |
| 4039 // executed, the code is identical to a normal store (see below). | 4039 // executed, the code is identical to a normal store (see below). |
| 4040 Comment cmnt(masm, "[ Init const"); | 4040 Comment cmnt(masm, "[ Init const"); |
| 4041 __ mov(eax, cgen_->SlotOperand(slot, ecx)); | 4041 __ mov(eax, cgen_->SlotOperand(slot, ecx)); |
| 4042 __ cmp(eax, Factory::the_hole_value()); | 4042 __ cmp(eax, Factory::the_hole_value()); |
| 4043 exit.Branch(not_equal); | 4043 exit.Branch(not_equal); |
| 4044 } | 4044 } |
| 4045 | 4045 |
| 4046 // We must execute the store. Storing a variable must keep the | 4046 // We must execute the store. Storing a variable must keep the |
| 4047 // (new) value on the stack. This is necessary for compiling | 4047 // (new) value on the stack. This is necessary for compiling |
| 4048 // assignment expressions. | 4048 // assignment expressions. |
| 4049 // | 4049 // |
| 4050 // Note: We will reach here even with slot->var()->mode() == | 4050 // Note: We will reach here even with slot->var()->mode() == |
| 4051 // Variable::CONST because of const declarations which will | 4051 // Variable::CONST because of const declarations which will |
| 4052 // initialize consts to 'the hole' value and by doing so, end up | 4052 // initialize consts to 'the hole' value and by doing so, end up |
| 4053 // calling this code. | 4053 // calling this code. |
| 4054 frame->Pop(eax); | 4054 frame->Pop(eax); |
| 4055 __ mov(cgen_->SlotOperand(slot, ecx), eax); | 4055 __ mov(cgen_->SlotOperand(slot, ecx), eax); |
| 4056 frame->Push(eax); // RecordWrite may destroy the value in eax. | 4056 frame->EmitPush(eax); // RecordWrite may destroy the value in eax. |
| 4057 if (slot->type() == Slot::CONTEXT) { | 4057 if (slot->type() == Slot::CONTEXT) { |
| 4058 // ecx is loaded with context when calling SlotOperand above. | 4058 // ecx is loaded with context when calling SlotOperand above. |
| 4059 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 4059 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 4060 __ RecordWrite(ecx, offset, eax, ebx); | 4060 __ RecordWrite(ecx, offset, eax, ebx); |
| 4061 } | 4061 } |
| 4062 // If we definitely did not jump over the assignment, we do not need | 4062 // If we definitely did not jump over the assignment, we do not need |
| 4063 // to bind the exit label. Doing so can defeat peephole | 4063 // to bind the exit label. Doing so can defeat peephole |
| 4064 // optimization. | 4064 // optimization. |
| 4065 if (init_state == CONST_INIT) { | 4065 if (init_state == CONST_INIT) { |
| 4066 exit.Bind(); | 4066 exit.Bind(); |
| 4067 } | 4067 } |
| 4068 } | 4068 } |
| 4069 break; | 4069 break; |
| 4070 } | 4070 } |
| 4071 | 4071 |
| 4072 case NAMED: { | 4072 case NAMED: { |
| 4073 Comment cmnt(masm, "[ Store to named Property"); | 4073 Comment cmnt(masm, "[ Store to named Property"); |
| 4074 // Call the appropriate IC code. | 4074 // Call the appropriate IC code. |
| 4075 Handle<String> name(GetName()); | 4075 Handle<String> name(GetName()); |
| 4076 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4076 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 4077 // TODO(1222589): Make the IC grab the values from the stack. | 4077 // TODO(1222589): Make the IC grab the values from the stack. |
| 4078 frame->Pop(eax); | 4078 frame->Pop(eax); |
| 4079 // Setup the name register. | 4079 // Setup the name register. |
| 4080 __ mov(ecx, name); | 4080 __ mov(ecx, name); |
| 4081 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4081 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4082 frame->Push(eax); // IC call leaves result in eax, push it out | 4082 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4083 break; | 4083 break; |
| 4084 } | 4084 } |
| 4085 | 4085 |
| 4086 case KEYED: { | 4086 case KEYED: { |
| 4087 Comment cmnt(masm, "[ Store to keyed Property"); | 4087 Comment cmnt(masm, "[ Store to keyed Property"); |
| 4088 Property* property = expression_->AsProperty(); | 4088 Property* property = expression_->AsProperty(); |
| 4089 ASSERT(property != NULL); | 4089 ASSERT(property != NULL); |
| 4090 __ RecordPosition(property->position()); | 4090 __ RecordPosition(property->position()); |
| 4091 // Call IC code. | 4091 // Call IC code. |
| 4092 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 4092 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 4093 // TODO(1222589): Make the IC grab the values from the stack. | 4093 // TODO(1222589): Make the IC grab the values from the stack. |
| 4094 frame->Pop(eax); | 4094 frame->Pop(eax); |
| 4095 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4095 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4096 frame->Push(eax); // IC call leaves result in eax, push it out | 4096 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4097 break; | 4097 break; |
| 4098 } | 4098 } |
| 4099 | 4099 |
| 4100 default: | 4100 default: |
| 4101 UNREACHABLE(); | 4101 UNREACHABLE(); |
| 4102 } | 4102 } |
| 4103 } | 4103 } |
| 4104 | 4104 |
| 4105 | 4105 |
| 4106 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). | 4106 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). |
| (...skipping 1214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5321 | 5321 |
| 5322 // Slow-case: Go through the JavaScript implementation. | 5322 // Slow-case: Go through the JavaScript implementation. |
| 5323 __ bind(&slow); | 5323 __ bind(&slow); |
| 5324 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5324 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5325 } | 5325 } |
| 5326 | 5326 |
| 5327 | 5327 |
| 5328 #undef __ | 5328 #undef __ |
| 5329 | 5329 |
| 5330 } } // namespace v8::internal | 5330 } } // namespace v8::internal |
| OLD | NEW |