Commit a64858cf authored by palfia@homejinni.com's avatar palfia@homejinni.com

MIPS: Track storage types of instance variables.

Port r14464 (70300e97) and r14470 (65af80fc)

BUG=

Review URL: https://codereview.chromium.org/14305024

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14474 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 84a5a45e
......@@ -91,6 +91,10 @@ void LCodeGen::FinishCode(Handle<Code> code) {
prototype_maps_.at(i)->AddDependentCode(
DependentCode::kPrototypeCheckGroup, code);
}
for (int i = 0 ; i < transition_maps_.length(); i++) {
transition_maps_.at(i)->AddDependentCode(
DependentCode::kTransitionGroup, code);
}
}
......@@ -2685,12 +2689,30 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
Register object = ToRegister(instr->object());
Register result = ToRegister(instr->result());
if (!FLAG_track_double_fields) {
ASSERT(!instr->hydrogen()->representation().IsDouble());
}
Register temp = instr->hydrogen()->representation().IsDouble()
? scratch0() : ToRegister(instr->result());
if (instr->hydrogen()->is_in_object()) {
__ lw(result, FieldMemOperand(object, instr->hydrogen()->offset()));
__ lw(temp, FieldMemOperand(object, instr->hydrogen()->offset()));
} else {
__ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
__ lw(result, FieldMemOperand(result, instr->hydrogen()->offset()));
__ lw(temp, FieldMemOperand(object, JSObject::kPropertiesOffset));
__ lw(temp, FieldMemOperand(temp, instr->hydrogen()->offset()));
}
if (instr->hydrogen()->representation().IsDouble()) {
Label load_from_heap_number, done;
DoubleRegister result = ToDoubleRegister(instr->result());
FPURegister flt_scratch = double_scratch0().low();
__ JumpIfNotSmi(temp, &load_from_heap_number);
__ SmiUntag(temp);
__ mtc1(temp, flt_scratch);
__ cvt_d_w(result, flt_scratch);
__ Branch(&done);
__ bind(&load_from_heap_number);
__ ldc1(result, FieldMemOperand(temp, HeapNumber::kValueOffset));
__ bind(&done);
}
}
......@@ -3919,15 +3941,37 @@ void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Representation representation = instr->representation();
Register object = ToRegister(instr->object());
Register value = ToRegister(instr->value());
ASSERT(!object.is(value));
Register scratch = scratch0();
int offset = instr->offset();
ASSERT(!object.is(value));
if (!instr->transition().is_null()) {
__ li(scratch, Operand(instr->transition()));
if (FLAG_track_fields && representation.IsSmi()) {
__ SmiTagCheckOverflow(value, value, scratch);
if (!instr->hydrogen()->value()->range()->IsInSmiRange()) {
DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
}
} else if (FLAG_track_double_fields && representation.IsDouble() &&
!instr->hydrogen()->value()->type().IsSmi() &&
!instr->hydrogen()->value()->type().IsHeapNumber()) {
Label do_store;
__ JumpIfSmi(value, &do_store);
Handle<Map> map(isolate()->factory()->heap_number_map());
__ lw(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
DoCheckMapCommon(scratch, map, REQUIRE_EXACT_MAP, instr->environment());
__ bind(&do_store);
}
Handle<Map> transition = instr->transition();
if (!transition.is_null()) {
if (transition->CanBeDeprecated()) {
transition_maps_.Add(transition, info()->zone());
}
__ li(scratch, Operand(transition));
__ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
Register temp = ToRegister(instr->temp());
......
......@@ -56,6 +56,7 @@ class LCodeGen BASE_EMBEDDED {
deopt_jump_table_(4, info->zone()),
deoptimization_literals_(8, info->zone()),
prototype_maps_(0, info->zone()),
transition_maps_(0, info->zone()),
inlined_function_count_(0),
scope_(info->scope()),
status_(UNUSED),
......@@ -416,6 +417,7 @@ class LCodeGen BASE_EMBEDDED {
ZoneList<JumpTableEntry> deopt_jump_table_;
ZoneList<Handle<Object> > deoptimization_literals_;
ZoneList<Handle<Map> > prototype_maps_;
ZoneList<Handle<Map> > transition_maps_;
int inlined_function_count_;
Scope* const scope_;
Status status_;
......
......@@ -1993,8 +1993,8 @@ LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
return DefineAsRegister(
new(zone()) LLoadNamedField(UseRegisterAtStart(instr->object())));
LOperand* obj = UseRegisterAtStart(instr->object());
return DefineAsRegister(new(zone()) LLoadNamedField(obj));
}
......@@ -2199,14 +2199,20 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
: UseRegisterAtStart(instr->object());
}
LOperand* val = needs_write_barrier
? UseTempRegister(instr->value())
: UseRegister(instr->value());
LOperand* val =
needs_write_barrier ||
(FLAG_track_fields && instr->field_representation().IsSmi())
? UseTempRegister(instr->value()) : UseRegister(instr->value());
// We need a temporary register for write barrier of the map field.
LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
return new(zone()) LStoreNamedField(obj, val, temp);
LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
if ((FLAG_track_fields && instr->field_representation().IsSmi()) ||
(FLAG_track_double_fields && instr->field_representation().IsDouble())) {
return AssignEnvironment(result);
}
return result;
}
......
......@@ -2089,6 +2089,9 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> {
bool is_in_object() { return hydrogen()->is_in_object(); }
int offset() { return hydrogen()->offset(); }
Handle<Map> transition() const { return hydrogen()->transition(); }
Representation representation() const {
return hydrogen()->field_representation();
}
};
......
......@@ -5135,6 +5135,18 @@ void MacroAssembler::CheckPageFlag(
}
void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
Register scratch,
Label* if_deprecated) {
if (map->CanBeDeprecated()) {
li(scratch, Operand(map));
lw(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
And(scratch, scratch, Operand(Smi::FromInt(Map::Deprecated::kMask)));
Branch(if_deprecated, ne, scratch, Operand(zero_reg));
}
}
void MacroAssembler::JumpIfBlack(Register object,
Register scratch0,
Register scratch1,
......
......@@ -325,6 +325,10 @@ class MacroAssembler: public Assembler {
Condition cc,
Label* condition_met);
void CheckMapDeprecated(Handle<Map> map,
Register scratch,
Label* if_deprecated);
// Check if object is in new space. Jumps if the object is not in new space.
// The register scratch can be object itself, but it will be clobbered.
void JumpIfNotInNewSpace(Register object,
......
......@@ -456,6 +456,25 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
__ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
}
int descriptor = transition->LastAdded();
DescriptorArray* descriptors = transition->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
ASSERT(!representation.IsNone());
// Ensure no transitions to deprecated maps are followed.
__ CheckMapDeprecated(transition, scratch1, miss_label);
if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store;
__ JumpIfSmi(value_reg, &do_store);
__ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ bind(&do_store);
}
// Check that we are allowed to write this.
if (object->GetPrototype()->IsJSObject()) {
JSObject* holder;
......@@ -537,18 +556,20 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
int offset = object->map()->instance_size() + (index * kPointerSize);
__ sw(value_reg, FieldMemOperand(receiver_reg, offset));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg,
offset,
name_reg,
scratch1,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
if (!FLAG_track_fields || !representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg,
offset,
name_reg,
scratch1,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
}
} else {
// Write to the properties array.
int offset = index * kPointerSize + FixedArray::kHeaderSize;
......@@ -557,18 +578,20 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ sw(value_reg, FieldMemOperand(scratch1, offset));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
offset,
name_reg,
receiver_reg,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
if (!FLAG_track_fields || !representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
offset,
name_reg,
receiver_reg,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
}
}
// Return the value (register v0).
......@@ -615,24 +638,38 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
// object and the number of in-object properties is not going to change.
index -= object->map()->inobject_properties();
Representation representation = lookup->representation();
ASSERT(!representation.IsNone());
if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store;
__ JumpIfSmi(value_reg, &do_store);
__ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
miss_label, DONT_DO_SMI_CHECK);
__ bind(&do_store);
}
// TODO(verwaest): Share this code as a code stub.
if (index < 0) {
// Set the property straight into the object.
int offset = object->map()->instance_size() + (index * kPointerSize);
__ sw(value_reg, FieldMemOperand(receiver_reg, offset));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg,
offset,
name_reg,
scratch1,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
if (!FLAG_track_fields || !representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Pass the now unused name_reg as a scratch register.
__ mov(name_reg, value_reg);
__ RecordWriteField(receiver_reg,
offset,
name_reg,
scratch1,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
}
} else {
// Write to the properties array.
int offset = index * kPointerSize + FixedArray::kHeaderSize;
......@@ -641,18 +678,20 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ sw(value_reg, FieldMemOperand(scratch1, offset));
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
offset,
name_reg,
receiver_reg,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
if (!FLAG_track_fields || !representation.IsSmi()) {
// Skip updating write barrier if storing a smi.
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, value_reg);
__ RecordWriteField(scratch1,
offset,
name_reg,
receiver_reg,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
}
}
// Return the value (register v0).
......@@ -2935,18 +2974,24 @@ Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
Register map_reg = scratch1();
int receiver_count = receiver_maps->length();
int number_of_handled_maps = 0;
__ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
for (int current = 0; current < receiver_count; ++current) {
__ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
eq, map_reg, Operand(receiver_maps->at(current)));
Handle<Map> map = receiver_maps->at(current);
if (!map->is_deprecated()) {
number_of_handled_maps++;
__ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
eq, map_reg, Operand(receiver_maps->at(current)));
}
}
ASSERT(number_of_handled_maps != 0);
__ bind(&miss);
TailCallBuiltin(masm(), MissBuiltin(kind()));
// Return the generated code.
InlineCacheState state =
receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
return GetICCode(kind(), type, name, 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