Index: src/ia32/lithium-codegen-ia32.cc |
=================================================================== |
--- src/ia32/lithium-codegen-ia32.cc (revision 11774) |
+++ src/ia32/lithium-codegen-ia32.cc (working copy) |
@@ -2302,12 +2302,12 @@ |
void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, |
Register object, |
Handle<Map> type, |
- Handle<String> name) { |
+ Handle<String> name, |
+ LEnvironment* env) { |
LookupResult lookup(isolate()); |
type->LookupInDescriptors(NULL, *name, &lookup); |
- ASSERT(lookup.IsFound() && |
- (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); |
- if (lookup.type() == FIELD) { |
+ ASSERT(lookup.IsFound() || lookup.IsCacheable()); |
+ if (lookup.IsFound() && lookup.type() == FIELD) { |
int index = lookup.GetLocalFieldIndexFromMap(*type); |
int offset = index * kPointerSize; |
if (index < 0) { |
@@ -2319,9 +2319,23 @@ |
__ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); |
__ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize)); |
} |
- } else { |
+ } else if (lookup.IsFound() && lookup.type() == CONSTANT_FUNCTION) { |
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type)); |
__ LoadHeapObject(result, function); |
+ } else { |
+ // Negative lookup. |
+ // Check prototypes. |
+ HeapObject* current = HeapObject::cast((*type)->prototype()); |
+ Heap* heap = type->GetHeap(); |
+ while (current != heap->null_value()) { |
+ Handle<HeapObject> link(current); |
+ __ LoadHeapObject(result, link); |
+ __ cmp(FieldOperand(result, HeapObject::kMapOffset), |
+ Handle<Map>(JSObject::cast(current)->map())); |
+ DeoptimizeIf(not_equal, env); |
+ current = HeapObject::cast(current->map()->prototype()); |
+ } |
+ __ mov(result, factory()->undefined_value()); |
} |
} |
@@ -2356,18 +2370,36 @@ |
} |
Handle<String> name = instr->hydrogen()->name(); |
Label done; |
+ bool compact_code = true; |
for (int i = 0; i < map_count; ++i) { |
+ LookupResult lookup(isolate()); |
+ Handle<Map> map = instr->hydrogen()->types()->at(i); |
+ map->LookupInDescriptors(NULL, *name, &lookup); |
+ if (!lookup.IsFound() || |
+ (lookup.type() != FIELD && lookup.type() != CONSTANT_FUNCTION)) { |
+ // The two cases above cause a bounded amount of code to be emitted. This |
+ // is not necessarily the case for other lookup results. |
+ compact_code = false; |
+ break; |
+ } |
+ } |
+ for (int i = 0; i < map_count; ++i) { |
bool last = (i == map_count - 1); |
Handle<Map> map = instr->hydrogen()->types()->at(i); |
- __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); |
+ Label check_passed; |
+ __ CompareMap(object, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS); |
if (last && !need_generic) { |
DeoptimizeIf(not_equal, instr->environment()); |
- EmitLoadFieldOrConstantFunction(result, object, map, name); |
+ __ bind(&check_passed); |
+ EmitLoadFieldOrConstantFunction( |
+ result, object, map, name, instr->environment()); |
} else { |
Label next; |
__ j(not_equal, &next, Label::kNear); |
- EmitLoadFieldOrConstantFunction(result, object, map, name); |
- __ jmp(&done, Label::kNear); |
+ __ bind(&check_passed); |
+ EmitLoadFieldOrConstantFunction( |
+ result, object, map, name, instr->environment()); |
+ __ jmp(&done, compact_code ? Label::kNear : Label::kFar); |
__ bind(&next); |
} |
} |