}
+LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
+ HLoadNamedFieldPolymorphic* instr) {
+ ASSERT(instr->representation().IsTagged());
+ if (instr->need_generic()) {
+ LOperand* obj = UseFixed(instr->object(), r0);
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return MarkAsCall(DefineFixed(result, r0), instr);
+ } else {
+ LOperand* obj = UseRegisterAtStart(instr->object());
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return AssignEnvironment(DefineAsRegister(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* object = UseFixed(instr->object(), r0);
LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(LoadPixelArrayElement) \
V(ModI) \
};
+class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadNamedFieldPolymorphic(LOperand* object) {
+ inputs_[0] = object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic)
+
+ LOperand* object() { return inputs_[0]; }
+};
+
+
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadNamedGeneric(LOperand* object) {
}
+void LCodeGen::EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name) {
+ LookupResult lookup;
+ type->LookupInDescriptors(NULL, *name, &lookup);
+ ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
+ int index = lookup.GetLocalFieldIndexFromMap(*type);
+ int offset = index * kPointerSize;
+ if (index < 0) {
+ // Negative property indices are in-object properties, indexed
+ // from the end of the fixed part of the object.
+ __ ldr(result, FieldMemOperand(object, offset + type->instance_size()));
+ } else {
+ // Non-negative property indices are in the properties array.
+ __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+ __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
+ }
+}
+
+
+void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+ Register scratch = scratch0();
+ int map_count = instr->hydrogen()->types()->length();
+ Handle<String> name = instr->hydrogen()->name();
+ if (map_count == 0) {
+ ASSERT(instr->hydrogen()->need_generic());
+ __ mov(r2, Operand(name));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ Label done;
+ __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+ for (int i = 0; i < map_count - 1; ++i) {
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ Label next;
+ __ cmp(scratch, Operand(map));
+ __ b(ne, &next);
+ EmitLoadField(result, object, map, name);
+ __ b(&done);
+ __ bind(&next);
+ }
+ Handle<Map> map = instr->hydrogen()->types()->last();
+ __ cmp(scratch, Operand(map));
+ if (instr->hydrogen()->need_generic()) {
+ Label generic;
+ __ b(ne, &generic);
+ EmitLoadField(result, object, map, name);
+ __ b(&done);
+ __ bind(&generic);
+ __ mov(r2, Operand(name));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ DeoptimizeIf(ne, instr->environment());
+ EmitLoadField(result, object, map, name);
+ }
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(r0));
ASSERT(ToRegister(instr->result()).is(r0));
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp1, Register temp2);
+ void EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name);
+
LChunk* const chunk_;
MacroAssembler* const masm_;
CompilationInfo* const info_;
}
+HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* object,
+ ZoneMapList* types,
+ Handle<String> name)
+ : HUnaryOperation(object),
+ types_(Min(types->length(), kMaxLoadPolymorphism)),
+ name_(name),
+ need_generic_(false) {
+ set_representation(Representation::Tagged());
+ SetFlag(kDependsOnMaps);
+ for (int i = 0;
+ i < types->length() && types_.length() < kMaxLoadPolymorphism;
+ ++i) {
+ Handle<Map> map = types->at(i);
+ LookupResult lookup;
+ map->LookupInDescriptors(NULL, *name, &lookup);
+ if (lookup.IsProperty() && lookup.type() == FIELD) {
+ types_.Add(types->at(i));
+ int index = lookup.GetLocalFieldIndexFromMap(*map);
+ if (index < 0) {
+ SetFlag(kDependsOnInobjectFields);
+ } else {
+ SetFlag(kDependsOnBackingStoreFields);
+ }
+ }
+ }
+
+ if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) {
+ SetFlag(kUseGVN);
+ } else {
+ SetAllSideEffects();
+ need_generic_ = true;
+ }
+}
+
+
+bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
+ HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
+ if (types_.length() != other->types()->length()) return false;
+ if (!name_.is_identical_to(other->name())) return false;
+ if (need_generic_ != other->need_generic_) return false;
+ for (int i = 0; i < types_.length(); i++) {
+ bool found = false;
+ for (int j = 0; j < types_.length(); j++) {
+ if (types_.at(j).is_identical_to(other->types()->at(i))) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return false;
+ }
+ return true;
+}
+
+
void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add("[");
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadPixelArrayElement) \
V(Mod) \
V(Mul) \
};
+class HLoadNamedFieldPolymorphic: public HUnaryOperation {
+ public:
+ HLoadNamedFieldPolymorphic(HValue* object,
+ ZoneMapList* types,
+ Handle<String> name);
+
+ HValue* object() { return OperandAt(0); }
+ ZoneMapList* types() { return &types_; }
+ Handle<String> name() { return name_; }
+ bool need_generic() { return need_generic_; }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic,
+ "load_named_field_polymorphic")
+
+ static const int kMaxLoadPolymorphism = 4;
+
+ protected:
+ virtual bool DataEquals(HValue* value);
+
+ private:
+ ZoneMapList types_;
+ Handle<String> name_;
+ bool need_generic_;
+};
+
+
+
class HLoadNamedGeneric: public HBinaryOperation {
public:
HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
}
-void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
- HValue* object,
- ZoneMapList* types,
- Handle<String> name) {
- // TODO(ager): We should recognize when the prototype chains for different
- // maps are identical. In that case we can avoid repeatedly generating the
- // same prototype map checks.
- int count = 0;
- HBasicBlock* join = NULL;
- for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
- Handle<Map> map = types->at(i);
- LookupResult lookup;
- map->LookupInDescriptors(NULL, *name, &lookup);
- if (lookup.IsProperty() && lookup.type() == FIELD) {
- if (count == 0) {
- AddInstruction(new HCheckNonSmi(object)); // Only needed once.
- join = graph()->CreateBasicBlock();
- }
- ++count;
- HBasicBlock* if_true = graph()->CreateBasicBlock();
- HBasicBlock* if_false = graph()->CreateBasicBlock();
- HCompareMap* compare = new HCompareMap(object, map, if_true, if_false);
- current_block()->Finish(compare);
-
- set_current_block(if_true);
- HLoadNamedField* instr =
- BuildLoadNamedField(object, expr, map, &lookup, false);
- instr->set_position(expr->position());
- instr->ClearFlag(HValue::kUseGVN);
- AddInstruction(instr);
- if (!ast_context()->IsEffect()) Push(instr);
- current_block()->Goto(join);
-
- set_current_block(if_false);
- }
- }
-
- // Finish up. Unconditionally deoptimize if we've handled all the maps we
- // know about and do not want to handle ones we've never seen. Otherwise
- // use a generic IC.
- if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
- current_block()->FinishExitWithDeoptimization();
- } else {
- HInstruction* instr = BuildLoadNamedGeneric(object, expr);
- instr->set_position(expr->position());
-
- if (join != NULL) {
- AddInstruction(instr);
- if (!ast_context()->IsEffect()) Push(instr);
- current_block()->Goto(join);
- } else {
- ast_context()->ReturnInstruction(instr, expr->id());
- return;
- }
- }
-
- ASSERT(join != NULL);
- join->SetJoinId(expr->id());
- set_current_block(join);
- if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
-}
-
-
HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
Property* expr,
Handle<Map> type,
if (expr->IsMonomorphic()) {
instr = BuildLoadNamed(obj, expr, types->first(), name);
} else if (types != NULL && types->length() > 1) {
- HandlePolymorphicLoadNamedField(expr, obj, types, name);
- return;
-
+ AddInstruction(new HCheckNonSmi(obj));
+ instr = new HLoadNamedFieldPolymorphic(obj, types, name);
} else {
instr = BuildLoadNamedGeneric(obj, expr);
}
void HandlePropertyAssignment(Assignment* expr);
void HandleCompoundAssignment(Assignment* expr);
- void HandlePolymorphicLoadNamedField(Property* expr,
- HValue* object,
- ZoneMapList* types,
- Handle<String> name);
void HandlePolymorphicStoreNamedField(Assignment* expr,
HValue* object,
HValue* value,
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
- Register object = ToRegister(instr->InputAt(0));
+ Register object = ToRegister(instr->object());
Register result = ToRegister(instr->result());
if (instr->hydrogen()->is_in_object()) {
__ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
}
+void LCodeGen::EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name) {
+ LookupResult lookup;
+ type->LookupInDescriptors(NULL, *name, &lookup);
+ ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
+ int index = lookup.GetLocalFieldIndexFromMap(*type);
+ int offset = index * kPointerSize;
+ if (index < 0) {
+ // Negative property indices are in-object properties, indexed
+ // from the end of the fixed part of the object.
+ __ mov(result, FieldOperand(object, offset + type->instance_size()));
+ } else {
+ // Non-negative property indices are in the properties array.
+ __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
+ __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+ }
+}
+
+
+void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+
+ int map_count = instr->hydrogen()->types()->length();
+ Handle<String> name = instr->hydrogen()->name();
+ if (map_count == 0) {
+ ASSERT(instr->hydrogen()->need_generic());
+ __ mov(ecx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
+ } else {
+ NearLabel done;
+ for (int i = 0; i < map_count - 1; ++i) {
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ NearLabel next;
+ __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ __ j(not_equal, &next);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&next);
+ }
+ Handle<Map> map = instr->hydrogen()->types()->last();
+ __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ if (instr->hydrogen()->need_generic()) {
+ NearLabel generic;
+ __ j(not_equal, &generic);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&generic);
+ __ mov(ecx, name);
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
+ } else {
+ DeoptimizeIf(not_equal, instr->environment());
+ EmitLoadField(result, object, map, name);
+ }
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(eax));
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp);
+ void EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name);
LChunk* const chunk_;
MacroAssembler* const masm_;
}
+LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
+ HLoadNamedFieldPolymorphic* instr) {
+ ASSERT(instr->representation().IsTagged());
+ if (instr->need_generic()) {
+ LOperand* obj = UseFixed(instr->object(), eax);
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return MarkAsCall(DefineFixed(result, eax), instr);
+ } else {
+ LOperand* obj = UseRegisterAtStart(instr->object());
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return AssignEnvironment(DefineAsRegister(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* object = UseFixed(instr->object(), eax);
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(LoadPixelArrayElement) \
V(ModI) \
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
+
+ LOperand* object() { return inputs_[0]; }
+};
+
+
+class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadNamedFieldPolymorphic(LOperand* object) {
+ inputs_[0] = object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic)
+
+ LOperand* object() { return inputs_[0]; }
};
}
+void LCodeGen::EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name) {
+ LookupResult lookup;
+ type->LookupInDescriptors(NULL, *name, &lookup);
+ ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
+ int index = lookup.GetLocalFieldIndexFromMap(*type);
+ int offset = index * kPointerSize;
+ if (index < 0) {
+ // Negative property indices are in-object properties, indexed
+ // from the end of the fixed part of the object.
+ __ movq(result, FieldOperand(object, offset + type->instance_size()));
+ } else {
+ // Non-negative property indices are in the properties array.
+ __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
+ __ movq(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
+ }
+}
+
+
+void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+
+ int map_count = instr->hydrogen()->types()->length();
+ Handle<String> name = instr->hydrogen()->name();
+
+ if (map_count == 0) {
+ ASSERT(instr->hydrogen()->need_generic());
+ __ Move(rcx, instr->hydrogen()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ NearLabel done;
+ for (int i = 0; i < map_count - 1; ++i) {
+ Handle<Map> map = instr->hydrogen()->types()->at(i);
+ NearLabel next;
+ __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ __ j(not_equal, &next);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&next);
+ }
+ Handle<Map> map = instr->hydrogen()->types()->last();
+ __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
+ if (instr->hydrogen()->need_generic()) {
+ NearLabel generic;
+ __ j(not_equal, &generic);
+ EmitLoadField(result, object, map, name);
+ __ jmp(&done);
+ __ bind(&generic);
+ __ Move(rcx, instr->hydrogen()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ DeoptimizeIf(not_equal, instr->environment());
+ EmitLoadField(result, object, map, name);
+ }
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(rax));
ASSERT(ToRegister(instr->result()).is(rax));
// Caller should branch on equal condition.
void EmitIsConstructCall(Register temp);
+ void EmitLoadField(Register result,
+ Register object,
+ Handle<Map> type,
+ Handle<String> name);
+
// Emits code for pushing a constant operand.
void EmitPushConstantOperand(LOperand* operand);
}
+LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
+ HLoadNamedFieldPolymorphic* instr) {
+ ASSERT(instr->representation().IsTagged());
+ if (instr->need_generic()) {
+ LOperand* obj = UseFixed(instr->object(), rax);
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return MarkAsCall(DefineFixed(result, rax), instr);
+ } else {
+ LOperand* obj = UseRegisterAtStart(instr->object());
+ LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
+ return AssignEnvironment(DefineAsRegister(result));
+ }
+}
+
+
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
LOperand* object = UseFixed(instr->object(), rax);
LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
+ V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
V(LoadPixelArrayElement) \
};
+class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LLoadNamedFieldPolymorphic(LOperand* object) {
+ inputs_[0] = object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic")
+ DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic)
+
+ LOperand* object() { return inputs_[0]; }
+};
+
+
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
public:
explicit LLoadNamedGeneric(LOperand* object) {