Commit 2b91f23b authored by verwaest@chromium.org's avatar verwaest@chromium.org

MIPS: Use a special EnumLength field to indicate number of valid enum cache values.

Port r12400 (03ae62de)

Original commit message:
This is preparatory work for sharing Enum Caches.

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/10914025
Patch from Akos Palfi <palfia@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12417 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5dd51baf
...@@ -1141,25 +1141,32 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { ...@@ -1141,25 +1141,32 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// modification check. Otherwise, we got a fixed array, and we have // modification check. Otherwise, we got a fixed array, and we have
// to do a slow check. // to do a slow check.
Label fixed_array; Label fixed_array;
__ mov(a2, v0); __ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
__ LoadRoot(at, Heap::kMetaMapRootIndex); __ LoadRoot(at, Heap::kMetaMapRootIndex);
__ Branch(&fixed_array, ne, a1, Operand(at)); __ Branch(&fixed_array, ne, a2, Operand(at));
// We got a map in register v0. Get the enumeration cache from it. // We got a map in register v0. Get the enumeration cache from it.
Label no_descriptors;
__ bind(&use_cache); __ bind(&use_cache);
__ LoadInstanceDescriptors(v0, a1, a2);
__ lw(a1, FieldMemOperand(a1, DescriptorArray::kEnumCacheOffset)); __ EnumLength(a1, v0);
__ lw(a2, FieldMemOperand(a1, DescriptorArray::kEnumCacheBridgeCacheOffset)); __ Branch(&no_descriptors, eq, a1, Operand(Smi::FromInt(0)));
__ LoadInstanceDescriptors(v0, a2, t0);
__ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheOffset));
__ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots. // Set up the four remaining stack slots.
__ push(v0); // Map. __ push(v0); // Map.
__ lw(a1, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ li(a0, Operand(Smi::FromInt(0))); __ li(a0, Operand(Smi::FromInt(0)));
// Push enumeration cache, enumeration cache length (as smi) and zero. // Push enumeration cache, enumeration cache length (as smi) and zero.
__ Push(a2, a1, a0); __ Push(a2, a1, a0);
__ jmp(&loop); __ jmp(&loop);
__ bind(&no_descriptors);
__ Drop(1);
__ jmp(&exit);
// We got a fixed array in register v0. Iterate through that. // We got a fixed array in register v0. Iterate through that.
Label non_proxy; Label non_proxy;
__ bind(&fixed_array); __ bind(&fixed_array);
......
...@@ -1224,6 +1224,13 @@ void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { ...@@ -1224,6 +1224,13 @@ void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
} }
void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
Register result = ToRegister(instr->result());
Register map = ToRegister(instr->InputAt(0));
__ EnumLength(result, map);
}
void LCodeGen::DoElementsKind(LElementsKind* instr) { void LCodeGen::DoElementsKind(LElementsKind* instr) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0)); Register input = ToRegister(instr->InputAt(0));
...@@ -5304,12 +5311,21 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { ...@@ -5304,12 +5311,21 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
Register map = ToRegister(instr->map()); Register map = ToRegister(instr->map());
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
Register scratch = ToRegister(instr->scratch()); Register scratch = ToRegister(instr->scratch());
Label load_cache, done;
__ EnumLength(result, map);
__ Branch(&load_cache, ne, result, Operand(Smi::FromInt(0)));
__ li(result, Operand(isolate()->factory()->empty_fixed_array()));
__ jmp(&done);
__ bind(&load_cache);
__ LoadInstanceDescriptors(map, result, scratch); __ LoadInstanceDescriptors(map, result, scratch);
__ lw(result, __ lw(result,
FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
__ lw(result, __ lw(result,
FieldMemOperand(result, FixedArray::SizeFor(instr->idx()))); FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg)); DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
__ bind(&done);
} }
......
...@@ -1473,6 +1473,12 @@ LInstruction* LChunkBuilder::DoFixedArrayBaseLength( ...@@ -1473,6 +1473,12 @@ LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
} }
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
LOperand* map = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LMapEnumLength(map));
}
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) { LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
LOperand* object = UseRegisterAtStart(instr->value()); LOperand* object = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LElementsKind(object)); return DefineAsRegister(new(zone()) LElementsKind(object));
......
...@@ -131,6 +131,7 @@ class LCodeGen; ...@@ -131,6 +131,7 @@ class LCodeGen;
V(LoadNamedField) \ V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \ V(LoadNamedGeneric) \
V(MapEnumLength) \
V(MathMinMax) \ V(MathMinMax) \
V(ModI) \ V(ModI) \
V(MulI) \ V(MulI) \
...@@ -984,6 +985,16 @@ class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { ...@@ -984,6 +985,16 @@ class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> {
}; };
class LMapEnumLength: public LTemplateInstruction<1, 1, 0> {
public:
explicit LMapEnumLength(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length")
};
class LElementsKind: public LTemplateInstruction<1, 1, 0> { class LElementsKind: public LTemplateInstruction<1, 1, 0> {
public: public:
explicit LElementsKind(LOperand* value) { explicit LElementsKind(LOperand* value) {
......
...@@ -5313,51 +5313,44 @@ void MacroAssembler::LoadInstanceDescriptors(Register map, ...@@ -5313,51 +5313,44 @@ void MacroAssembler::LoadInstanceDescriptors(Register map,
} }
void MacroAssembler::EnumLength(Register dst, Register map) {
STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
lw(dst, FieldMemOperand(map, Map::kBitField3Offset));
And(dst, dst, Operand(Smi::FromInt(Map::EnumLengthBits::kMask)));
}
void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) { void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
Label next;
// Preload a couple of values used in the loop.
Register empty_fixed_array_value = t2; Register empty_fixed_array_value = t2;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
mov(a1, a0); Label next, start;
bind(&next); mov(a2, a0);
// Check that there are no elements. Register a1 contains the // Check if the enum length field is properly initialized, indicating that
// current JS object we've reached through the prototype chain. // there is an enum cache.
lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset)); lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
Branch(call_runtime, ne, a2, Operand(empty_fixed_array_value));
// Check that instance descriptors are not empty so that we can
// check for an enum cache. Leave the map in a2 for the subsequent
// prototype load.
lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
lw(a3, FieldMemOperand(a2, Map::kTransitionsOrBackPointerOffset));
CheckMap(a3, EnumLength(a3, a1);
t3, Branch(call_runtime, eq, a3, Operand(Smi::FromInt(Map::kInvalidEnumCache)));
isolate()->factory()->fixed_array_map(),
call_runtime,
DONT_DO_SMI_CHECK);
LoadRoot(t3, Heap::kEmptyDescriptorArrayRootIndex); jmp(&start);
lw(a3, FieldMemOperand(a3, TransitionArray::kDescriptorsOffset));
Branch(call_runtime, eq, a3, Operand(t3));
// Check that there is an enum cache in the non-empty instance bind(&next);
// descriptors (a3). This is the case if the next enumeration lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
// index field does not contain a smi.
lw(a3, FieldMemOperand(a3, DescriptorArray::kEnumCacheOffset));
JumpIfSmi(a3, call_runtime);
// For all objects but the receiver, check that the cache is empty. // For all objects but the receiver, check that the cache is empty.
Label check_prototype; EnumLength(a3, a1);
Branch(&check_prototype, eq, a1, Operand(a0)); Branch(call_runtime, ne, a3, Operand(Smi::FromInt(0)));
lw(a3, FieldMemOperand(a3, DescriptorArray::kEnumCacheBridgeCacheOffset));
Branch(call_runtime, ne, a3, Operand(empty_fixed_array_value)); bind(&start);
// Load the prototype from the map and loop if non-null. // Check that there are no elements. Register r2 contains the current JS
bind(&check_prototype); // object we've reached through the prototype chain.
lw(a1, FieldMemOperand(a2, Map::kPrototypeOffset)); lw(a2, FieldMemOperand(a2, JSObject::kElementsOffset));
Branch(&next, ne, a1, Operand(null_value)); Branch(call_runtime, ne, a2, Operand(empty_fixed_array_value));
lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset));
Branch(&next, ne, a2, Operand(null_value));
} }
......
...@@ -1399,6 +1399,7 @@ class MacroAssembler: public Assembler { ...@@ -1399,6 +1399,7 @@ class MacroAssembler: public Assembler {
void LoadInstanceDescriptors(Register map, void LoadInstanceDescriptors(Register map,
Register descriptors, Register descriptors,
Register scratch); Register scratch);
void EnumLength(Register dst, Register map);
// Activation support. // Activation support.
......
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