Enable GVN for polymorphic loads by not expanding them at the HIR level.
This change adds a new IR instruction for polymorphic loads. It performs map compares and loads in one IR instruction instead of splitting each load into a graph of map-compares and field loads. The advantage is a smaller IR and less basic blocks, plus it allows to do GVN on polymorphic loads. Review URL: http://codereview.chromium.org/6708085 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7336 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
956bd6f7bf
commit
7d8e6c929d
@ -1769,6 +1769,21 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
|
||||||
LOperand* object = UseFixed(instr->object(), r0);
|
LOperand* object = UseFixed(instr->object(), r0);
|
||||||
LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
|
LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
|
||||||
|
@ -123,6 +123,7 @@ class LCodeGen;
|
|||||||
V(LoadKeyedFastElement) \
|
V(LoadKeyedFastElement) \
|
||||||
V(LoadKeyedGeneric) \
|
V(LoadKeyedGeneric) \
|
||||||
V(LoadNamedField) \
|
V(LoadNamedField) \
|
||||||
|
V(LoadNamedFieldPolymorphic) \
|
||||||
V(LoadNamedGeneric) \
|
V(LoadNamedGeneric) \
|
||||||
V(LoadPixelArrayElement) \
|
V(LoadPixelArrayElement) \
|
||||||
V(ModI) \
|
V(ModI) \
|
||||||
@ -1148,6 +1149,19 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 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]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
|
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
|
||||||
public:
|
public:
|
||||||
explicit LLoadNamedGeneric(LOperand* object) {
|
explicit LLoadNamedGeneric(LOperand* object) {
|
||||||
|
@ -2203,6 +2203,70 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
|
||||||
ASSERT(ToRegister(instr->object()).is(r0));
|
ASSERT(ToRegister(instr->object()).is(r0));
|
||||||
ASSERT(ToRegister(instr->result()).is(r0));
|
ASSERT(ToRegister(instr->result()).is(r0));
|
||||||
|
@ -264,6 +264,11 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
// Caller should branch on equal condition.
|
// Caller should branch on equal condition.
|
||||||
void EmitIsConstructCall(Register temp1, Register temp2);
|
void EmitIsConstructCall(Register temp1, Register temp2);
|
||||||
|
|
||||||
|
void EmitLoadField(Register result,
|
||||||
|
Register object,
|
||||||
|
Handle<Map> type,
|
||||||
|
Handle<String> name);
|
||||||
|
|
||||||
LChunk* const chunk_;
|
LChunk* const chunk_;
|
||||||
MacroAssembler* const masm_;
|
MacroAssembler* const masm_;
|
||||||
CompilationInfo* const info_;
|
CompilationInfo* const info_;
|
||||||
|
@ -1156,6 +1156,60 @@ void HLoadNamedField::PrintDataTo(StringStream* stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
|
||||||
object()->PrintNameTo(stream);
|
object()->PrintNameTo(stream);
|
||||||
stream->Add("[");
|
stream->Add("[");
|
||||||
|
@ -129,6 +129,7 @@ class LChunkBuilder;
|
|||||||
V(LoadKeyedGeneric) \
|
V(LoadKeyedGeneric) \
|
||||||
V(LoadNamedField) \
|
V(LoadNamedField) \
|
||||||
V(LoadNamedGeneric) \
|
V(LoadNamedGeneric) \
|
||||||
|
V(LoadNamedFieldPolymorphic) \
|
||||||
V(LoadPixelArrayElement) \
|
V(LoadPixelArrayElement) \
|
||||||
V(Mod) \
|
V(Mod) \
|
||||||
V(Mul) \
|
V(Mul) \
|
||||||
@ -2972,6 +2973,37 @@ class HLoadNamedField: public HUnaryOperation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
class HLoadNamedGeneric: public HBinaryOperation {
|
||||||
public:
|
public:
|
||||||
HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
|
HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
|
||||||
|
@ -3445,69 +3445,6 @@ void HGraphBuilder::VisitThrow(Throw* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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,
|
HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
|
||||||
Property* expr,
|
Property* expr,
|
||||||
Handle<Map> type,
|
Handle<Map> type,
|
||||||
@ -3748,9 +3685,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|||||||
if (expr->IsMonomorphic()) {
|
if (expr->IsMonomorphic()) {
|
||||||
instr = BuildLoadNamed(obj, expr, types->first(), name);
|
instr = BuildLoadNamed(obj, expr, types->first(), name);
|
||||||
} else if (types != NULL && types->length() > 1) {
|
} else if (types != NULL && types->length() > 1) {
|
||||||
HandlePolymorphicLoadNamedField(expr, obj, types, name);
|
AddInstruction(new HCheckNonSmi(obj));
|
||||||
return;
|
instr = new HLoadNamedFieldPolymorphic(obj, types, name);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
instr = BuildLoadNamedGeneric(obj, expr);
|
instr = BuildLoadNamedGeneric(obj, expr);
|
||||||
}
|
}
|
||||||
|
@ -794,10 +794,6 @@ class HGraphBuilder: public AstVisitor {
|
|||||||
|
|
||||||
void HandlePropertyAssignment(Assignment* expr);
|
void HandlePropertyAssignment(Assignment* expr);
|
||||||
void HandleCompoundAssignment(Assignment* expr);
|
void HandleCompoundAssignment(Assignment* expr);
|
||||||
void HandlePolymorphicLoadNamedField(Property* expr,
|
|
||||||
HValue* object,
|
|
||||||
ZoneMapList* types,
|
|
||||||
Handle<String> name);
|
|
||||||
void HandlePolymorphicStoreNamedField(Assignment* expr,
|
void HandlePolymorphicStoreNamedField(Assignment* expr,
|
||||||
HValue* object,
|
HValue* object,
|
||||||
HValue* value,
|
HValue* value,
|
||||||
|
@ -2109,7 +2109,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
||||||
Register object = ToRegister(instr->InputAt(0));
|
Register object = ToRegister(instr->object());
|
||||||
Register result = ToRegister(instr->result());
|
Register result = ToRegister(instr->result());
|
||||||
if (instr->hydrogen()->is_in_object()) {
|
if (instr->hydrogen()->is_in_object()) {
|
||||||
__ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
|
__ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
|
||||||
@ -2120,6 +2120,69 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
|
||||||
ASSERT(ToRegister(instr->context()).is(esi));
|
ASSERT(ToRegister(instr->context()).is(esi));
|
||||||
ASSERT(ToRegister(instr->object()).is(eax));
|
ASSERT(ToRegister(instr->object()).is(eax));
|
||||||
|
@ -246,6 +246,10 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
// Caller should branch on equal condition.
|
// Caller should branch on equal condition.
|
||||||
void EmitIsConstructCall(Register temp);
|
void EmitIsConstructCall(Register temp);
|
||||||
|
|
||||||
|
void EmitLoadField(Register result,
|
||||||
|
Register object,
|
||||||
|
Handle<Map> type,
|
||||||
|
Handle<String> name);
|
||||||
|
|
||||||
LChunk* const chunk_;
|
LChunk* const chunk_;
|
||||||
MacroAssembler* const masm_;
|
MacroAssembler* const masm_;
|
||||||
|
@ -1790,6 +1790,21 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
|
||||||
LOperand* context = UseFixed(instr->context(), esi);
|
LOperand* context = UseFixed(instr->context(), esi);
|
||||||
LOperand* object = UseFixed(instr->object(), eax);
|
LOperand* object = UseFixed(instr->object(), eax);
|
||||||
|
@ -125,6 +125,7 @@ class LCodeGen;
|
|||||||
V(LoadKeyedFastElement) \
|
V(LoadKeyedFastElement) \
|
||||||
V(LoadKeyedGeneric) \
|
V(LoadKeyedGeneric) \
|
||||||
V(LoadNamedField) \
|
V(LoadNamedField) \
|
||||||
|
V(LoadNamedFieldPolymorphic) \
|
||||||
V(LoadNamedGeneric) \
|
V(LoadNamedGeneric) \
|
||||||
V(LoadPixelArrayElement) \
|
V(LoadPixelArrayElement) \
|
||||||
V(ModI) \
|
V(ModI) \
|
||||||
@ -1171,6 +1172,21 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> {
|
|||||||
|
|
||||||
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
|
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
|
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]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2091,6 +2091,70 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
|
||||||
ASSERT(ToRegister(instr->object()).is(rax));
|
ASSERT(ToRegister(instr->object()).is(rax));
|
||||||
ASSERT(ToRegister(instr->result()).is(rax));
|
ASSERT(ToRegister(instr->result()).is(rax));
|
||||||
|
@ -241,6 +241,11 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
// Caller should branch on equal condition.
|
// Caller should branch on equal condition.
|
||||||
void EmitIsConstructCall(Register temp);
|
void EmitIsConstructCall(Register temp);
|
||||||
|
|
||||||
|
void EmitLoadField(Register result,
|
||||||
|
Register object,
|
||||||
|
Handle<Map> type,
|
||||||
|
Handle<String> name);
|
||||||
|
|
||||||
// Emits code for pushing a constant operand.
|
// Emits code for pushing a constant operand.
|
||||||
void EmitPushConstantOperand(LOperand* operand);
|
void EmitPushConstantOperand(LOperand* operand);
|
||||||
|
|
||||||
|
@ -1763,6 +1763,21 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
|
||||||
LOperand* object = UseFixed(instr->object(), rax);
|
LOperand* object = UseFixed(instr->object(), rax);
|
||||||
LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
|
LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
|
||||||
|
@ -122,6 +122,7 @@ class LCodeGen;
|
|||||||
V(LoadKeyedFastElement) \
|
V(LoadKeyedFastElement) \
|
||||||
V(LoadKeyedGeneric) \
|
V(LoadKeyedGeneric) \
|
||||||
V(LoadNamedField) \
|
V(LoadNamedField) \
|
||||||
|
V(LoadNamedFieldPolymorphic) \
|
||||||
V(LoadNamedGeneric) \
|
V(LoadNamedGeneric) \
|
||||||
V(LoadFunctionPrototype) \
|
V(LoadFunctionPrototype) \
|
||||||
V(LoadPixelArrayElement) \
|
V(LoadPixelArrayElement) \
|
||||||
@ -1134,6 +1135,19 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 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]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
|
class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> {
|
||||||
public:
|
public:
|
||||||
explicit LLoadNamedGeneric(LOperand* object) {
|
explicit LLoadNamedGeneric(LOperand* object) {
|
||||||
|
Loading…
Reference in New Issue
Block a user