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) {
// modification check. Otherwise, we got a fixed array, and we have
// to do a slow check.
Label fixed_array;
__ mov(a2, v0);
__ lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
__ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
__ 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.
Label no_descriptors;
__ bind(&use_cache);
__ LoadInstanceDescriptors(v0, a1, a2);
__ lw(a1, FieldMemOperand(a1, DescriptorArray::kEnumCacheOffset));
__ lw(a2, FieldMemOperand(a1, DescriptorArray::kEnumCacheBridgeCacheOffset));
__ EnumLength(a1, v0);
__ 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.
__ push(v0); // Map.
__ lw(a1, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ li(a0, Operand(Smi::FromInt(0)));
// Push enumeration cache, enumeration cache length (as smi) and zero.
__ Push(a2, a1, a0);
__ jmp(&loop);
__ bind(&no_descriptors);
__ Drop(1);
__ jmp(&exit);
// We got a fixed array in register v0. Iterate through that.
Label non_proxy;
__ bind(&fixed_array);
......
......@@ -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) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
......@@ -5304,12 +5311,21 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
Register map = ToRegister(instr->map());
Register result = ToRegister(instr->result());
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);
__ lw(result,
FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
__ lw(result,
FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
__ bind(&done);
}
......
......@@ -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) {
LOperand* object = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LElementsKind(object));
......
......@@ -131,6 +131,7 @@ class LCodeGen;
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(MapEnumLength) \
V(MathMinMax) \
V(ModI) \
V(MulI) \
......@@ -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> {
public:
explicit LElementsKind(LOperand* value) {
......
......@@ -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) {
Label next;
// Preload a couple of values used in the loop.
Register empty_fixed_array_value = t2;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
mov(a1, a0);
bind(&next);
Label next, start;
mov(a2, a0);
// Check that there are no elements. Register a1 contains the
// current JS object we've reached through the prototype chain.
lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
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));
// Check if the enum length field is properly initialized, indicating that
// there is an enum cache.
lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
CheckMap(a3,
t3,
isolate()->factory()->fixed_array_map(),
call_runtime,
DONT_DO_SMI_CHECK);
EnumLength(a3, a1);
Branch(call_runtime, eq, a3, Operand(Smi::FromInt(Map::kInvalidEnumCache)));
LoadRoot(t3, Heap::kEmptyDescriptorArrayRootIndex);
lw(a3, FieldMemOperand(a3, TransitionArray::kDescriptorsOffset));
Branch(call_runtime, eq, a3, Operand(t3));
jmp(&start);
// Check that there is an enum cache in the non-empty instance
// descriptors (a3). This is the case if the next enumeration
// index field does not contain a smi.
lw(a3, FieldMemOperand(a3, DescriptorArray::kEnumCacheOffset));
JumpIfSmi(a3, call_runtime);
bind(&next);
lw(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
// For all objects but the receiver, check that the cache is empty.
Label check_prototype;
Branch(&check_prototype, eq, a1, Operand(a0));
lw(a3, FieldMemOperand(a3, DescriptorArray::kEnumCacheBridgeCacheOffset));
Branch(call_runtime, ne, a3, Operand(empty_fixed_array_value));
// Load the prototype from the map and loop if non-null.
bind(&check_prototype);
lw(a1, FieldMemOperand(a2, Map::kPrototypeOffset));
Branch(&next, ne, a1, Operand(null_value));
EnumLength(a3, a1);
Branch(call_runtime, ne, a3, Operand(Smi::FromInt(0)));
bind(&start);
// Check that there are no elements. Register r2 contains the current JS
// object we've reached through the prototype chain.
lw(a2, FieldMemOperand(a2, JSObject::kElementsOffset));
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 {
void LoadInstanceDescriptors(Register map,
Register descriptors,
Register scratch);
void EnumLength(Register dst, Register map);
// 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