| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 LoadFromSlotCheckForArguments(variable->AsSlot(), INSIDE_TYPEOF); | 726 LoadFromSlotCheckForArguments(variable->AsSlot(), INSIDE_TYPEOF); |
| 727 } else { | 727 } else { |
| 728 // Anything else can be handled normally. | 728 // Anything else can be handled normally. |
| 729 Load(expr); | 729 Load(expr); |
| 730 } | 730 } |
| 731 } | 731 } |
| 732 | 732 |
| 733 | 733 |
| 734 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { | 734 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { |
| 735 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; | 735 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; |
| 736 ASSERT(scope()->arguments_shadow() != NULL); | 736 |
| 737 // In strict mode there is no need for shadow arguments. |
| 738 ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode()); |
| 739 |
| 737 // We don't want to do lazy arguments allocation for functions that | 740 // We don't want to do lazy arguments allocation for functions that |
| 738 // have heap-allocated contexts, because it interfers with the | 741 // have heap-allocated contexts, because it interfers with the |
| 739 // uninitialized const tracking in the context objects. | 742 // uninitialized const tracking in the context objects. |
| 740 return (scope()->num_heap_slots() > 0) | 743 return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode()) |
| 741 ? EAGER_ARGUMENTS_ALLOCATION | 744 ? EAGER_ARGUMENTS_ALLOCATION |
| 742 : LAZY_ARGUMENTS_ALLOCATION; | 745 : LAZY_ARGUMENTS_ALLOCATION; |
| 743 } | 746 } |
| 744 | 747 |
| 745 | 748 |
| 746 Result CodeGenerator::StoreArgumentsObject(bool initial) { | 749 Result CodeGenerator::StoreArgumentsObject(bool initial) { |
| 747 ArgumentsAllocationMode mode = ArgumentsMode(); | 750 ArgumentsAllocationMode mode = ArgumentsMode(); |
| 748 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | 751 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); |
| 749 | 752 |
| 750 Comment cmnt(masm_, "[ store arguments object"); | 753 Comment cmnt(masm_, "[ store arguments object"); |
| 751 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | 754 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { |
| 752 // When using lazy arguments allocation, we store the arguments marker value | 755 // When using lazy arguments allocation, we store the arguments marker value |
| 753 // as a sentinel indicating that the arguments object hasn't been | 756 // as a sentinel indicating that the arguments object hasn't been |
| 754 // allocated yet. | 757 // allocated yet. |
| 755 frame_->Push(Factory::arguments_marker()); | 758 frame_->Push(Factory::arguments_marker()); |
| 756 } else { | 759 } else { |
| 757 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 760 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 758 frame_->PushFunction(); | 761 frame_->PushFunction(); |
| 759 frame_->PushReceiverSlotAddress(); | 762 frame_->PushReceiverSlotAddress(); |
| 760 frame_->Push(Smi::FromInt(scope()->num_parameters())); | 763 frame_->Push(Smi::FromInt(scope()->num_parameters())); |
| 761 Result result = frame_->CallStub(&stub, 3); | 764 Result result = frame_->CallStub(&stub, 3); |
| 762 frame_->Push(&result); | 765 frame_->Push(&result); |
| 763 } | 766 } |
| 764 | 767 |
| 765 Variable* arguments = scope()->arguments(); | 768 Variable* arguments = scope()->arguments(); |
| 766 Variable* shadow = scope()->arguments_shadow(); | 769 Variable* shadow = scope()->arguments_shadow(); |
| 770 |
| 767 ASSERT(arguments != NULL && arguments->AsSlot() != NULL); | 771 ASSERT(arguments != NULL && arguments->AsSlot() != NULL); |
| 768 ASSERT(shadow != NULL && shadow->AsSlot() != NULL); | 772 ASSERT((shadow != NULL && shadow->AsSlot() != NULL) || |
| 773 scope()->is_strict_mode()); |
| 774 |
| 769 JumpTarget done; | 775 JumpTarget done; |
| 770 bool skip_arguments = false; | 776 bool skip_arguments = false; |
| 771 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | 777 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { |
| 772 // We have to skip storing into the arguments slot if it has | 778 // We have to skip storing into the arguments slot if it has |
| 773 // already been written to. This can happen if the a function | 779 // already been written to. This can happen if the a function |
| 774 // has a local variable named 'arguments'. | 780 // has a local variable named 'arguments'. |
| 775 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); | 781 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); |
| 776 Result probe = frame_->Pop(); | 782 Result probe = frame_->Pop(); |
| 777 if (probe.is_constant()) { | 783 if (probe.is_constant()) { |
| 778 // We have to skip updating the arguments object if it has | 784 // We have to skip updating the arguments object if it has |
| 779 // been assigned a proper value. | 785 // been assigned a proper value. |
| 780 skip_arguments = !probe.handle()->IsArgumentsMarker(); | 786 skip_arguments = !probe.handle()->IsArgumentsMarker(); |
| 781 } else { | 787 } else { |
| 782 __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker())); | 788 __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker())); |
| 783 probe.Unuse(); | 789 probe.Unuse(); |
| 784 done.Branch(not_equal); | 790 done.Branch(not_equal); |
| 785 } | 791 } |
| 786 } | 792 } |
| 787 if (!skip_arguments) { | 793 if (!skip_arguments) { |
| 788 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); | 794 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); |
| 789 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 795 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
| 790 } | 796 } |
| 791 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); | 797 if (shadow != NULL) { |
| 798 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); |
| 799 } |
| 792 return frame_->Pop(); | 800 return frame_->Pop(); |
| 793 } | 801 } |
| 794 | 802 |
| 795 //------------------------------------------------------------------------------ | 803 //------------------------------------------------------------------------------ |
| 796 // CodeGenerator implementation of variables, lookups, and stores. | 804 // CodeGenerator implementation of variables, lookups, and stores. |
| 797 | 805 |
| 798 Reference::Reference(CodeGenerator* cgen, | 806 Reference::Reference(CodeGenerator* cgen, |
| 799 Expression* expression, | 807 Expression* expression, |
| 800 bool persist_after_get) | 808 bool persist_after_get) |
| 801 : cgen_(cgen), | 809 : cgen_(cgen), |
| (...skipping 2721 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3523 | 3531 |
| 3524 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 3532 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 3525 // Call the runtime to declare the globals. The inevitable call | 3533 // Call the runtime to declare the globals. The inevitable call |
| 3526 // will sync frame elements to memory anyway, so we do it eagerly to | 3534 // will sync frame elements to memory anyway, so we do it eagerly to |
| 3527 // allow us to push the arguments directly into place. | 3535 // allow us to push the arguments directly into place. |
| 3528 frame_->SyncRange(0, frame_->element_count() - 1); | 3536 frame_->SyncRange(0, frame_->element_count() - 1); |
| 3529 | 3537 |
| 3530 frame_->EmitPush(esi); // The context is the first argument. | 3538 frame_->EmitPush(esi); // The context is the first argument. |
| 3531 frame_->EmitPush(Immediate(pairs)); | 3539 frame_->EmitPush(Immediate(pairs)); |
| 3532 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 3540 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 3533 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 3541 frame_->EmitPush(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 3542 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 4); |
| 3534 // Return value is ignored. | 3543 // Return value is ignored. |
| 3535 } | 3544 } |
| 3536 | 3545 |
| 3537 | 3546 |
| 3538 void CodeGenerator::VisitDeclaration(Declaration* node) { | 3547 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 3539 Comment cmnt(masm_, "[ Declaration"); | 3548 Comment cmnt(masm_, "[ Declaration"); |
| 3540 Variable* var = node->proxy()->var(); | 3549 Variable* var = node->proxy()->var(); |
| 3541 ASSERT(var != NULL); // must have been resolved | 3550 ASSERT(var != NULL); // must have been resolved |
| 3542 Slot* slot = var->AsSlot(); | 3551 Slot* slot = var->AsSlot(); |
| 3543 | 3552 |
| (...skipping 1712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5256 // context slot declaration, but we cannot initialize it at the same | 5265 // context slot declaration, but we cannot initialize it at the same |
| 5257 // time, because the const declaration may be at the end of the eval | 5266 // time, because the const declaration may be at the end of the eval |
| 5258 // code (sigh...) and the const variable may have been used before | 5267 // code (sigh...) and the const variable may have been used before |
| 5259 // (where its value is 'undefined'). Thus, we can only do the | 5268 // (where its value is 'undefined'). Thus, we can only do the |
| 5260 // initialization when we actually encounter the expression and when | 5269 // initialization when we actually encounter the expression and when |
| 5261 // the expression operands are defined and valid, and thus we need the | 5270 // the expression operands are defined and valid, and thus we need the |
| 5262 // split into 2 operations: declaration of the context slot followed | 5271 // split into 2 operations: declaration of the context slot followed |
| 5263 // by initialization. | 5272 // by initialization. |
| 5264 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 5273 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 5265 } else { | 5274 } else { |
| 5266 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | 5275 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 5276 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 4); |
| 5267 } | 5277 } |
| 5268 // Storing a variable must keep the (new) value on the expression | 5278 // Storing a variable must keep the (new) value on the expression |
| 5269 // stack. This is necessary for compiling chained assignment | 5279 // stack. This is necessary for compiling chained assignment |
| 5270 // expressions. | 5280 // expressions. |
| 5271 frame_->Push(&value); | 5281 frame_->Push(&value); |
| 5272 | 5282 |
| 5273 } else { | 5283 } else { |
| 5274 ASSERT(!slot->var()->is_dynamic()); | 5284 ASSERT(!slot->var()->is_dynamic()); |
| 5275 | 5285 |
| 5276 JumpTarget exit; | 5286 JumpTarget exit; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5362 ASSERT(var->is_global()); | 5372 ASSERT(var->is_global()); |
| 5363 ASSERT(!in_safe_int32_mode()); | 5373 ASSERT(!in_safe_int32_mode()); |
| 5364 Reference ref(this, node); | 5374 Reference ref(this, node); |
| 5365 ref.GetValue(); | 5375 ref.GetValue(); |
| 5366 } | 5376 } |
| 5367 } | 5377 } |
| 5368 | 5378 |
| 5369 | 5379 |
| 5370 void CodeGenerator::VisitLiteral(Literal* node) { | 5380 void CodeGenerator::VisitLiteral(Literal* node) { |
| 5371 Comment cmnt(masm_, "[ Literal"); | 5381 Comment cmnt(masm_, "[ Literal"); |
| 5372 if (in_safe_int32_mode()) { | 5382 if (frame_->ConstantPoolOverflowed()) { |
| 5373 frame_->PushUntaggedElement(node->handle()); | 5383 Result temp = allocator_->Allocate(); |
| 5384 ASSERT(temp.is_valid()); |
| 5385 if (in_safe_int32_mode()) { |
| 5386 temp.set_untagged_int32(true); |
| 5387 } |
| 5388 __ Set(temp.reg(), Immediate(node->handle())); |
| 5389 frame_->Push(&temp); |
| 5374 } else { | 5390 } else { |
| 5375 frame_->Push(node->handle()); | 5391 if (in_safe_int32_mode()) { |
| 5392 frame_->PushUntaggedElement(node->handle()); |
| 5393 } else { |
| 5394 frame_->Push(node->handle()); |
| 5395 } |
| 5376 } | 5396 } |
| 5377 } | 5397 } |
| 5378 | 5398 |
| 5379 | 5399 |
| 5380 void CodeGenerator::PushUnsafeSmi(Handle<Object> value) { | 5400 void CodeGenerator::PushUnsafeSmi(Handle<Object> value) { |
| 5381 ASSERT(value->IsSmi()); | 5401 ASSERT(value->IsSmi()); |
| 5382 int bits = reinterpret_cast<int>(*value); | 5402 int bits = reinterpret_cast<int>(*value); |
| 5383 __ push(Immediate(bits ^ jit_cookie_)); | 5403 __ push(Immediate(bits ^ jit_cookie_)); |
| 5384 __ xor_(Operand(esp, 0), Immediate(jit_cookie_)); | 5404 __ xor_(Operand(esp, 0), Immediate(jit_cookie_)); |
| 5385 } | 5405 } |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5610 break; | 5630 break; |
| 5611 } | 5631 } |
| 5612 // Fall through | 5632 // Fall through |
| 5613 } | 5633 } |
| 5614 case ObjectLiteral::Property::PROTOTYPE: { | 5634 case ObjectLiteral::Property::PROTOTYPE: { |
| 5615 // Duplicate the object as an argument to the runtime call. | 5635 // Duplicate the object as an argument to the runtime call. |
| 5616 frame_->Dup(); | 5636 frame_->Dup(); |
| 5617 Load(property->key()); | 5637 Load(property->key()); |
| 5618 Load(property->value()); | 5638 Load(property->value()); |
| 5619 if (property->emit_store()) { | 5639 if (property->emit_store()) { |
| 5640 frame_->Push(Smi::FromInt(NONE)); // PropertyAttributes |
| 5620 // Ignore the result. | 5641 // Ignore the result. |
| 5621 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); | 5642 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 4); |
| 5622 } else { | 5643 } else { |
| 5623 frame_->Drop(3); | 5644 frame_->Drop(3); |
| 5624 } | 5645 } |
| 5625 break; | 5646 break; |
| 5626 } | 5647 } |
| 5627 case ObjectLiteral::Property::SETTER: { | 5648 case ObjectLiteral::Property::SETTER: { |
| 5628 // Duplicate the object as an argument to the runtime call. | 5649 // Duplicate the object as an argument to the runtime call. |
| 5629 frame_->Dup(); | 5650 frame_->Dup(); |
| 5630 Load(property->key()); | 5651 Load(property->key()); |
| 5631 frame_->Push(Smi::FromInt(1)); | 5652 frame_->Push(Smi::FromInt(1)); |
| (...skipping 2610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8242 Load(property->key()); | 8263 Load(property->key()); |
| 8243 frame_->Push(Smi::FromInt(strict_mode_flag())); | 8264 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 8244 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3); | 8265 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3); |
| 8245 frame_->Push(&answer); | 8266 frame_->Push(&answer); |
| 8246 return; | 8267 return; |
| 8247 } | 8268 } |
| 8248 | 8269 |
| 8249 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 8270 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 8250 if (variable != NULL) { | 8271 if (variable != NULL) { |
| 8251 // Delete of an unqualified identifier is disallowed in strict mode | 8272 // Delete of an unqualified identifier is disallowed in strict mode |
| 8252 // so this code can only be reached in non-strict mode. | 8273 // but "delete this" is. |
| 8253 ASSERT(strict_mode_flag() == kNonStrictMode); | 8274 ASSERT(strict_mode_flag() == kNonStrictMode || variable->is_this()); |
| 8254 Slot* slot = variable->AsSlot(); | 8275 Slot* slot = variable->AsSlot(); |
| 8255 if (variable->is_global()) { | 8276 if (variable->is_global()) { |
| 8256 LoadGlobal(); | 8277 LoadGlobal(); |
| 8257 frame_->Push(variable->name()); | 8278 frame_->Push(variable->name()); |
| 8258 frame_->Push(Smi::FromInt(kNonStrictMode)); | 8279 frame_->Push(Smi::FromInt(kNonStrictMode)); |
| 8259 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, | 8280 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
| 8260 CALL_FUNCTION, 3); | 8281 CALL_FUNCTION, 3); |
| 8261 frame_->Push(&answer); | 8282 frame_->Push(&answer); |
| 8262 return; | |
| 8263 | 8283 |
| 8264 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 8284 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 8265 // Call the runtime to delete from the context holding the named | 8285 // Call the runtime to delete from the context holding the named |
| 8266 // variable. Sync the virtual frame eagerly so we can push the | 8286 // variable. Sync the virtual frame eagerly so we can push the |
| 8267 // arguments directly into place. | 8287 // arguments directly into place. |
| 8268 frame_->SyncRange(0, frame_->element_count() - 1); | 8288 frame_->SyncRange(0, frame_->element_count() - 1); |
| 8269 frame_->EmitPush(esi); | 8289 frame_->EmitPush(esi); |
| 8270 frame_->EmitPush(Immediate(variable->name())); | 8290 frame_->EmitPush(Immediate(variable->name())); |
| 8271 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); | 8291 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); |
| 8272 frame_->Push(&answer); | 8292 frame_->Push(&answer); |
| 8273 return; | 8293 } else { |
| 8294 // Default: Result of deleting non-global, not dynamically |
| 8295 // introduced variables is false. |
| 8296 frame_->Push(Factory::false_value()); |
| 8274 } | 8297 } |
| 8275 | |
| 8276 // Default: Result of deleting non-global, not dynamically | |
| 8277 // introduced variables is false. | |
| 8278 frame_->Push(Factory::false_value()); | |
| 8279 | |
| 8280 } else { | 8298 } else { |
| 8281 // Default: Result of deleting expressions is true. | 8299 // Default: Result of deleting expressions is true. |
| 8282 Load(node->expression()); // may have side-effects | 8300 Load(node->expression()); // may have side-effects |
| 8283 frame_->SetElementAt(0, Factory::true_value()); | 8301 frame_->SetElementAt(0, Factory::true_value()); |
| 8284 } | 8302 } |
| 8285 | 8303 |
| 8286 } else if (op == Token::TYPEOF) { | 8304 } else if (op == Token::TYPEOF) { |
| 8287 // Special case for loading the typeof expression; see comment on | 8305 // Special case for loading the typeof expression; see comment on |
| 8288 // LoadTypeofExpression(). | 8306 // LoadTypeofExpression(). |
| 8289 LoadTypeofExpression(node->expression()); | 8307 LoadTypeofExpression(node->expression()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 8311 if (in_safe_int32_mode()) { | 8329 if (in_safe_int32_mode()) { |
| 8312 Visit(node->expression()); | 8330 Visit(node->expression()); |
| 8313 Result value = frame_->Pop(); | 8331 Result value = frame_->Pop(); |
| 8314 ASSERT(value.is_untagged_int32()); | 8332 ASSERT(value.is_untagged_int32()); |
| 8315 // Registers containing an int32 value are not multiply used. | 8333 // Registers containing an int32 value are not multiply used. |
| 8316 ASSERT(!value.is_register() || !frame_->is_used(value.reg())); | 8334 ASSERT(!value.is_register() || !frame_->is_used(value.reg())); |
| 8317 value.ToRegister(); | 8335 value.ToRegister(); |
| 8318 switch (op) { | 8336 switch (op) { |
| 8319 case Token::SUB: { | 8337 case Token::SUB: { |
| 8320 __ neg(value.reg()); | 8338 __ neg(value.reg()); |
| 8339 frame_->Push(&value); |
| 8321 if (node->no_negative_zero()) { | 8340 if (node->no_negative_zero()) { |
| 8322 // -MIN_INT is MIN_INT with the overflow flag set. | 8341 // -MIN_INT is MIN_INT with the overflow flag set. |
| 8323 unsafe_bailout_->Branch(overflow); | 8342 unsafe_bailout_->Branch(overflow); |
| 8324 } else { | 8343 } else { |
| 8325 // MIN_INT and 0 both have bad negations. They both have 31 zeros. | 8344 // MIN_INT and 0 both have bad negations. They both have 31 zeros. |
| 8326 __ test(value.reg(), Immediate(0x7FFFFFFF)); | 8345 __ test(value.reg(), Immediate(0x7FFFFFFF)); |
| 8327 unsafe_bailout_->Branch(zero); | 8346 unsafe_bailout_->Branch(zero); |
| 8328 } | 8347 } |
| 8329 break; | 8348 break; |
| 8330 } | 8349 } |
| 8331 case Token::BIT_NOT: { | 8350 case Token::BIT_NOT: { |
| 8332 __ not_(value.reg()); | 8351 __ not_(value.reg()); |
| 8352 frame_->Push(&value); |
| 8333 break; | 8353 break; |
| 8334 } | 8354 } |
| 8335 case Token::ADD: { | 8355 case Token::ADD: { |
| 8336 // Unary plus has no effect on int32 values. | 8356 // Unary plus has no effect on int32 values. |
| 8357 frame_->Push(&value); |
| 8337 break; | 8358 break; |
| 8338 } | 8359 } |
| 8339 default: | 8360 default: |
| 8340 UNREACHABLE(); | 8361 UNREACHABLE(); |
| 8341 break; | 8362 break; |
| 8342 } | 8363 } |
| 8343 frame_->Push(&value); | |
| 8344 } else { | 8364 } else { |
| 8345 Load(node->expression()); | 8365 Load(node->expression()); |
| 8346 bool can_overwrite = node->expression()->ResultOverwriteAllowed(); | 8366 bool can_overwrite = node->expression()->ResultOverwriteAllowed(); |
| 8347 UnaryOverwriteMode overwrite = | 8367 UnaryOverwriteMode overwrite = |
| 8348 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 8368 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 8349 bool no_negative_zero = node->expression()->no_negative_zero(); | 8369 bool no_negative_zero = node->expression()->no_negative_zero(); |
| 8350 switch (op) { | 8370 switch (op) { |
| 8351 case Token::NOT: | 8371 case Token::NOT: |
| 8352 case Token::DELETE: | 8372 case Token::DELETE: |
| 8353 case Token::TYPEOF: | 8373 case Token::TYPEOF: |
| (...skipping 1115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9469 | 9489 |
| 9470 if (!dst_.is(eax)) __ mov(dst_, eax); | 9490 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 9471 } | 9491 } |
| 9472 | 9492 |
| 9473 | 9493 |
| 9474 class DeferredReferenceSetKeyedValue: public DeferredCode { | 9494 class DeferredReferenceSetKeyedValue: public DeferredCode { |
| 9475 public: | 9495 public: |
| 9476 DeferredReferenceSetKeyedValue(Register value, | 9496 DeferredReferenceSetKeyedValue(Register value, |
| 9477 Register key, | 9497 Register key, |
| 9478 Register receiver, | 9498 Register receiver, |
| 9479 Register scratch) | 9499 Register scratch, |
| 9500 StrictModeFlag strict_mode) |
| 9480 : value_(value), | 9501 : value_(value), |
| 9481 key_(key), | 9502 key_(key), |
| 9482 receiver_(receiver), | 9503 receiver_(receiver), |
| 9483 scratch_(scratch) { | 9504 scratch_(scratch), |
| 9505 strict_mode_(strict_mode) { |
| 9484 set_comment("[ DeferredReferenceSetKeyedValue"); | 9506 set_comment("[ DeferredReferenceSetKeyedValue"); |
| 9485 } | 9507 } |
| 9486 | 9508 |
| 9487 virtual void Generate(); | 9509 virtual void Generate(); |
| 9488 | 9510 |
| 9489 Label* patch_site() { return &patch_site_; } | 9511 Label* patch_site() { return &patch_site_; } |
| 9490 | 9512 |
| 9491 private: | 9513 private: |
| 9492 Register value_; | 9514 Register value_; |
| 9493 Register key_; | 9515 Register key_; |
| 9494 Register receiver_; | 9516 Register receiver_; |
| 9495 Register scratch_; | 9517 Register scratch_; |
| 9496 Label patch_site_; | 9518 Label patch_site_; |
| 9519 StrictModeFlag strict_mode_; |
| 9497 }; | 9520 }; |
| 9498 | 9521 |
| 9499 | 9522 |
| 9500 void DeferredReferenceSetKeyedValue::Generate() { | 9523 void DeferredReferenceSetKeyedValue::Generate() { |
| 9501 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 9524 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); |
| 9502 // Move value_ to eax, key_ to ecx, and receiver_ to edx. | 9525 // Move value_ to eax, key_ to ecx, and receiver_ to edx. |
| 9503 Register old_value = value_; | 9526 Register old_value = value_; |
| 9504 | 9527 |
| 9505 // First, move value to eax. | 9528 // First, move value to eax. |
| 9506 if (!value_.is(eax)) { | 9529 if (!value_.is(eax)) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9545 } | 9568 } |
| 9546 } | 9569 } |
| 9547 } else { // Key is not in edx or ecx. | 9570 } else { // Key is not in edx or ecx. |
| 9548 if (!receiver_.is(edx)) { | 9571 if (!receiver_.is(edx)) { |
| 9549 __ mov(edx, receiver_); | 9572 __ mov(edx, receiver_); |
| 9550 } | 9573 } |
| 9551 __ mov(ecx, key_); | 9574 __ mov(ecx, key_); |
| 9552 } | 9575 } |
| 9553 | 9576 |
| 9554 // Call the IC stub. | 9577 // Call the IC stub. |
| 9555 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 9578 Handle<Code> ic(Builtins::builtin( |
| 9579 (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict |
| 9580 : Builtins::KeyedStoreIC_Initialize)); |
| 9556 __ call(ic, RelocInfo::CODE_TARGET); | 9581 __ call(ic, RelocInfo::CODE_TARGET); |
| 9557 // The delta from the start of the map-compare instruction to the | 9582 // The delta from the start of the map-compare instruction to the |
| 9558 // test instruction. We use masm_-> directly here instead of the | 9583 // test instruction. We use masm_-> directly here instead of the |
| 9559 // __ macro because the macro sometimes uses macro expansion to turn | 9584 // __ macro because the macro sometimes uses macro expansion to turn |
| 9560 // into something that can't return a value. This is encountered | 9585 // into something that can't return a value. This is encountered |
| 9561 // when doing generated code coverage tests. | 9586 // when doing generated code coverage tests. |
| 9562 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 9587 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 9563 // Here we use masm_-> instead of the __ macro because this is the | 9588 // Here we use masm_-> instead of the __ macro because this is the |
| 9564 // instruction that gets patched and coverage code gets in the way. | 9589 // instruction that gets patched and coverage code gets in the way. |
| 9565 masm_->test(eax, Immediate(-delta_to_patch_site)); | 9590 masm_->test(eax, Immediate(-delta_to_patch_site)); |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9910 | 9935 |
| 9911 // Make sure that value, key and receiver are in registers. | 9936 // Make sure that value, key and receiver are in registers. |
| 9912 result.ToRegister(); | 9937 result.ToRegister(); |
| 9913 key.ToRegister(); | 9938 key.ToRegister(); |
| 9914 receiver.ToRegister(); | 9939 receiver.ToRegister(); |
| 9915 | 9940 |
| 9916 DeferredReferenceSetKeyedValue* deferred = | 9941 DeferredReferenceSetKeyedValue* deferred = |
| 9917 new DeferredReferenceSetKeyedValue(result.reg(), | 9942 new DeferredReferenceSetKeyedValue(result.reg(), |
| 9918 key.reg(), | 9943 key.reg(), |
| 9919 receiver.reg(), | 9944 receiver.reg(), |
| 9920 tmp.reg()); | 9945 tmp.reg(), |
| 9946 strict_mode_flag()); |
| 9921 | 9947 |
| 9922 // Check that the receiver is not a smi. | 9948 // Check that the receiver is not a smi. |
| 9923 __ test(receiver.reg(), Immediate(kSmiTagMask)); | 9949 __ test(receiver.reg(), Immediate(kSmiTagMask)); |
| 9924 deferred->Branch(zero); | 9950 deferred->Branch(zero); |
| 9925 | 9951 |
| 9926 // Check that the key is a smi. | 9952 // Check that the key is a smi. |
| 9927 if (!key.is_smi()) { | 9953 if (!key.is_smi()) { |
| 9928 __ test(key.reg(), Immediate(kSmiTagMask)); | 9954 __ test(key.reg(), Immediate(kSmiTagMask)); |
| 9929 deferred->Branch(not_zero); | 9955 deferred->Branch(not_zero); |
| 9930 } else { | 9956 } else { |
| 9931 if (FLAG_debug_code) __ AbortIfNotSmi(key.reg()); | 9957 if (FLAG_debug_code) __ AbortIfNotSmi(key.reg()); |
| 9932 } | 9958 } |
| 9933 | 9959 |
| 9934 // Check that the receiver is a JSArray. | 9960 // Check that the receiver is a JSArray. |
| 9935 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, tmp.reg()); | 9961 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, tmp.reg()); |
| 9936 deferred->Branch(not_equal); | 9962 deferred->Branch(not_equal); |
| 9937 | 9963 |
| 9938 // Check that the key is within bounds. Both the key and the length of | |
| 9939 // the JSArray are smis. Use unsigned comparison to handle negative keys. | |
| 9940 __ cmp(key.reg(), | |
| 9941 FieldOperand(receiver.reg(), JSArray::kLengthOffset)); | |
| 9942 deferred->Branch(above_equal); | |
| 9943 | |
| 9944 // Get the elements array from the receiver and check that it is not a | 9964 // Get the elements array from the receiver and check that it is not a |
| 9945 // dictionary. | 9965 // dictionary. |
| 9946 __ mov(tmp.reg(), | 9966 __ mov(tmp.reg(), |
| 9947 FieldOperand(receiver.reg(), JSArray::kElementsOffset)); | 9967 FieldOperand(receiver.reg(), JSArray::kElementsOffset)); |
| 9948 | 9968 |
| 9949 // Check whether it is possible to omit the write barrier. If the elements | 9969 // Check whether it is possible to omit the write barrier. If the elements |
| 9950 // array is in new space or the value written is a smi we can safely update | 9970 // array is in new space or the value written is a smi we can safely update |
| 9951 // the elements array without write barrier. | 9971 // the elements array without write barrier. |
| 9952 Label in_new_space; | 9972 Label in_new_space; |
| 9953 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space); | 9973 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space); |
| 9954 if (!value_is_constant) { | 9974 if (!value_is_constant) { |
| 9955 __ test(result.reg(), Immediate(kSmiTagMask)); | 9975 __ test(result.reg(), Immediate(kSmiTagMask)); |
| 9956 deferred->Branch(not_zero); | 9976 deferred->Branch(not_zero); |
| 9957 } | 9977 } |
| 9958 | 9978 |
| 9959 | 9979 |
| 9960 __ bind(&in_new_space); | 9980 __ bind(&in_new_space); |
| 9961 // Bind the deferred code patch site to be able to locate the fixed | 9981 // Bind the deferred code patch site to be able to locate the fixed |
| 9962 // array map comparison. When debugging, we patch this comparison to | 9982 // array map comparison. When debugging, we patch this comparison to |
| 9963 // always fail so that we will hit the IC call in the deferred code | 9983 // always fail so that we will hit the IC call in the deferred code |
| 9964 // which will allow the debugger to break for fast case stores. | 9984 // which will allow the debugger to break for fast case stores. |
| 9965 __ bind(deferred->patch_site()); | 9985 __ bind(deferred->patch_site()); |
| 9966 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 9986 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
| 9967 Immediate(Factory::fixed_array_map())); | 9987 Immediate(Factory::fixed_array_map())); |
| 9968 deferred->Branch(not_equal); | 9988 deferred->Branch(not_equal); |
| 9969 | 9989 |
| 9990 // Check that the key is within bounds. Both the key and the length of |
| 9991 // the JSArray are smis (because the fixed array check above ensures the |
| 9992 // elements are in fast case). Use unsigned comparison to handle negative |
| 9993 // keys. |
| 9994 __ cmp(key.reg(), |
| 9995 FieldOperand(receiver.reg(), JSArray::kLengthOffset)); |
| 9996 deferred->Branch(above_equal); |
| 9997 |
| 9970 // Store the value. | 9998 // Store the value. |
| 9971 __ mov(FixedArrayElementOperand(tmp.reg(), key.reg()), result.reg()); | 9999 __ mov(FixedArrayElementOperand(tmp.reg(), key.reg()), result.reg()); |
| 9972 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 10000 __ IncrementCounter(&Counters::keyed_store_inline, 1); |
| 9973 | 10001 |
| 9974 deferred->BindExit(); | 10002 deferred->BindExit(); |
| 9975 } else { | 10003 } else { |
| 9976 result = frame()->CallKeyedStoreIC(); | 10004 result = frame()->CallKeyedStoreIC(strict_mode_flag()); |
| 9977 // Make sure that we do not have a test instruction after the | 10005 // Make sure that we do not have a test instruction after the |
| 9978 // call. A test instruction after the call is used to | 10006 // call. A test instruction after the call is used to |
| 9979 // indicate that we have generated an inline version of the | 10007 // indicate that we have generated an inline version of the |
| 9980 // keyed store. | 10008 // keyed store. |
| 9981 __ nop(); | 10009 __ nop(); |
| 9982 } | 10010 } |
| 9983 ASSERT(frame()->height() == original_height - 3); | 10011 ASSERT(frame()->height() == original_height - 3); |
| 9984 return result; | 10012 return result; |
| 9985 } | 10013 } |
| 9986 | 10014 |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10349 memcpy(base, desc.buffer, desc.instr_size); | 10377 memcpy(base, desc.buffer, desc.instr_size); |
| 10350 CPU::FlushICache(base, desc.instr_size); | 10378 CPU::FlushICache(base, desc.instr_size); |
| 10351 return FUNCTION_CAST<MemCopyFunction>(reinterpret_cast<Address>(base)); | 10379 return FUNCTION_CAST<MemCopyFunction>(reinterpret_cast<Address>(base)); |
| 10352 } | 10380 } |
| 10353 | 10381 |
| 10354 #undef __ | 10382 #undef __ |
| 10355 | 10383 |
| 10356 } } // namespace v8::internal | 10384 } } // namespace v8::internal |
| 10357 | 10385 |
| 10358 #endif // V8_TARGET_ARCH_IA32 | 10386 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |