Revision: 4999
Author: [email protected]
Date: Thu Jul 1 08:06:24 2010
Log: ARM: Don't emit a write barrier for an inlined keyed load
if the right hand side is a literal like true, false, etc.
Also if the value is not a likely Smi we inline the newspace
check.
Review URL: http://codereview.chromium.org/2833048
http://code.google.com/p/v8/source/detail?r=4999
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.h
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Wed Jun 30 08:19:06 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Jul 1 08:06:24 2010
@@ -1744,12 +1744,16 @@
} else {
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);
-
- // Check that the key is a smi.
- __ tst(key, Operand(kSmiTagMask));
- deferred->Branch(ne);
+ if (!value_is_harmless) {
+ // If the value is not likely to be a Smi then let's test the fixed
array
+ // 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
+ }
+ }
+
+ 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.
+ __ 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
+ }
+ // Check that the elements array is not a dictionary.
+ __ 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);
@@ -6424,6 +6466,8 @@
ASSERT_EQ(kInlinedKeyedStoreInstructionsAfterPatch,
masm_->InstructionsGeneratedSince(&check_inlined_codesize));
}
+
+ ASSERT(we_remembered_the_write_barrier);
deferred->BindExit();
} else {
@@ -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;
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Mon Jun 28 04:47:23 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Thu Jul 1 08:06:24 2010
@@ -44,6 +44,7 @@
enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
enum GenerateInlineSmi { DONT_GENERATE_INLINE_SMI, GENERATE_INLINE_SMI };
+enum WriteBarrierCharacter { UNLIKELY_SMI, LIKELY_SMI, NEVER_NEWSPACE };
//
-------------------------------------------------------------------------
@@ -100,7 +101,7 @@
// on the expression stack. The value is stored in the location
specified
// by the reference, and is left on top of the stack, after the reference
// is popped from beneath it (unloaded).
- void SetValue(InitState init_state);
+ void SetValue(InitState init_state, WriteBarrierCharacter wb);
// This is in preparation for something that uses the reference on the
stack.
// If we need this reference afterwards get then dup it now. Otherwise
mark
@@ -384,7 +385,7 @@
// Store a keyed property. Key and receiver are on the stack and the
value is
// in r0. Result is returned in r0.
- void EmitKeyedStore(StaticType* key_type);
+ void EmitKeyedStore(StaticType* key_type, WriteBarrierCharacter wb_info);
void LoadFromGlobalSlotCheckExtensions(Slot* slot,
TypeofState typeof_state,
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev