Commit 5a54b703 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4999 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 59f2b6c8
...@@ -1745,11 +1745,15 @@ void CodeGenerator::VisitDeclaration(Declaration* node) { ...@@ -1745,11 +1745,15 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
val = node->fun(); // NULL if we don't have a function val = node->fun(); // NULL if we don't have a function
} }
if (val != NULL) { if (val != NULL) {
WriteBarrierCharacter wb_info =
val->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI;
if (val->AsLiteral() != NULL) wb_info = NEVER_NEWSPACE;
// Set initial value. // Set initial value.
Reference target(this, node->proxy()); Reference target(this, node->proxy());
Load(val); Load(val);
target.SetValue(NOT_CONST_INIT); target.SetValue(NOT_CONST_INIT, wb_info);
// Get rid of the assigned value (declarations are statements). // Get rid of the assigned value (declarations are statements).
frame_->Drop(); frame_->Drop();
...@@ -2485,13 +2489,13 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { ...@@ -2485,13 +2489,13 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
if (each.size() > 0) { if (each.size() > 0) {
__ ldr(r0, frame_->ElementAt(each.size())); __ ldr(r0, frame_->ElementAt(each.size()));
frame_->EmitPush(r0); frame_->EmitPush(r0);
each.SetValue(NOT_CONST_INIT); each.SetValue(NOT_CONST_INIT, UNLIKELY_SMI);
frame_->Drop(2); frame_->Drop(2);
} else { } else {
// If the reference was to a slot we rely on the convenient property // 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 // that it doesn't matter whether a value (eg, r3 pushed above) is
// right on top of or right underneath a zero-sized reference. // 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(); frame_->Drop();
} }
} }
...@@ -3646,6 +3650,8 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { ...@@ -3646,6 +3650,8 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
// Evaluate the receiver subexpression. // Evaluate the receiver subexpression.
Load(prop->obj()); Load(prop->obj());
WriteBarrierCharacter wb_info;
// Change to slow case in the beginning of an initialization block to // Change to slow case in the beginning of an initialization block to
// avoid the quadratic behavior of repeatedly adding fast properties. // avoid the quadratic behavior of repeatedly adding fast properties.
if (node->starts_initialization_block()) { if (node->starts_initialization_block()) {
...@@ -3667,7 +3673,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { ...@@ -3667,7 +3673,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
// [tos] : key // [tos] : key
// [tos+1] : receiver // [tos+1] : receiver
// [tos+2] : receiver if at the end of an initialization block // [tos+2] : receiver if at the end of an initialization block
//
// Evaluate the right-hand side. // Evaluate the right-hand side.
if (node->is_compound()) { if (node->is_compound()) {
// For a compound assignment the right-hand side is a binary operation // For a compound assignment the right-hand side is a binary operation
...@@ -3699,9 +3705,13 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { ...@@ -3699,9 +3705,13 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE,
inline_smi); inline_smi);
} }
wb_info = node->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI;
} else { } else {
// For non-compound assignment just load the right-hand side. // For non-compound assignment just load the right-hand side.
Load(node->value()); Load(node->value());
wb_info = node->value()->AsLiteral() != NULL ?
NEVER_NEWSPACE :
(node->value()->type()->IsLikelySmi() ? LIKELY_SMI : UNLIKELY_SMI);
} }
// Stack layout: // Stack layout:
...@@ -3713,7 +3723,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { ...@@ -3713,7 +3723,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
// Perform the assignment. It is safe to ignore constants here. // Perform the assignment. It is safe to ignore constants here.
ASSERT(node->op() != Token::INIT_CONST); ASSERT(node->op() != Token::INIT_CONST);
CodeForSourcePosition(node->position()); CodeForSourcePosition(node->position());
EmitKeyedStore(prop->key()->type()); EmitKeyedStore(prop->key()->type(), wb_info);
frame_->EmitPush(r0); frame_->EmitPush(r0);
// Stack layout: // Stack layout:
...@@ -5509,7 +5519,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { ...@@ -5509,7 +5519,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
__ sub(value, value, Operand(Smi::FromInt(1))); __ sub(value, value, Operand(Smi::FromInt(1)));
} }
frame_->EmitPush(value); frame_->EmitPush(value);
target.SetValue(NOT_CONST_INIT); target.SetValue(NOT_CONST_INIT, LIKELY_SMI);
if (is_postfix) frame_->Pop(); if (is_postfix) frame_->Pop();
ASSERT_EQ(original_height + 1, frame_->height()); ASSERT_EQ(original_height + 1, frame_->height());
return; return;
...@@ -5608,7 +5618,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { ...@@ -5608,7 +5618,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
// Set the target with the result, leaving the result on // Set the target with the result, leaving the result on
// top of the stack. Removes the target from the stack if // top of the stack. Removes the target from the stack if
// it has a non-zero size. // 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. // Postfix: Discard the new value and use the old.
...@@ -6341,7 +6351,8 @@ void CodeGenerator::EmitKeyedLoad() { ...@@ -6341,7 +6351,8 @@ void CodeGenerator::EmitKeyedLoad() {
} }
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 // Generate inlined version of the keyed store if the code is in a loop
// and the key is likely to be a smi. // and the key is likely to be a smi.
if (loop_nesting() > 0 && key_type->IsLikelySmi()) { if (loop_nesting() > 0 && key_type->IsLikelySmi()) {
...@@ -6357,25 +6368,45 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type) { ...@@ -6357,25 +6368,45 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type) {
__ IncrementCounter(&Counters::keyed_store_inline, 1, __ IncrementCounter(&Counters::keyed_store_inline, 1,
scratch1, scratch2); scratch1, scratch2);
// Load the value, key and receiver from the stack. // 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 value = frame_->PopToRegister();
Register key = frame_->PopToRegister(value); Register key = frame_->PopToRegister(value);
VirtualFrame::SpilledScope spilled(frame_); VirtualFrame::SpilledScope spilled(frame_);
Register receiver = r2; Register receiver = r2;
frame_->EmitPop(receiver); 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. // The deferred code expects value, key and receiver in registers.
DeferredReferenceSetKeyedValue* deferred = DeferredReferenceSetKeyedValue* deferred =
new DeferredReferenceSetKeyedValue(value, key, receiver); new DeferredReferenceSetKeyedValue(value, key, receiver);
// Check that the value is a smi. As this inlined code does not set the // 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. // write barrier it is only possible to store smi values.
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)); __ tst(value, Operand(kSmiTagMask));
deferred->Branch(ne); deferred->Branch(ne);
#ifdef DEBUG
we_remembered_the_write_barrier = true;
#endif
}
}
if (!key_is_smi) {
// Check that the key is a smi. // Check that the key is a smi.
__ tst(key, Operand(kSmiTagMask)); __ tst(key, Operand(kSmiTagMask));
deferred->Branch(ne); deferred->Branch(ne);
}
// Check that the receiver is a heap object. // Check that the receiver is a heap object.
__ tst(receiver, Operand(kSmiTagMask)); __ tst(receiver, Operand(kSmiTagMask));
...@@ -6391,24 +6422,35 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type) { ...@@ -6391,24 +6422,35 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type) {
__ cmp(scratch1, key); __ cmp(scratch1, key);
deferred->Branch(ls); // Unsigned less equal. 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 // The following instructions are the part of the inlined store keyed
// property code which can be patched. Therefore the exact number of // property code which can be patched. Therefore the exact number of
// instructions generated need to be fixed, so the constant pool is blocked // instructions generated need to be fixed, so the constant pool is blocked
// while generating this code. // while generating this code.
{ Assembler::BlockConstPoolScope block_const_pool(masm_); { Assembler::BlockConstPoolScope block_const_pool(masm_);
// Get the elements array from the receiver and check that it #ifdef DEBUG
// is not a dictionary. Label check_inlined_codesize;
__ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); masm_->bind(&check_inlined_codesize);
__ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); #endif
// Read the fixed array map from the constant pool (not from the root // 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 // 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 // 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 // deferred code which will allow the debugger to break for fast case
// stores. // stores.
#ifdef DEBUG
Label check_inlined_codesize;
masm_->bind(&check_inlined_codesize);
#endif
__ mov(scratch3, Operand(Factory::fixed_array_map())); __ mov(scratch3, Operand(Factory::fixed_array_map()));
__ cmp(scratch2, scratch3); __ cmp(scratch2, scratch3);
deferred->Branch(ne); deferred->Branch(ne);
...@@ -6425,6 +6467,8 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type) { ...@@ -6425,6 +6467,8 @@ void CodeGenerator::EmitKeyedStore(StaticType* key_type) {
masm_->InstructionsGeneratedSince(&check_inlined_codesize)); masm_->InstructionsGeneratedSince(&check_inlined_codesize));
} }
ASSERT(we_remembered_the_write_barrier);
deferred->BindExit(); deferred->BindExit();
} else { } else {
frame()->CallKeyedStoreIC(); frame()->CallKeyedStoreIC();
...@@ -6522,7 +6566,7 @@ void Reference::GetValue() { ...@@ -6522,7 +6566,7 @@ void Reference::GetValue() {
} }
void Reference::SetValue(InitState init_state) { void Reference::SetValue(InitState init_state, WriteBarrierCharacter wb_info) {
ASSERT(!is_illegal()); ASSERT(!is_illegal());
ASSERT(!cgen_->has_cc()); ASSERT(!cgen_->has_cc());
MacroAssembler* masm = cgen_->masm(); MacroAssembler* masm = cgen_->masm();
...@@ -6554,7 +6598,7 @@ void Reference::SetValue(InitState init_state) { ...@@ -6554,7 +6598,7 @@ void Reference::SetValue(InitState init_state) {
Property* property = expression_->AsProperty(); Property* property = expression_->AsProperty();
ASSERT(property != NULL); ASSERT(property != NULL);
cgen_->CodeForSourcePosition(property->position()); cgen_->CodeForSourcePosition(property->position());
cgen_->EmitKeyedStore(property->key()->type()); cgen_->EmitKeyedStore(property->key()->type(), wb_info);
frame->EmitPush(r0); frame->EmitPush(r0);
set_unloaded(); set_unloaded();
break; break;
......
...@@ -44,6 +44,7 @@ class RegisterFile; ...@@ -44,6 +44,7 @@ class RegisterFile;
enum InitState { CONST_INIT, NOT_CONST_INIT }; enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
enum GenerateInlineSmi { DONT_GENERATE_INLINE_SMI, GENERATE_INLINE_SMI }; enum GenerateInlineSmi { DONT_GENERATE_INLINE_SMI, GENERATE_INLINE_SMI };
enum WriteBarrierCharacter { UNLIKELY_SMI, LIKELY_SMI, NEVER_NEWSPACE };
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -100,7 +101,7 @@ class Reference BASE_EMBEDDED { ...@@ -100,7 +101,7 @@ class Reference BASE_EMBEDDED {
// on the expression stack. The value is stored in the location specified // 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 // by the reference, and is left on top of the stack, after the reference
// is popped from beneath it (unloaded). // 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. // 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 // If we need this reference afterwards get then dup it now. Otherwise mark
...@@ -384,7 +385,7 @@ class CodeGenerator: public AstVisitor { ...@@ -384,7 +385,7 @@ class CodeGenerator: public AstVisitor {
// Store a keyed property. Key and receiver are on the stack and the value is // Store a keyed property. Key and receiver are on the stack and the value is
// in r0. Result is returned in r0. // in r0. Result is returned in r0.
void EmitKeyedStore(StaticType* key_type); void EmitKeyedStore(StaticType* key_type, WriteBarrierCharacter wb_info);
void LoadFromGlobalSlotCheckExtensions(Slot* slot, void LoadFromGlobalSlotCheckExtensions(Slot* slot,
TypeofState typeof_state, TypeofState typeof_state,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment