Chromium Code Reviews| 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 1727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1738 ASSERT(!var->is_global()); | 1738 ASSERT(!var->is_global()); |
| 1739 | 1739 |
| 1740 // If we have a function or a constant, we need to initialize the variable. | 1740 // If we have a function or a constant, we need to initialize the variable. |
| 1741 Expression* val = NULL; | 1741 Expression* val = NULL; |
| 1742 if (node->mode() == Variable::CONST) { | 1742 if (node->mode() == Variable::CONST) { |
| 1743 val = new Literal(Factory::the_hole_value()); | 1743 val = new Literal(Factory::the_hole_value()); |
| 1744 } else { | 1744 } else { |
| 1745 val = node->fun(); // NULL if we don't have a function | 1745 val = node->fun(); // NULL if we don't have a function |
| 1746 } | 1746 } |
| 1747 | 1747 |
| 1748 | |
| 1748 if (val != NULL) { | 1749 if (val != NULL) { |
| 1750 WriteBarrierCharacter wb_info = | |
| 1751 val->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI; | |
| 1752 if (val->AsLiteral() != NULL) wb_info = NEVER_NEWSPACE; | |
| 1749 // Set initial value. | 1753 // Set initial value. |
| 1750 Reference target(this, node->proxy()); | 1754 Reference target(this, node->proxy()); |
| 1751 Load(val); | 1755 Load(val); |
| 1752 target.SetValue(NOT_CONST_INIT); | 1756 target.SetValue(NOT_CONST_INIT, wb_info); |
| 1753 | 1757 |
| 1754 // Get rid of the assigned value (declarations are statements). | 1758 // Get rid of the assigned value (declarations are statements). |
| 1755 frame_->Drop(); | 1759 frame_->Drop(); |
| 1756 } | 1760 } |
| 1757 ASSERT(frame_->height() == original_height); | 1761 ASSERT(frame_->height() == original_height); |
| 1758 } | 1762 } |
| 1759 | 1763 |
| 1760 | 1764 |
| 1761 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1765 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1762 #ifdef DEBUG | 1766 #ifdef DEBUG |
| (...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2478 | 2482 |
| 2479 end_del_check.Bind(); | 2483 end_del_check.Bind(); |
| 2480 // Store the entry in the 'each' expression and take another spin in the | 2484 // Store the entry in the 'each' expression and take another spin in the |
| 2481 // loop. r3: i'th entry of the enum cache (or string there of) | 2485 // loop. r3: i'th entry of the enum cache (or string there of) |
| 2482 frame_->EmitPush(r3); // push entry | 2486 frame_->EmitPush(r3); // push entry |
| 2483 { Reference each(this, node->each()); | 2487 { Reference each(this, node->each()); |
| 2484 if (!each.is_illegal()) { | 2488 if (!each.is_illegal()) { |
| 2485 if (each.size() > 0) { | 2489 if (each.size() > 0) { |
| 2486 __ ldr(r0, frame_->ElementAt(each.size())); | 2490 __ ldr(r0, frame_->ElementAt(each.size())); |
| 2487 frame_->EmitPush(r0); | 2491 frame_->EmitPush(r0); |
| 2488 each.SetValue(NOT_CONST_INIT); | 2492 each.SetValue(NOT_CONST_INIT, UNLIKELY_SMI); |
| 2489 frame_->Drop(2); | 2493 frame_->Drop(2); |
| 2490 } else { | 2494 } else { |
| 2491 // If the reference was to a slot we rely on the convenient property | 2495 // If the reference was to a slot we rely on the convenient property |
| 2492 // that it doesn't matter whether a value (eg, r3 pushed above) is | 2496 // that it doesn't matter whether a value (eg, r3 pushed above) is |
| 2493 // right on top of or right underneath a zero-sized reference. | 2497 // right on top of or right underneath a zero-sized reference. |
| 2494 each.SetValue(NOT_CONST_INIT); | 2498 each.SetValue(NOT_CONST_INIT, UNLIKELY_SMI); |
| 2495 frame_->Drop(); | 2499 frame_->Drop(); |
| 2496 } | 2500 } |
| 2497 } | 2501 } |
| 2498 } | 2502 } |
| 2499 // Body. | 2503 // Body. |
| 2500 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2504 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2501 Visit(node->body()); | 2505 Visit(node->body()); |
| 2502 | 2506 |
| 2503 // Next. Reestablish a spilled frame in case we are coming here via | 2507 // Next. Reestablish a spilled frame in case we are coming here via |
| 2504 // a continue in the body. | 2508 // a continue in the body. |
| (...skipping 1134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3639 #ifdef DEBUG | 3643 #ifdef DEBUG |
| 3640 int original_height = frame_->height(); | 3644 int original_height = frame_->height(); |
| 3641 #endif | 3645 #endif |
| 3642 Comment cmnt(masm_, "[ Keyed Property Assignment"); | 3646 Comment cmnt(masm_, "[ Keyed Property Assignment"); |
| 3643 Property* prop = node->target()->AsProperty(); | 3647 Property* prop = node->target()->AsProperty(); |
| 3644 ASSERT_NOT_NULL(prop); | 3648 ASSERT_NOT_NULL(prop); |
| 3645 | 3649 |
| 3646 // Evaluate the receiver subexpression. | 3650 // Evaluate the receiver subexpression. |
| 3647 Load(prop->obj()); | 3651 Load(prop->obj()); |
| 3648 | 3652 |
| 3653 WriteBarrierCharacter wb_info; | |
| 3654 | |
| 3649 // Change to slow case in the beginning of an initialization block to | 3655 // Change to slow case in the beginning of an initialization block to |
| 3650 // avoid the quadratic behavior of repeatedly adding fast properties. | 3656 // avoid the quadratic behavior of repeatedly adding fast properties. |
| 3651 if (node->starts_initialization_block()) { | 3657 if (node->starts_initialization_block()) { |
| 3652 frame_->Dup(); | 3658 frame_->Dup(); |
| 3653 frame_->CallRuntime(Runtime::kToSlowProperties, 1); | 3659 frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
| 3654 } | 3660 } |
| 3655 | 3661 |
| 3656 // Change to fast case at the end of an initialization block. To prepare for | 3662 // Change to fast case at the end of an initialization block. To prepare for |
| 3657 // that add an extra copy of the receiver to the frame, so that it can be | 3663 // that add an extra copy of the receiver to the frame, so that it can be |
| 3658 // converted back to fast case after the assignment. | 3664 // converted back to fast case after the assignment. |
| 3659 if (node->ends_initialization_block()) { | 3665 if (node->ends_initialization_block()) { |
| 3660 frame_->Dup(); | 3666 frame_->Dup(); |
| 3661 } | 3667 } |
| 3662 | 3668 |
| 3663 // Evaluate the key subexpression. | 3669 // Evaluate the key subexpression. |
| 3664 Load(prop->key()); | 3670 Load(prop->key()); |
| 3665 | 3671 |
| 3666 // Stack layout: | 3672 // Stack layout: |
| 3667 // [tos] : key | 3673 // [tos] : key |
| 3668 // [tos+1] : receiver | 3674 // [tos+1] : receiver |
| 3669 // [tos+2] : receiver if at the end of an initialization block | 3675 // [tos+2] : receiver if at the end of an initialization block |
| 3670 | 3676 // |
| 3671 // Evaluate the right-hand side. | 3677 // Evaluate the right-hand side. |
| 3672 if (node->is_compound()) { | 3678 if (node->is_compound()) { |
| 3673 // For a compound assignment the right-hand side is a binary operation | 3679 // For a compound assignment the right-hand side is a binary operation |
| 3674 // between the current property value and the actual right-hand side. | 3680 // between the current property value and the actual right-hand side. |
| 3675 // Duplicate receiver and key for loading the current property value. | 3681 // Duplicate receiver and key for loading the current property value. |
| 3676 frame_->Dup2(); | 3682 frame_->Dup2(); |
| 3677 EmitKeyedLoad(); | 3683 EmitKeyedLoad(); |
| 3678 frame_->EmitPush(r0); | 3684 frame_->EmitPush(r0); |
| 3679 | 3685 |
| 3680 // Perform the binary operation. | 3686 // Perform the binary operation. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 3692 loop_nesting() > 0 ? GENERATE_INLINE_SMI : DONT_GENERATE_INLINE_SMI; | 3698 loop_nesting() > 0 ? GENERATE_INLINE_SMI : DONT_GENERATE_INLINE_SMI; |
| 3693 if (literal != NULL) { | 3699 if (literal != NULL) { |
| 3694 ASSERT(!literal->handle()->IsSmi()); | 3700 ASSERT(!literal->handle()->IsSmi()); |
| 3695 inline_smi = DONT_GENERATE_INLINE_SMI; | 3701 inline_smi = DONT_GENERATE_INLINE_SMI; |
| 3696 } | 3702 } |
| 3697 Load(node->value()); | 3703 Load(node->value()); |
| 3698 GenericBinaryOperation(node->binary_op(), | 3704 GenericBinaryOperation(node->binary_op(), |
| 3699 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, | 3705 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
| 3700 inline_smi); | 3706 inline_smi); |
| 3701 } | 3707 } |
| 3708 wb_info = node->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI; | |
| 3702 } else { | 3709 } else { |
| 3703 // For non-compound assignment just load the right-hand side. | 3710 // For non-compound assignment just load the right-hand side. |
| 3704 Load(node->value()); | 3711 Load(node->value()); |
| 3712 wb_info = node->value()->AsLiteral() != NULL ? | |
| 3713 NEVER_NEWSPACE : | |
| 3714 (node->value()->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI); | |
| 3705 } | 3715 } |
| 3706 | 3716 |
| 3707 // Stack layout: | 3717 // Stack layout: |
| 3708 // [tos] : value | 3718 // [tos] : value |
| 3709 // [tos+1] : key | 3719 // [tos+1] : key |
| 3710 // [tos+2] : receiver | 3720 // [tos+2] : receiver |
| 3711 // [tos+3] : receiver if at the end of an initialization block | 3721 // [tos+3] : receiver if at the end of an initialization block |
| 3712 | 3722 |
| 3713 // Perform the assignment. It is safe to ignore constants here. | 3723 // Perform the assignment. It is safe to ignore constants here. |
| 3714 ASSERT(node->op() != Token::INIT_CONST); | 3724 ASSERT(node->op() != Token::INIT_CONST); |
| 3715 CodeForSourcePosition(node->position()); | 3725 CodeForSourcePosition(node->position()); |
| 3716 EmitKeyedStore(prop->key()->type()); | 3726 EmitKeyedStore(prop->key()->type(), wb_info); |
| 3717 frame_->EmitPush(r0); | 3727 frame_->EmitPush(r0); |
| 3718 | 3728 |
| 3719 // Stack layout: | 3729 // Stack layout: |
| 3720 // [tos] : result | 3730 // [tos] : result |
| 3721 // [tos+1] : receiver if at the end of an initialization block | 3731 // [tos+1] : receiver if at the end of an initialization block |
| 3722 | 3732 |
| 3723 // Change to fast case at the end of an initialization block. | 3733 // Change to fast case at the end of an initialization block. |
| 3724 if (node->ends_initialization_block()) { | 3734 if (node->ends_initialization_block()) { |
| 3725 // The argument to the runtime call is the extra copy of the receiver, | 3735 // The argument to the runtime call is the extra copy of the receiver, |
| 3726 // which is below the value of the assignment. Swap the receiver and | 3736 // which is below the value of the assignment. Swap the receiver and |
| (...skipping 1775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5502 ASSERT(!target.is_illegal()); | 5512 ASSERT(!target.is_illegal()); |
| 5503 target.GetValue(); // Pushes the value. | 5513 target.GetValue(); // Pushes the value. |
| 5504 Register value = frame_->PopToRegister(); | 5514 Register value = frame_->PopToRegister(); |
| 5505 if (is_postfix) frame_->EmitPush(value); | 5515 if (is_postfix) frame_->EmitPush(value); |
| 5506 if (is_increment) { | 5516 if (is_increment) { |
| 5507 __ add(value, value, Operand(Smi::FromInt(1))); | 5517 __ add(value, value, Operand(Smi::FromInt(1))); |
| 5508 } else { | 5518 } else { |
| 5509 __ sub(value, value, Operand(Smi::FromInt(1))); | 5519 __ sub(value, value, Operand(Smi::FromInt(1))); |
| 5510 } | 5520 } |
| 5511 frame_->EmitPush(value); | 5521 frame_->EmitPush(value); |
| 5512 target.SetValue(NOT_CONST_INIT); | 5522 target.SetValue(NOT_CONST_INIT, LIKELY_SMI); |
| 5513 if (is_postfix) frame_->Pop(); | 5523 if (is_postfix) frame_->Pop(); |
| 5514 ASSERT_EQ(original_height + 1, frame_->height()); | 5524 ASSERT_EQ(original_height + 1, frame_->height()); |
| 5515 return; | 5525 return; |
| 5516 } | 5526 } |
| 5517 | 5527 |
| 5518 // If it's a postfix expression and its result is not ignored and the | 5528 // If it's a postfix expression and its result is not ignored and the |
| 5519 // reference is non-trivial, then push a placeholder on the stack now | 5529 // reference is non-trivial, then push a placeholder on the stack now |
| 5520 // to hold the result of the expression. | 5530 // to hold the result of the expression. |
| 5521 bool placeholder_pushed = false; | 5531 bool placeholder_pushed = false; |
| 5522 if (!is_slot && is_postfix) { | 5532 if (!is_slot && is_postfix) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5601 } | 5611 } |
| 5602 | 5612 |
| 5603 __ Move(value, r0); | 5613 __ Move(value, r0); |
| 5604 // Store the new value in the target if not const. | 5614 // Store the new value in the target if not const. |
| 5605 // At this point the answer is in the value register. | 5615 // At this point the answer is in the value register. |
| 5606 exit.Bind(); | 5616 exit.Bind(); |
| 5607 frame_->EmitPush(value); | 5617 frame_->EmitPush(value); |
| 5608 // Set the target with the result, leaving the result on | 5618 // Set the target with the result, leaving the result on |
| 5609 // top of the stack. Removes the target from the stack if | 5619 // top of the stack. Removes the target from the stack if |
| 5610 // it has a non-zero size. | 5620 // it has a non-zero size. |
| 5611 if (!is_const) target.SetValue(NOT_CONST_INIT); | 5621 if (!is_const) target.SetValue(NOT_CONST_INIT, LIKELY_SMI); |
| 5612 } | 5622 } |
| 5613 | 5623 |
| 5614 // Postfix: Discard the new value and use the old. | 5624 // Postfix: Discard the new value and use the old. |
| 5615 if (is_postfix) frame_->Pop(); | 5625 if (is_postfix) frame_->Pop(); |
| 5616 ASSERT_EQ(original_height + 1, frame_->height()); | 5626 ASSERT_EQ(original_height + 1, frame_->height()); |
| 5617 } | 5627 } |
| 5618 | 5628 |
| 5619 | 5629 |
| 5620 void CodeGenerator::GenerateLogicalBooleanOperation(BinaryOperation* node) { | 5630 void CodeGenerator::GenerateLogicalBooleanOperation(BinaryOperation* node) { |
| 5621 // According to ECMA-262 section 11.11, page 58, the binary logical | 5631 // According to ECMA-262 section 11.11, page 58, the binary logical |
| (...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6334 // Make sure that the expected number of instructions are generated. | 6344 // Make sure that the expected number of instructions are generated. |
| 6335 ASSERT_EQ(GetInlinedKeyedLoadInstructionsAfterPatch(), | 6345 ASSERT_EQ(GetInlinedKeyedLoadInstructionsAfterPatch(), |
| 6336 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); | 6346 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); |
| 6337 } | 6347 } |
| 6338 | 6348 |
| 6339 deferred->BindExit(); | 6349 deferred->BindExit(); |
| 6340 } | 6350 } |
| 6341 } | 6351 } |
| 6342 | 6352 |
| 6343 | 6353 |
| 6344 void CodeGenerator::EmitKeyedStore(StaticType* key_type) { | 6354 void CodeGenerator::EmitKeyedStore(StaticType* key_type, |
| 6355 WriteBarrierCharacter wb_info) { | |
| 6345 // Generate inlined version of the keyed store if the code is in a loop | 6356 // Generate inlined version of the keyed store if the code is in a loop |
| 6346 // and the key is likely to be a smi. | 6357 // and the key is likely to be a smi. |
| 6347 if (loop_nesting() > 0 && key_type->IsLikelySmi()) { | 6358 if (loop_nesting() > 0 && key_type->IsLikelySmi()) { |
| 6348 // Inline the keyed store. | 6359 // Inline the keyed store. |
| 6349 Comment cmnt(masm_, "[ Inlined store to keyed property"); | 6360 Comment cmnt(masm_, "[ Inlined store to keyed property"); |
| 6350 | 6361 |
| 6351 Register scratch1 = VirtualFrame::scratch0(); | 6362 Register scratch1 = VirtualFrame::scratch0(); |
| 6352 Register scratch2 = VirtualFrame::scratch1(); | 6363 Register scratch2 = VirtualFrame::scratch1(); |
| 6353 Register scratch3 = r3; | 6364 Register scratch3 = r3; |
| 6354 | 6365 |
| 6355 // Counter will be decremented in the deferred code. Placed here to avoid | 6366 // Counter will be decremented in the deferred code. Placed here to avoid |
| 6356 // having it in the instruction stream below where patching will occur. | 6367 // having it in the instruction stream below where patching will occur. |
| 6357 __ IncrementCounter(&Counters::keyed_store_inline, 1, | 6368 __ IncrementCounter(&Counters::keyed_store_inline, 1, |
| 6358 scratch1, scratch2); | 6369 scratch1, scratch2); |
| 6359 | 6370 |
| 6371 | |
| 6372 | |
| 6360 // Load the value, key and receiver from the stack. | 6373 // Load the value, key and receiver from the stack. |
| 6374 bool value_is_harmless = frame_->KnownSmiAt(0); | |
| 6375 if (wb_info == NEVER_NEWSPACE) value_is_harmless = true; | |
| 6376 bool key_is_smi = frame_->KnownSmiAt(1); | |
| 6361 Register value = frame_->PopToRegister(); | 6377 Register value = frame_->PopToRegister(); |
| 6362 Register key = frame_->PopToRegister(value); | 6378 Register key = frame_->PopToRegister(value); |
| 6363 VirtualFrame::SpilledScope spilled(frame_); | 6379 VirtualFrame::SpilledScope spilled(frame_); |
| 6364 Register receiver = r2; | 6380 Register receiver = r2; |
| 6365 frame_->EmitPop(receiver); | 6381 frame_->EmitPop(receiver); |
| 6366 | 6382 |
| 6383 #ifdef DEBUG | |
| 6384 bool we_remembered_the_write_barrier = value_is_harmless; | |
| 6385 #endif | |
| 6386 | |
| 6367 // The deferred code expects value, key and receiver in registers. | 6387 // The deferred code expects value, key and receiver in registers. |
| 6368 DeferredReferenceSetKeyedValue* deferred = | 6388 DeferredReferenceSetKeyedValue* deferred = |
| 6369 new DeferredReferenceSetKeyedValue(value, key, receiver); | 6389 new DeferredReferenceSetKeyedValue(value, key, receiver); |
| 6370 | 6390 |
| 6371 // Check that the value is a smi. As this inlined code does not set the | 6391 // Check that the value is a smi. As this inlined code does not set the |
| 6372 // write barrier it is only possible to store smi values. | 6392 // write barrier it is only possible to store smi values. |
| 6373 __ tst(value, Operand(kSmiTagMask)); | 6393 if (!value_is_harmless) { |
| 6374 deferred->Branch(ne); | 6394 // If the value is not likely to be a Smi then lets test the fixed array |
|
William Hesse
2010/07/01 15:00:59
let's
| |
| 6395 // for new space instead. See below. | |
| 6396 if (wb_info == LIKELY_SMI) { | |
| 6397 __ tst(value, Operand(kSmiTagMask)); | |
| 6398 deferred->Branch(ne); | |
| 6399 #ifdef DEBUG | |
| 6400 we_remembered_the_write_barrier = true; | |
| 6401 #endif | |
| 6402 } | |
| 6403 } | |
| 6375 | 6404 |
| 6376 // Check that the key is a smi. | 6405 if (!key_is_smi) { |
| 6377 __ tst(key, Operand(kSmiTagMask)); | 6406 // Check that the key is a smi. |
| 6378 deferred->Branch(ne); | 6407 __ tst(key, Operand(kSmiTagMask)); |
| 6408 deferred->Branch(ne); | |
| 6409 } | |
| 6379 | 6410 |
| 6380 // Check that the receiver is a heap object. | 6411 // Check that the receiver is a heap object. |
| 6381 __ tst(receiver, Operand(kSmiTagMask)); | 6412 __ tst(receiver, Operand(kSmiTagMask)); |
| 6382 deferred->Branch(eq); | 6413 deferred->Branch(eq); |
| 6383 | 6414 |
| 6384 // Check that the receiver is a JSArray. | 6415 // Check that the receiver is a JSArray. |
| 6385 __ CompareObjectType(receiver, scratch1, scratch1, JS_ARRAY_TYPE); | 6416 __ CompareObjectType(receiver, scratch1, scratch1, JS_ARRAY_TYPE); |
| 6386 deferred->Branch(ne); | 6417 deferred->Branch(ne); |
| 6387 | 6418 |
| 6388 // Check that the key is within bounds. Both the key and the length of | 6419 // Check that the key is within bounds. Both the key and the length of |
| 6389 // the JSArray are smis. Use unsigned comparison to handle negative keys. | 6420 // the JSArray are smis. Use unsigned comparison to handle negative keys. |
| 6390 __ ldr(scratch1, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 6421 __ ldr(scratch1, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 6391 __ cmp(scratch1, key); | 6422 __ cmp(scratch1, key); |
| 6392 deferred->Branch(ls); // Unsigned less equal. | 6423 deferred->Branch(ls); // Unsigned less equal. |
| 6393 | 6424 |
| 6425 // Get the elements array from the receiver and check that it | |
| 6426 // is not a dictionary. | |
|
William Hesse
2010/07/01 15:00:59
The check that it is a dictionary is pretty far aw
| |
| 6427 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 6428 if (!value_is_harmless && wb_info != LIKELY_SMI) { | |
| 6429 Label ok; | |
| 6430 __ and_(scratch2, scratch1, Operand(ExternalReference::new_space_mask())); | |
| 6431 __ cmp(scratch2, Operand(ExternalReference::new_space_start())); | |
| 6432 __ tst(value, Operand(kSmiTagMask), ne); | |
| 6433 deferred->Branch(ne); | |
| 6434 #ifdef DEBUG | |
| 6435 we_remembered_the_write_barrier = true; | |
| 6436 #endif | |
| 6437 } | |
| 6438 __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); | |
| 6394 // The following instructions are the part of the inlined store keyed | 6439 // The following instructions are the part of the inlined store keyed |
| 6395 // property code which can be patched. Therefore the exact number of | 6440 // property code which can be patched. Therefore the exact number of |
| 6396 // instructions generated need to be fixed, so the constant pool is blocked | 6441 // instructions generated need to be fixed, so the constant pool is blocked |
| 6397 // while generating this code. | 6442 // while generating this code. |
| 6398 { Assembler::BlockConstPoolScope block_const_pool(masm_); | 6443 { Assembler::BlockConstPoolScope block_const_pool(masm_); |
| 6399 // Get the elements array from the receiver and check that it | 6444 #ifdef DEBUG |
| 6400 // is not a dictionary. | 6445 Label check_inlined_codesize; |
| 6401 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 6446 masm_->bind(&check_inlined_codesize); |
| 6402 __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); | 6447 #endif |
| 6448 | |
| 6403 // Read the fixed array map from the constant pool (not from the root | 6449 // Read the fixed array map from the constant pool (not from the root |
| 6404 // array) so that the value can be patched. When debugging, we patch this | 6450 // array) so that the value can be patched. When debugging, we patch this |
| 6405 // comparison to always fail so that we will hit the IC call in the | 6451 // comparison to always fail so that we will hit the IC call in the |
| 6406 // deferred code which will allow the debugger to break for fast case | 6452 // deferred code which will allow the debugger to break for fast case |
| 6407 // stores. | 6453 // stores. |
| 6408 #ifdef DEBUG | |
| 6409 Label check_inlined_codesize; | |
| 6410 masm_->bind(&check_inlined_codesize); | |
| 6411 #endif | |
| 6412 __ mov(scratch3, Operand(Factory::fixed_array_map())); | 6454 __ mov(scratch3, Operand(Factory::fixed_array_map())); |
| 6413 __ cmp(scratch2, scratch3); | 6455 __ cmp(scratch2, scratch3); |
| 6414 deferred->Branch(ne); | 6456 deferred->Branch(ne); |
| 6415 | 6457 |
| 6416 // Store the value. | 6458 // Store the value. |
| 6417 __ add(scratch1, scratch1, | 6459 __ add(scratch1, scratch1, |
| 6418 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 6460 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 6419 __ str(value, | 6461 __ str(value, |
| 6420 MemOperand(scratch1, key, LSL, | 6462 MemOperand(scratch1, key, LSL, |
| 6421 kPointerSizeLog2 - (kSmiTagSize + kSmiShiftSize))); | 6463 kPointerSizeLog2 - (kSmiTagSize + kSmiShiftSize))); |
| 6422 | 6464 |
| 6423 // Make sure that the expected number of instructions are generated. | 6465 // Make sure that the expected number of instructions are generated. |
| 6424 ASSERT_EQ(kInlinedKeyedStoreInstructionsAfterPatch, | 6466 ASSERT_EQ(kInlinedKeyedStoreInstructionsAfterPatch, |
| 6425 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); | 6467 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); |
| 6426 } | 6468 } |
| 6427 | 6469 |
| 6470 ASSERT(we_remembered_the_write_barrier); | |
| 6471 | |
| 6428 deferred->BindExit(); | 6472 deferred->BindExit(); |
| 6429 } else { | 6473 } else { |
| 6430 frame()->CallKeyedStoreIC(); | 6474 frame()->CallKeyedStoreIC(); |
| 6431 } | 6475 } |
| 6432 } | 6476 } |
| 6433 | 6477 |
| 6434 | 6478 |
| 6435 #ifdef DEBUG | 6479 #ifdef DEBUG |
| 6436 bool CodeGenerator::HasValidEntryRegisters() { return true; } | 6480 bool CodeGenerator::HasValidEntryRegisters() { return true; } |
| 6437 #endif | 6481 #endif |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6515 cgen_->frame()->EmitPush(r0); | 6559 cgen_->frame()->EmitPush(r0); |
| 6516 break; | 6560 break; |
| 6517 } | 6561 } |
| 6518 | 6562 |
| 6519 default: | 6563 default: |
| 6520 UNREACHABLE(); | 6564 UNREACHABLE(); |
| 6521 } | 6565 } |
| 6522 } | 6566 } |
| 6523 | 6567 |
| 6524 | 6568 |
| 6525 void Reference::SetValue(InitState init_state) { | 6569 void Reference::SetValue(InitState init_state, WriteBarrierCharacter wb_info) { |
| 6526 ASSERT(!is_illegal()); | 6570 ASSERT(!is_illegal()); |
| 6527 ASSERT(!cgen_->has_cc()); | 6571 ASSERT(!cgen_->has_cc()); |
| 6528 MacroAssembler* masm = cgen_->masm(); | 6572 MacroAssembler* masm = cgen_->masm(); |
| 6529 VirtualFrame* frame = cgen_->frame(); | 6573 VirtualFrame* frame = cgen_->frame(); |
| 6530 Property* property = expression_->AsProperty(); | 6574 Property* property = expression_->AsProperty(); |
| 6531 if (property != NULL) { | 6575 if (property != NULL) { |
| 6532 cgen_->CodeForSourcePosition(property->position()); | 6576 cgen_->CodeForSourcePosition(property->position()); |
| 6533 } | 6577 } |
| 6534 | 6578 |
| 6535 switch (type_) { | 6579 switch (type_) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 6547 frame->EmitPush(r0); | 6591 frame->EmitPush(r0); |
| 6548 set_unloaded(); | 6592 set_unloaded(); |
| 6549 break; | 6593 break; |
| 6550 } | 6594 } |
| 6551 | 6595 |
| 6552 case KEYED: { | 6596 case KEYED: { |
| 6553 Comment cmnt(masm, "[ Store to keyed Property"); | 6597 Comment cmnt(masm, "[ Store to keyed Property"); |
| 6554 Property* property = expression_->AsProperty(); | 6598 Property* property = expression_->AsProperty(); |
| 6555 ASSERT(property != NULL); | 6599 ASSERT(property != NULL); |
| 6556 cgen_->CodeForSourcePosition(property->position()); | 6600 cgen_->CodeForSourcePosition(property->position()); |
| 6557 cgen_->EmitKeyedStore(property->key()->type()); | 6601 cgen_->EmitKeyedStore(property->key()->type(), wb_info); |
| 6558 frame->EmitPush(r0); | 6602 frame->EmitPush(r0); |
| 6559 set_unloaded(); | 6603 set_unloaded(); |
| 6560 break; | 6604 break; |
| 6561 } | 6605 } |
| 6562 | 6606 |
| 6563 default: | 6607 default: |
| 6564 UNREACHABLE(); | 6608 UNREACHABLE(); |
| 6565 } | 6609 } |
| 6566 } | 6610 } |
| 6567 | 6611 |
| (...skipping 4554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 11122 __ bind(&string_add_runtime); | 11166 __ bind(&string_add_runtime); |
| 11123 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 11167 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 11124 } | 11168 } |
| 11125 | 11169 |
| 11126 | 11170 |
| 11127 #undef __ | 11171 #undef __ |
| 11128 | 11172 |
| 11129 } } // namespace v8::internal | 11173 } } // namespace v8::internal |
| 11130 | 11174 |
| 11131 #endif // V8_TARGET_ARCH_ARM | 11175 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |