Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 4996) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -1745,11 +1745,15 @@ |
val = node->fun(); // NULL if we don't have a function |
} |
+ |
if (val != NULL) { |
+ WriteBarrierCharacter wb_info = |
+ val->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI; |
+ if (val->AsLiteral() != NULL) wb_info = NEVER_NEWSPACE; |
// Set initial value. |
Reference target(this, node->proxy()); |
Load(val); |
- target.SetValue(NOT_CONST_INIT); |
+ target.SetValue(NOT_CONST_INIT, wb_info); |
// Get rid of the assigned value (declarations are statements). |
frame_->Drop(); |
@@ -2485,13 +2489,13 @@ |
if (each.size() > 0) { |
__ ldr(r0, frame_->ElementAt(each.size())); |
frame_->EmitPush(r0); |
- each.SetValue(NOT_CONST_INIT); |
+ each.SetValue(NOT_CONST_INIT, UNLIKELY_SMI); |
frame_->Drop(2); |
} else { |
// If the reference was to a slot we rely on the convenient property |
// that it doesn't matter whether a value (eg, r3 pushed above) is |
// right on top of or right underneath a zero-sized reference. |
- each.SetValue(NOT_CONST_INIT); |
+ each.SetValue(NOT_CONST_INIT, UNLIKELY_SMI); |
frame_->Drop(); |
} |
} |
@@ -3646,6 +3650,8 @@ |
// Evaluate the receiver subexpression. |
Load(prop->obj()); |
+ WriteBarrierCharacter wb_info; |
+ |
// Change to slow case in the beginning of an initialization block to |
// avoid the quadratic behavior of repeatedly adding fast properties. |
if (node->starts_initialization_block()) { |
@@ -3667,7 +3673,7 @@ |
// [tos] : key |
// [tos+1] : receiver |
// [tos+2] : receiver if at the end of an initialization block |
- |
+ // |
// Evaluate the right-hand side. |
if (node->is_compound()) { |
// For a compound assignment the right-hand side is a binary operation |
@@ -3699,9 +3705,13 @@ |
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
inline_smi); |
} |
+ wb_info = node->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI; |
} else { |
// For non-compound assignment just load the right-hand side. |
Load(node->value()); |
+ wb_info = node->value()->AsLiteral() != NULL ? |
+ NEVER_NEWSPACE : |
+ (node->value()->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI); |
} |
// Stack layout: |
@@ -3713,7 +3723,7 @@ |
// Perform the assignment. It is safe to ignore constants here. |
ASSERT(node->op() != Token::INIT_CONST); |
CodeForSourcePosition(node->position()); |
- EmitKeyedStore(prop->key()->type()); |
+ EmitKeyedStore(prop->key()->type(), wb_info); |
frame_->EmitPush(r0); |
// Stack layout: |
@@ -5509,7 +5519,7 @@ |
__ sub(value, value, Operand(Smi::FromInt(1))); |
} |
frame_->EmitPush(value); |
- target.SetValue(NOT_CONST_INIT); |
+ target.SetValue(NOT_CONST_INIT, LIKELY_SMI); |
if (is_postfix) frame_->Pop(); |
ASSERT_EQ(original_height + 1, frame_->height()); |
return; |
@@ -5608,7 +5618,7 @@ |
// Set the target with the result, leaving the result on |
// top of the stack. Removes the target from the stack if |
// it has a non-zero size. |
- if (!is_const) target.SetValue(NOT_CONST_INIT); |
+ if (!is_const) target.SetValue(NOT_CONST_INIT, LIKELY_SMI); |
} |
// Postfix: Discard the new value and use the old. |
@@ -6341,7 +6351,8 @@ |
} |
-void CodeGenerator::EmitKeyedStore(StaticType* key_type) { |
+void CodeGenerator::EmitKeyedStore(StaticType* key_type, |
+ WriteBarrierCharacter wb_info) { |
// Generate inlined version of the keyed store if the code is in a loop |
// and the key is likely to be a smi. |
if (loop_nesting() > 0 && key_type->IsLikelySmi()) { |
@@ -6357,25 +6368,45 @@ |
__ IncrementCounter(&Counters::keyed_store_inline, 1, |
scratch1, scratch2); |
+ |
+ |
// Load the value, key and receiver from the stack. |
+ bool value_is_harmless = frame_->KnownSmiAt(0); |
+ if (wb_info == NEVER_NEWSPACE) value_is_harmless = true; |
+ bool key_is_smi = frame_->KnownSmiAt(1); |
Register value = frame_->PopToRegister(); |
Register key = frame_->PopToRegister(value); |
VirtualFrame::SpilledScope spilled(frame_); |
Register receiver = r2; |
frame_->EmitPop(receiver); |
+#ifdef DEBUG |
+ bool we_remembered_the_write_barrier = value_is_harmless; |
+#endif |
+ |
// The deferred code expects value, key and receiver in registers. |
DeferredReferenceSetKeyedValue* deferred = |
new DeferredReferenceSetKeyedValue(value, key, receiver); |
// Check that the value is a smi. As this inlined code does not set the |
// write barrier it is only possible to store smi values. |
- __ tst(value, Operand(kSmiTagMask)); |
- deferred->Branch(ne); |
+ if (!value_is_harmless) { |
+ // 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
|
+ // for new space instead. See below. |
+ if (wb_info == LIKELY_SMI) { |
+ __ tst(value, Operand(kSmiTagMask)); |
+ deferred->Branch(ne); |
+#ifdef DEBUG |
+ we_remembered_the_write_barrier = true; |
+#endif |
+ } |
+ } |
- // Check that the key is a smi. |
- __ tst(key, Operand(kSmiTagMask)); |
- deferred->Branch(ne); |
+ if (!key_is_smi) { |
+ // Check that the key is a smi. |
+ __ tst(key, Operand(kSmiTagMask)); |
+ deferred->Branch(ne); |
+ } |
// Check that the receiver is a heap object. |
__ tst(receiver, Operand(kSmiTagMask)); |
@@ -6391,24 +6422,35 @@ |
__ cmp(scratch1, key); |
deferred->Branch(ls); // Unsigned less equal. |
+ // Get the elements array from the receiver and check that it |
+ // is not a dictionary. |
William Hesse
2010/07/01 15:00:59
The check that it is a dictionary is pretty far aw
|
+ __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
+ if (!value_is_harmless && wb_info != LIKELY_SMI) { |
+ Label ok; |
+ __ and_(scratch2, scratch1, Operand(ExternalReference::new_space_mask())); |
+ __ cmp(scratch2, Operand(ExternalReference::new_space_start())); |
+ __ tst(value, Operand(kSmiTagMask), ne); |
+ deferred->Branch(ne); |
+#ifdef DEBUG |
+ we_remembered_the_write_barrier = true; |
+#endif |
+ } |
+ __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); |
// The following instructions are the part of the inlined store keyed |
// property code which can be patched. Therefore the exact number of |
// instructions generated need to be fixed, so the constant pool is blocked |
// while generating this code. |
{ Assembler::BlockConstPoolScope block_const_pool(masm_); |
- // Get the elements array from the receiver and check that it |
- // is not a dictionary. |
- __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
- __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); |
+#ifdef DEBUG |
+ Label check_inlined_codesize; |
+ masm_->bind(&check_inlined_codesize); |
+#endif |
+ |
// Read the fixed array map from the constant pool (not from the root |
// array) so that the value can be patched. When debugging, we patch this |
// comparison to always fail so that we will hit the IC call in the |
// deferred code which will allow the debugger to break for fast case |
// stores. |
-#ifdef DEBUG |
- Label check_inlined_codesize; |
- masm_->bind(&check_inlined_codesize); |
-#endif |
__ mov(scratch3, Operand(Factory::fixed_array_map())); |
__ cmp(scratch2, scratch3); |
deferred->Branch(ne); |
@@ -6425,6 +6467,8 @@ |
masm_->InstructionsGeneratedSince(&check_inlined_codesize)); |
} |
+ ASSERT(we_remembered_the_write_barrier); |
+ |
deferred->BindExit(); |
} else { |
frame()->CallKeyedStoreIC(); |
@@ -6522,7 +6566,7 @@ |
} |
-void Reference::SetValue(InitState init_state) { |
+void Reference::SetValue(InitState init_state, WriteBarrierCharacter wb_info) { |
ASSERT(!is_illegal()); |
ASSERT(!cgen_->has_cc()); |
MacroAssembler* masm = cgen_->masm(); |
@@ -6554,7 +6598,7 @@ |
Property* property = expression_->AsProperty(); |
ASSERT(property != NULL); |
cgen_->CodeForSourcePosition(property->position()); |
- cgen_->EmitKeyedStore(property->key()->type()); |
+ cgen_->EmitKeyedStore(property->key()->type(), wb_info); |
frame->EmitPush(r0); |
set_unloaded(); |
break; |