Revision: 12400
Author: [email protected]
Date: Tue Aug 28 07:20:50 2012
Log: Use a special EnumLength field to indicate number of valid enum
cache values.
This is preparatory work for sharing Enum Caches.
Review URL: https://chromiumcodereview.appspot.com/10824079
http://code.google.com/p/v8/source/detail?r=12400
Modified:
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.h
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.h
/branches/bleeding_edge/src/handles.cc
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.h
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/utils.h
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.h
/branches/bleeding_edge/src/x64/macro-assembler-x64.cc
/branches/bleeding_edge/src/x64/macro-assembler-x64.h
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Aug 27 02:40:26
2012
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Aug 28 07:20:50
2012
@@ -1125,26 +1125,34 @@
// modification check. Otherwise, we got a fixed array, and we have
// to do a slow check.
Label fixed_array;
- __ mov(r2, r0);
- __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
+ __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kMetaMapRootIndex);
- __ cmp(r1, ip);
+ __ cmp(r2, ip);
__ b(ne, &fixed_array);
// We got a map in register r0. Get the enumeration cache from it.
+ Label no_descriptors;
__ bind(&use_cache);
- __ LoadInstanceDescriptors(r0, r1, r2);
- __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumCacheOffset));
- __ ldr(r2, FieldMemOperand(r1,
DescriptorArray::kEnumCacheBridgeCacheOffset));
+
+ __ EnumLength(r1, r0);
+ __ cmp(r1, Operand(Smi::FromInt(0)));
+ __ b(eq, &no_descriptors);
+
+ __ LoadInstanceDescriptors(r0, r2, r4);
+ __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheOffset));
+ __ ldr(r2, FieldMemOperand(r2,
DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots.
__ push(r0); // Map.
- __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset));
__ mov(r0, Operand(Smi::FromInt(0)));
// Push enumeration cache, enumeration cache length (as smi) and zero.
__ Push(r2, r1, r0);
__ jmp(&loop);
+ __ bind(&no_descriptors);
+ __ Drop(1);
+ __ jmp(&exit);
+
// We got a fixed array in register r0. Iterate through that.
Label non_proxy;
__ bind(&fixed_array);
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Aug 28 00:18:06 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Tue Aug 28 07:20:50 2012
@@ -1537,6 +1537,12 @@
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LFixedArrayBaseLength(array));
}
+
+
+LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
+ LOperand* map = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new(zone()) LMapEnumLength(map));
+}
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h Tue Aug 28 00:18:06 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.h Tue Aug 28 07:20:50 2012
@@ -132,6 +132,7 @@
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MapEnumLength) \
V(MathFloorOfDiv) \
V(MathMinMax) \
V(ModI) \
@@ -1002,6 +1003,16 @@
};
+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) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Aug 28
00:18:06 2012
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Aug 28
07:20:50 2012
@@ -1537,6 +1537,13 @@
Register array = ToRegister(instr->InputAt(0));
__ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
}
+
+
+void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
+ Register result = ToRegister(instr->result());
+ Register map = ToRegister(instr->InputAt(0));
+ __ EnumLength(result, map);
+}
void LCodeGen::DoElementsKind(LElementsKind* instr) {
@@ -5558,6 +5565,14 @@
Register map = ToRegister(instr->map());
Register result = ToRegister(instr->result());
Register scratch = ToRegister(instr->scratch());
+ Label load_cache, done;
+ __ EnumLength(result, map);
+ __ cmp(result, Operand(Smi::FromInt(0)));
+ __ b(ne, &load_cache);
+ __ mov(result, Operand(isolate()->factory()->empty_fixed_array()));
+ __ jmp(&done);
+
+ __ bind(&load_cache);
__ LoadInstanceDescriptors(map, result, scratch);
__ ldr(result,
FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
@@ -5565,6 +5580,8 @@
FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
__ cmp(result, Operand(0));
DeoptimizeIf(eq, instr->environment());
+
+ __ bind(&done);
}
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Aug 22
07:27:11 2012
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Aug 28
07:20:50 2012
@@ -3715,57 +3715,49 @@
mov(descriptors, Operand(FACTORY->empty_descriptor_array()));
bind(&ok);
}
+
+
+void MacroAssembler::EnumLength(Register dst, Register map) {
+ STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
+ ldr(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 = r6;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
- mov(r1, r0);
- bind(&next);
+ Label next, start;
+ mov(r2, r0);
- // Check that there are no elements. Register r1 contains the
- // current JS object we've reached through the prototype chain.
- ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
- cmp(r2, empty_fixed_array_value);
- b(ne, call_runtime);
+ // Check if the enum length field is properly initialized, indicating
that
+ // there is an enum cache.
+ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
- // Check that instance descriptors are not empty so that we can
- // check for an enum cache. Leave the map in r2 for the subsequent
- // prototype load.
- ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
- ldr(r3, FieldMemOperand(r2, Map::kTransitionsOrBackPointerOffset));
-
- CheckMap(r3,
- r7,
- isolate()->factory()->fixed_array_map(),
- call_runtime,
- DONT_DO_SMI_CHECK);
-
- LoadRoot(r7, Heap::kEmptyDescriptorArrayRootIndex);
- ldr(r3, FieldMemOperand(r3, TransitionArray::kDescriptorsOffset));
- cmp(r3, r7);
+ EnumLength(r3, r1);
+ cmp(r3, Operand(Smi::FromInt(Map::kInvalidEnumCache)));
b(eq, call_runtime);
- // Check that there is an enum cache in the non-empty instance
- // descriptors (r3). This is the case if the next enumeration
- // index field does not contain a smi.
- ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumCacheOffset));
- JumpIfSmi(r3, call_runtime);
+ jmp(&start);
+
+ bind(&next);
+ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
// For all objects but the receiver, check that the cache is empty.
- Label check_prototype;
- cmp(r1, r0);
- b(eq, &check_prototype);
- ldr(r3, FieldMemOperand(r3,
DescriptorArray::kEnumCacheBridgeCacheOffset));
- cmp(r3, empty_fixed_array_value);
+ EnumLength(r3, r1);
+ cmp(r3, Operand(Smi::FromInt(0)));
b(ne, call_runtime);
- // Load the prototype from the map and loop if non-null.
- bind(&check_prototype);
- ldr(r1, FieldMemOperand(r2, Map::kPrototypeOffset));
- cmp(r1, null_value);
+ bind(&start);
+
+ // Check that there are no elements. Register r2 contains the current JS
+ // object we've reached through the prototype chain.
+ ldr(r2, FieldMemOperand(r2, JSObject::kElementsOffset));
+ cmp(r2, empty_fixed_array_value);
+ b(ne, call_runtime);
+
+ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset));
+ cmp(r2, null_value);
b(ne, &next);
}
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Fri Aug 17
05:59:00 2012
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Aug 28
07:20:50 2012
@@ -1272,6 +1272,7 @@
void LoadInstanceDescriptors(Register map,
Register descriptors,
Register scratch);
+ void EnumLength(Register dst, Register map);
// Activation support.
void EnterFrame(StackFrame::Type type);
=======================================
--- /branches/bleeding_edge/src/handles.cc Mon Aug 27 06:47:34 2012
+++ /branches/bleeding_edge/src/handles.cc Tue Aug 28 07:20:50 2012
@@ -704,30 +704,44 @@
Isolate* isolate = object->GetIsolate();
if (object->HasFastProperties()) {
if (object->map()->instance_descriptors()->HasEnumCache()) {
- isolate->counters()->enum_cache_hits()->Increment();
+ int own_property_count = object->map()->EnumLength();
+
+ // Mark that we have an enum cache if we are allowed to cache it.
+ if (cache_result && own_property_count == Map::kInvalidEnumCache) {
+ int num_enum =
object->map()->NumberOfDescribedProperties(DONT_ENUM);
+ object->map()->SetEnumLength(num_enum);
+ }
+
DescriptorArray* desc = object->map()->instance_descriptors();
- return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()),
- isolate);
+ Handle<FixedArray> keys(FixedArray::cast(desc->GetEnumCache()),
isolate);
+
+ isolate->counters()->enum_cache_hits()->Increment();
+ return keys;
}
- isolate->counters()->enum_cache_misses()->Increment();
+
Handle<Map> map(object->map());
- int num_enum = object->NumberOfLocalProperties(DONT_ENUM);
- Handle<FixedArray> storage =
isolate->factory()->NewFixedArray(num_enum);
- Handle<FixedArray> indices;
-
- if (cache_result) {
- indices = isolate->factory()->NewFixedArray(num_enum);
+ if (map->instance_descriptors()->IsEmpty()) {
+ isolate->counters()->enum_cache_hits()->Increment();
+ if (cache_result) map->SetEnumLength(0);
+ return isolate->factory()->empty_fixed_array();
}
+
+ isolate->counters()->enum_cache_misses()->Increment();
+
+ int num_enum = map->NumberOfDescribedProperties(DONT_ENUM);
+
+ Handle<FixedArray> storage =
isolate->factory()->NewFixedArray(num_enum);
+ Handle<FixedArray> indices =
isolate->factory()->NewFixedArray(num_enum);
Handle<DescriptorArray> descs =
Handle<DescriptorArray>(object->map()->instance_descriptors(),
isolate);
int index = 0;
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- if (!descs->GetDetails(i).IsDontEnum()) {
+ PropertyDetails details = descs->GetDetails(i);
+ if (!details.IsDontEnum()) {
storage->set(index, descs->GetKey(i));
- PropertyDetails details = descs->GetDetails(i);
if (!indices.is_null()) {
if (details.type() != FIELD) {
indices = Handle<FixedArray>();
@@ -742,17 +756,19 @@
index++;
}
}
+ ASSERT(index == storage->length());
+
+ Handle<FixedArray> bridge_storage =
+ isolate->factory()->NewFixedArray(
+ DescriptorArray::kEnumCacheBridgeLength);
+ DescriptorArray* desc = object->map()->instance_descriptors();
+ desc->SetEnumCache(*bridge_storage,
+ *storage,
+ indices.is_null() ? Object::cast(Smi::FromInt(0))
+ : Object::cast(*indices));
if (cache_result) {
- Handle<FixedArray> bridge_storage =
- isolate->factory()->NewFixedArray(
- DescriptorArray::kEnumCacheBridgeLength);
- DescriptorArray* desc = object->map()->instance_descriptors();
- desc->SetEnumCache(*bridge_storage,
- *storage,
- indices.is_null() ? Object::cast(Smi::FromInt(0))
- : Object::cast(*indices));
+ object->map()->SetEnumLength(index);
}
- ASSERT(storage->length() == index);
return storage;
} else {
int num_enum = object->NumberOfLocalProperties(DONT_ENUM);
=======================================
--- /branches/bleeding_edge/src/heap.cc Tue Aug 28 04:25:08 2012
+++ /branches/bleeding_edge/src/heap.cc Tue Aug 28 07:20:50 2012
@@ -2090,7 +2090,8 @@
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
- map->set_bit_field3(0);
+ int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache);
+ map->set_bit_field3(bit_field3);
map->set_elements_kind(elements_kind);
// If the map object is aligned fill the padding area with Smi 0 objects.
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Wed Aug 22 08:44:17
2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue Aug 28 07:20:50
2012
@@ -139,6 +139,7 @@
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MapEnumLength) \
V(MathFloorOfDiv) \
V(MathMinMax) \
V(Mod) \
@@ -1923,6 +1924,26 @@
};
+class HMapEnumLength: public HUnaryOperation {
+ public:
+ explicit HMapEnumLength(HValue* value) : HUnaryOperation(value) {
+ set_type(HType::Smi());
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+};
+
+
class HElementsKind: public HUnaryOperation {
public:
explicit HElementsKind(HValue* value) : HUnaryOperation(value) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Tue Aug 28 00:18:06 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Tue Aug 28 07:20:50 2012
@@ -4582,15 +4582,14 @@
map,
DescriptorArray::kEnumCacheBridgeCacheIndex));
- HInstruction* array_length = AddInstruction(
- new(zone()) HFixedArrayBaseLength(array));
+ HInstruction* enum_length = AddInstruction(new(zone())
HMapEnumLength(map));
HInstruction* start_index = AddInstruction(new(zone()) HConstant(
Handle<Object>(Smi::FromInt(0)), Representation::Integer32()));
Push(map);
Push(array);
- Push(array_length);
+ Push(enum_length);
Push(start_index);
HInstruction* index_cache = AddInstruction(
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Mon Aug 27
02:40:26 2012
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Aug 28
07:20:50 2012
@@ -1091,19 +1091,28 @@
// We got a map in register eax. Get the enumeration cache from it.
+ Label no_descriptors;
__ bind(&use_cache);
+
+ __ EnumLength(edx, eax);
+ __ cmp(edx, Immediate(Smi::FromInt(0)));
+ __ j(equal, &no_descriptors);
+
__ LoadInstanceDescriptors(eax, ecx);
__ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
- __ mov(edx, FieldOperand(ecx,
DescriptorArray::kEnumCacheBridgeCacheOffset));
+ __ mov(ecx, FieldOperand(ecx,
DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots.
__ push(eax); // Map.
- __ push(edx); // Enumeration cache.
- __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
- __ push(eax); // Enumeration cache length (as smi).
+ __ push(ecx); // Enumeration cache.
+ __ push(edx); // Number of valid entries for the map in the enum cache.
__ push(Immediate(Smi::FromInt(0))); // Initial index.
__ jmp(&loop);
+ __ bind(&no_descriptors);
+ __ add(esp, Immediate(kPointerSize));
+ __ jmp(&exit);
+
// We got a fixed array in register eax. Iterate through that.
Label non_proxy;
__ bind(&fixed_array);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Aug 28
00:18:06 2012
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Aug 28
07:20:50 2012
@@ -1392,6 +1392,13 @@
Register array = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}
+
+
+void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
+ Register result = ToRegister(instr->result());
+ Register map = ToRegister(instr->InputAt(0));
+ __ EnumLength(result, map);
+}
void LCodeGen::DoElementsKind(LElementsKind* instr) {
@@ -5454,11 +5461,20 @@
void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
Register map = ToRegister(instr->map());
Register result = ToRegister(instr->result());
+ Label load_cache, done;
+ __ EnumLength(result, map);
+ __ cmp(result, Immediate(Smi::FromInt(0)));
+ __ j(not_equal, &load_cache);
+ __ mov(result, isolate()->factory()->empty_fixed_array());
+ __ jmp(&done);
+
+ __ bind(&load_cache);
__ LoadInstanceDescriptors(map, result);
__ mov(result,
FieldOperand(result, DescriptorArray::kEnumCacheOffset));
__ mov(result,
FieldOperand(result, FixedArray::SizeFor(instr->idx())));
+ __ bind(&done);
__ test(result, result);
DeoptimizeIf(equal, instr->environment());
}
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Aug 28 00:18:06
2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Aug 28 07:20:50
2012
@@ -1585,6 +1585,12 @@
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LFixedArrayBaseLength(array));
}
+
+
+LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
+ LOperand* map = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new(zone()) LMapEnumLength(map));
+}
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h Tue Aug 28 00:18:06 2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h Tue Aug 28 07:20:50 2012
@@ -126,6 +126,7 @@
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MapEnumLength) \
V(MathFloorOfDiv) \
V(MathMinMax) \
V(MathPowHalf) \
@@ -1019,6 +1020,16 @@
};
+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) {
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Wed Aug 22
08:44:17 2012
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Aug 28
07:20:50 2012
@@ -2895,49 +2895,45 @@
bind(&done);
}
+
+
+void MacroAssembler::EnumLength(Register dst, Register map) {
+ STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
+ mov(dst, FieldOperand(map, Map::kBitField3Offset));
+ and_(dst, Immediate(Smi::FromInt(Map::EnumLengthBits::kMask)));
+}
void MacroAssembler::CheckEnumCache(Label* call_runtime) {
- Label next;
+ Label next, start;
mov(ecx, eax);
- bind(&next);
- // Check that there are no elements. Register ecx contains the
- // current JS object we've reached through the prototype chain.
- cmp(FieldOperand(ecx, JSObject::kElementsOffset),
- isolate()->factory()->empty_fixed_array());
- j(not_equal, call_runtime);
-
- // Check that instance descriptors are not empty so that we can
- // check for an enum cache. Leave the map in ebx for the subsequent
- // prototype load.
+ // Check if the enum length field is properly initialized, indicating
that
+ // there is an enum cache.
mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
- mov(edx, FieldOperand(ebx, Map::kTransitionsOrBackPointerOffset));
- CheckMap(edx,
- isolate()->factory()->fixed_array_map(),
- call_runtime,
- DONT_DO_SMI_CHECK);
- mov(edx, FieldOperand(edx, TransitionArray::kDescriptorsOffset));
- cmp(edx, isolate()->factory()->empty_descriptor_array());
+ EnumLength(edx, ebx);
+ cmp(edx, Immediate(Smi::FromInt(Map::kInvalidEnumCache)));
j(equal, call_runtime);
- // Check that there is an enum cache in the non-empty instance
- // descriptors (edx). This is the case if the next enumeration
- // index field does not contain a smi.
- mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheOffset));
- JumpIfSmi(edx, call_runtime);
+ jmp(&start);
+
+ bind(&next);
+ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
// For all objects but the receiver, check that the cache is empty.
- Label check_prototype;
- cmp(ecx, eax);
- j(equal, &check_prototype, Label::kNear);
- mov(edx, FieldOperand(edx,
DescriptorArray::kEnumCacheBridgeCacheOffset));
- cmp(edx, isolate()->factory()->empty_fixed_array());
+ EnumLength(edx, ebx);
+ cmp(edx, Immediate(Smi::FromInt(0)));
j(not_equal, call_runtime);
- // Load the prototype from the map and loop if non-null.
- bind(&check_prototype);
+ bind(&start);
+
+ // Check that there are no elements. Register rcx contains the current JS
+ // object we've reached through the prototype chain.
+ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
+ cmp(ecx, isolate()->factory()->empty_fixed_array());
+ j(not_equal, call_runtime);
+
mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
cmp(ecx, isolate()->factory()->null_value());
j(not_equal, &next);
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Wed Aug 22
08:44:17 2012
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Aug 28
07:20:50 2012
@@ -492,7 +492,15 @@
}
void LoadInstanceDescriptors(Register map, Register descriptors);
+ void EnumLength(Register dst, Register map);
+ template<typename Field>
+ void DecodeField(Register reg) {
+ static const int full_shift = Field::kShift + kSmiTagSize;
+ static const int low_mask = Field::kMask >> Field::kShift;
+ sar(reg, full_shift);
+ and_(reg, Immediate(low_mask));
+ }
void LoadPowerOf2(XMMRegister dst, Register scratch, int power);
// Abort execution if argument is not a number. Used in debug code.
=======================================
--- /branches/bleeding_edge/src/objects.cc Tue Aug 28 04:25:08 2012
+++ /branches/bleeding_edge/src/objects.cc Tue Aug 28 07:20:50 2012
@@ -4149,16 +4149,13 @@
o = JSObject::cast(o)->GetPrototype()) {
if (!o->IsJSObject()) return false;
JSObject* curr = JSObject::cast(o);
- if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
+ int enum_length = curr->map()->EnumLength();
+ if (enum_length == Map::kInvalidEnumCache) return false;
ASSERT(!curr->HasNamedInterceptor());
ASSERT(!curr->HasIndexedInterceptor());
ASSERT(!curr->IsAccessCheckNeeded());
if (curr->NumberOfEnumElements() > 0) return false;
- if (curr != this) {
- FixedArray* curr_fixed_array =
-
FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
- if (curr_fixed_array->length() > 0) return false;
- }
+ if (curr != this && enum_length != 0) return false;
}
return true;
}
@@ -4849,6 +4846,7 @@
result->set_bit_field2(bit_field2());
result->set_bit_field3(bit_field3());
result->SetNumberOfOwnDescriptors(0);
+ result->SetEnumLength(kInvalidEnumCache);
return result;
}
@@ -5775,7 +5773,7 @@
MaybeObject* maybe_result =
accessor->AddElementsToFixedArray(NULL, NULL, this, other);
FixedArray* result;
- if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
+ if (!maybe_result->To(&result)) return maybe_result;
#ifdef DEBUG
if (FLAG_enable_slow_asserts) {
for (int i = 0; i < result->length(); i++) {
=======================================
--- /branches/bleeding_edge/src/objects.h Tue Aug 28 04:25:08 2012
+++ /branches/bleeding_edge/src/objects.h Tue Aug 28 07:20:50 2012
@@ -4663,10 +4663,11 @@
inline int bit_field3();
inline void set_bit_field3(int value);
- class NumberOfOwnDescriptorsBits: public BitField<int, 0, 11> {};
- class IsShared: public BitField<bool, 11, 1> {};
- class FunctionWithPrototype: public BitField<bool, 12, 1> {};
- class DictionaryMap: public BitField<bool, 13, 1> {};
+ class EnumLengthBits: public BitField<int, 0, 11> {};
+ class NumberOfOwnDescriptorsBits: public BitField<int, 11, 11> {};
+ class IsShared: public BitField<bool, 22, 1> {};
+ class FunctionWithPrototype: public BitField<bool, 23, 1> {};
+ class DictionaryMap: public BitField<bool, 24, 1> {};
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
@@ -4917,6 +4918,14 @@
void SetNumberOfOwnDescriptors(int number) {
set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(),
number));
}
+
+ int EnumLength() {
+ return EnumLengthBits::decode(bit_field3());
+ }
+
+ void SetEnumLength(int index) {
+ set_bit_field3(EnumLengthBits::update(bit_field3(), index));
+ }
MUST_USE_RESULT MaybeObject* RawCopy(int instance_size);
MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors();
@@ -5057,6 +5066,9 @@
static const int kMaxPreAllocatedPropertyFields = 255;
+ // Constant for denoting that the Enum Cache field was not yet used.
+ static const int kInvalidEnumCache = EnumLengthBits::kMax;
+
// Layout description.
static const int kInstanceSizesOffset = HeapObject::kHeaderSize;
static const int kInstanceAttributesOffset = kInstanceSizesOffset +
kIntSize;
=======================================
--- /branches/bleeding_edge/src/utils.h Mon Aug 6 07:13:09 2012
+++ /branches/bleeding_edge/src/utils.h Tue Aug 28 07:20:50 2012
@@ -248,6 +248,7 @@
// bitfield without compiler warnings we have to compute 2^32 without
// using a shift count of 32.
static const uint32_t kMask = ((1U << shift) << size) - (1U << shift);
+ static const uint32_t kShift = shift;
// Value for the field with all bits set.
static const T kMax = static_cast<T>((1U << size) - 1);
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Mon Aug 27 02:40:26
2012
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue Aug 28 07:20:50
2012
@@ -1105,22 +1105,32 @@
Label fixed_array;
__ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
Heap::kMetaMapRootIndex);
- __ j(not_equal, &fixed_array, Label::kNear);
+ __ j(not_equal, &fixed_array);
// We got a map in register rax. Get the enumeration cache from it.
__ bind(&use_cache);
+
+ Label no_descriptors;
+
+ __ EnumLength(rdx, rax);
+ __ Cmp(rdx, Smi::FromInt(0));
+ __ j(equal, &no_descriptors);
+
__ LoadInstanceDescriptors(rax, rcx);
__ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
- __ movq(rdx, FieldOperand(rcx,
DescriptorArray::kEnumCacheBridgeCacheOffset));
+ __ movq(rcx, FieldOperand(rcx,
DescriptorArray::kEnumCacheBridgeCacheOffset));
// Set up the four remaining stack slots.
__ push(rax); // Map.
- __ push(rdx); // Enumeration cache.
- __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
- __ push(rax); // Enumeration cache length (as smi).
+ __ push(rcx); // Enumeration cache.
+ __ push(rdx); // Number of valid entries for the map in the enum cache.
__ Push(Smi::FromInt(0)); // Initial index.
__ jmp(&loop);
+ __ bind(&no_descriptors);
+ __ addq(rsp, Immediate(kPointerSize));
+ __ jmp(&exit);
+
// We got a fixed array in register rax. Iterate through that.
Label non_proxy;
__ bind(&fixed_array);
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Aug 28
00:18:06 2012
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Aug 28
07:20:50 2012
@@ -1283,6 +1283,13 @@
Register array = ToRegister(instr->InputAt(0));
__ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
}
+
+
+void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
+ Register result = ToRegister(instr->result());
+ Register map = ToRegister(instr->InputAt(0));
+ __ EnumLength(result, map);
+}
void LCodeGen::DoElementsKind(LElementsKind* instr) {
@@ -5217,11 +5224,19 @@
void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
Register map = ToRegister(instr->map());
Register result = ToRegister(instr->result());
+ Label load_cache, done;
+ __ EnumLength(result, map);
+ __ Cmp(result, Smi::FromInt(0));
+ __ j(not_equal, &load_cache);
+ __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex);
+ __ jmp(&done);
+ __ bind(&load_cache);
__ LoadInstanceDescriptors(map, result);
__ movq(result,
FieldOperand(result, DescriptorArray::kEnumCacheOffset));
__ movq(result,
FieldOperand(result, FixedArray::SizeFor(instr->idx())));
+ __ bind(&done);
Condition cc = masm()->CheckSmi(result);
DeoptimizeIf(cc, instr->environment());
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Tue Aug 28 00:18:06 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Tue Aug 28 07:20:50 2012
@@ -1526,6 +1526,12 @@
LOperand* array = UseRegisterAtStart(instr->value());
return DefineAsRegister(new(zone()) LFixedArrayBaseLength(array));
}
+
+
+LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
+ LOperand* map = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new(zone()) LMapEnumLength(map));
+}
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h Tue Aug 28 00:18:06 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.h Tue Aug 28 07:20:50 2012
@@ -96,6 +96,7 @@
V(ElementsKind) \
V(FastLiteral) \
V(FixedArrayBaseLength) \
+ V(MapEnumLength) \
V(FunctionLiteral) \
V(GetCachedArrayIndex) \
V(GlobalObject) \
@@ -1002,6 +1003,16 @@
};
+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) {
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Aug 22
08:44:17 2012
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Aug 28
07:20:50 2012
@@ -2896,6 +2896,14 @@
Move(descriptors, isolate()->factory()->empty_descriptor_array());
bind(&ok);
}
+
+
+void MacroAssembler::EnumLength(Register dst, Register map) {
+ STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
+ movq(dst, FieldOperand(map, Map::kBitField3Offset));
+ Move(kScratchRegister, Smi::FromInt(Map::EnumLengthBits::kMask));
+ and_(dst, kScratchRegister);
+}
void MacroAssembler::DispatchMap(Register obj,
@@ -4479,52 +4487,38 @@
void MacroAssembler::CheckEnumCache(Register null_value, Label*
call_runtime) {
- Label next;
+ Label next, start;
Register empty_fixed_array_value = r8;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
- Register empty_descriptor_array_value = r9;
- LoadRoot(empty_descriptor_array_value,
- Heap::kEmptyDescriptorArrayRootIndex);
movq(rcx, rax);
- bind(&next);
- // Check that there are no elements. Register rcx contains the
- // current JS object we've reached through the prototype chain.
- cmpq(empty_fixed_array_value,
- FieldOperand(rcx, JSObject::kElementsOffset));
- j(not_equal, call_runtime);
-
- // Check that instance descriptors are not empty so that we can
- // check for an enum cache. Leave the map in rbx for the subsequent
- // prototype load.
+ // Check if the enum length field is properly initialized, indicating
that
+ // there is an enum cache.
movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
- movq(rdx, FieldOperand(rbx, Map::kTransitionsOrBackPointerOffset));
- CheckMap(rdx,
- isolate()->factory()->fixed_array_map(),
- call_runtime,
- DONT_DO_SMI_CHECK);
-
- movq(rdx, FieldOperand(rdx, TransitionArray::kDescriptorsOffset));
- cmpq(rdx, empty_descriptor_array_value);
+ EnumLength(rdx, rbx);
+ Cmp(rdx, Smi::FromInt(Map::kInvalidEnumCache));
j(equal, call_runtime);
- // Check that there is an enum cache in the non-empty instance
- // descriptors (rdx). This is the case if the next enumeration
- // index field does not contain a smi.
- movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheOffset));
- JumpIfSmi(rdx, call_runtime);
+ jmp(&start);
+
+ bind(&next);
+
+ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
// For all objects but the receiver, check that the cache is empty.
- Label check_prototype;
- cmpq(rcx, rax);
- j(equal, &check_prototype, Label::kNear);
- movq(rdx, FieldOperand(rdx,
DescriptorArray::kEnumCacheBridgeCacheOffset));
- cmpq(rdx, empty_fixed_array_value);
+ EnumLength(rdx, rbx);
+ Cmp(rdx, Smi::FromInt(0));
j(not_equal, call_runtime);
- // Load the prototype from the map and loop if non-null.
- bind(&check_prototype);
+ bind(&start);
+
+ // Check that there are no elements. Register rcx contains the current JS
+ // object we've reached through the prototype chain.
+ cmpq(empty_fixed_array_value,
+ FieldOperand(rcx, JSObject::kElementsOffset));
+ j(not_equal, call_runtime);
+
movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
cmpq(rcx, null_value);
j(not_equal, &next);
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Aug 22
08:44:17 2012
+++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Aug 28
07:20:50 2012
@@ -948,6 +948,15 @@
void LoadUint32(XMMRegister dst, Register src, XMMRegister scratch);
void LoadInstanceDescriptors(Register map, Register descriptors);
+ void EnumLength(Register dst, Register map);
+
+ template<typename Field>
+ void DecodeField(Register reg) {
+ static const int full_shift = Field::kShift + kSmiShift;
+ static const int low_mask = Field::kMask >> Field::kShift;
+ shr(reg, Immediate(full_shift));
+ and_(reg, Immediate(low_mask));
+ }
// Abort execution if argument is not a number. Used in debug code.
void AbortIfNotNumber(Register object);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev