Crankshaft support for polymorphic array handling

Review URL: http://codereview.chromium.org/7170012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8325 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 40443462
......@@ -1111,6 +1111,9 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
} else if (v->IsCompareConstantEq()) {
HCompareConstantEq* compare = HCompareConstantEq::cast(v);
return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
......@@ -1519,6 +1522,13 @@ LInstruction* LChunkBuilder::DoCompareSymbolEq(
}
LInstruction* LChunkBuilder::DoCompareConstantEq(
HCompareConstantEq* instr) {
LOperand* left = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LCmpConstantEq(left));
}
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
......@@ -1603,6 +1613,12 @@ LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
}
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
LOperand* object = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LElementsKind(object));
}
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object, TempRegister());
......
......@@ -79,6 +79,8 @@ class LCodeGen;
V(ClampTToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(CmpConstantEq) \
V(CmpConstantEqAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
......@@ -95,6 +97,7 @@ class LCodeGen;
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
......@@ -679,6 +682,29 @@ class LCmpSymbolEqAndBranch: public LControlInstruction<2, 0> {
};
class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCmpConstantEq(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
public:
explicit LCmpConstantEqAndBranch(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
"cmp-constant-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
......@@ -1062,6 +1088,17 @@ class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
};
class LElementsKind: public LTemplateInstruction<1, 1, 0> {
public:
explicit LElementsKind(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind")
DECLARE_HYDROGEN_ACCESSOR(ElementsKind)
};
class LValueOf: public LTemplateInstruction<1, 1, 1> {
public:
LValueOf(LOperand* value, LOperand* temp) {
......
......@@ -1370,6 +1370,20 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
}
void LCodeGen::DoElementsKind(LElementsKind* instr) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
// Load map into |result|.
__ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
// Load the map's "bit field 2" into |result|. We only need the first byte,
// but the following bit field extraction takes care of that anyway.
__ ldr(result, FieldMemOperand(result, Map::kBitField2Offset));
// Retrieve elements_kind from bit field 2.
__ ubfx(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
}
void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -1744,6 +1758,27 @@ void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) {
}
void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label done;
__ cmp(left, Operand(instr->hydrogen()->right()));
__ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
__ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
}
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
__ cmp(left, Operand(instr->hydrogen()->right()));
EmitBranch(true_block, false_block, eq);
}
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -2536,7 +2571,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
Label done;
Label done, fail;
__ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
__ cmp(scratch, ip);
......@@ -2544,11 +2579,18 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
__ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
__ cmp(scratch, ip);
__ b(eq, &done);
__ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
__ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
__ sub(scratch, scratch, Operand(FIRST_EXTERNAL_ARRAY_TYPE));
__ cmp(scratch, Operand(kExternalArrayTypeCount));
__ Check(cc, "Check for fast elements failed.");
// |scratch| still contains |input|'s map.
__ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
__ ubfx(scratch, scratch, Map::kElementsKindShift,
Map::kElementsKindBitCount);
__ cmp(scratch, Operand(JSObject::FAST_ELEMENTS));
__ b(eq, &done);
__ cmp(scratch, Operand(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ b(lt, &fail);
__ cmp(scratch, Operand(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ b(le, &done);
__ bind(&fail);
__ Abort("Check for fast or external elements failed.");
__ bind(&done);
}
}
......
......@@ -607,6 +607,9 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
is_string_access_ = true;
} else if (is_monomorphic_) {
monomorphic_receiver_type_ = oracle->LoadMonomorphicReceiverType(this);
} else if (oracle->LoadIsMegamorphicWithTypeInfo(this)) {
receiver_types_ = new ZoneMapList(kMaxKeyedPolymorphism);
oracle->CollectKeyedReceiverTypes(this->id(), receiver_types_);
}
}
......@@ -622,8 +625,11 @@ void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
ZoneMapList* types = oracle->StoreReceiverTypes(this, name);
receiver_types_ = types;
} else if (is_monomorphic_) {
// Record receiver type for monomorphic keyed loads.
// Record receiver type for monomorphic keyed stores.
monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
} else if (oracle->StoreIsMegamorphicWithTypeInfo(this)) {
receiver_types_ = new ZoneMapList(kMaxKeyedPolymorphism);
oracle->CollectKeyedReceiverTypes(this->id(), receiver_types_);
}
}
......@@ -631,8 +637,11 @@ void Assignment::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
is_monomorphic_ = oracle->StoreIsMonomorphicNormal(this);
if (is_monomorphic_) {
// Record receiver type for monomorphic keyed loads.
// Record receiver type for monomorphic keyed stores.
monomorphic_receiver_type_ = oracle->StoreMonomorphicReceiverType(this);
} else if (oracle->StoreIsMegamorphicWithTypeInfo(this)) {
receiver_types_ = new ZoneMapList(kMaxKeyedPolymorphism);
oracle->CollectKeyedReceiverTypes(this->id(), receiver_types_);
}
}
......
......@@ -1405,7 +1405,8 @@ class CountOperation: public Expression {
expression_(expr),
pos_(pos),
assignment_id_(GetNextId()),
count_id_(GetNextId()) { }
count_id_(GetNextId()),
receiver_types_(NULL) { }
DECLARE_NODE_TYPE(CountOperation)
......@@ -1429,6 +1430,7 @@ class CountOperation: public Expression {
virtual Handle<Map> GetMonomorphicReceiverType() {
return monomorphic_receiver_type_;
}
virtual ZoneMapList* GetReceiverTypes() { return receiver_types_; }
// Bailout support.
int AssignmentId() const { return assignment_id_; }
......@@ -1443,6 +1445,7 @@ class CountOperation: public Expression {
int assignment_id_;
int count_id_;
Handle<Map> monomorphic_receiver_type_;
ZoneMapList* receiver_types_;
};
......
......@@ -94,11 +94,13 @@ class LChunkBuilder;
V(CompareJSObjectEq) \
V(CompareMap) \
V(CompareSymbolEq) \
V(CompareConstantEq) \
V(Constant) \
V(Context) \
V(DeleteProperty) \
V(Deoptimize) \
V(Div) \
V(ElementsKind) \
V(EnterInlined) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
......@@ -402,7 +404,7 @@ class HType {
kBoolean = 0x85, // 0000 0000 1000 0101
kNonPrimitive = 0x101, // 0000 0001 0000 0001
kJSObject = 0x301, // 0000 0011 0000 0001
kJSArray = 0x701, // 0000 0111 1000 0001
kJSArray = 0x701, // 0000 0111 0000 0001
kUninitialized = 0x1fff // 0001 1111 1111 1111
};
......@@ -484,6 +486,10 @@ class HValue: public ZoneObject {
GVN_FLAG_LIST(DECLARE_DO)
#undef DECLARE_DO
kFlexibleRepresentation,
// Participate in Global Value Numbering, i.e. elimination of
// unnecessary recomputations. If an instruction sets this flag, it must
// implement DataEquals(), which will be used to determine if other
// occurrences of the instruction are indeed the same.
kUseGVN,
kCanOverflow,
kBailoutOnMinusZero,
......@@ -1707,6 +1713,25 @@ class HExternalArrayLength: public HUnaryOperation {
};
class HElementsKind: public HUnaryOperation {
public:
explicit HElementsKind(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetFlag(kDependsOnMaps);
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(ElementsKind)
protected:
virtual bool DataEquals(HValue* other) { return true; }
};
class HBitNot: public HUnaryOperation {
public:
explicit HBitNot(HValue* value) : HUnaryOperation(value) {
......@@ -2589,6 +2614,43 @@ class HCompareSymbolEq: public HBinaryOperation {
};
class HCompareConstantEq: public HUnaryOperation {
public:
HCompareConstantEq(HValue* left, int right, Token::Value op)
: HUnaryOperation(left), op_(op), right_(right) {
ASSERT(op == Token::EQ_STRICT);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
Token::Value op() const { return op_; }
int right() const { return right_; }
virtual bool EmitAtUses() {
return !HasSideEffects() && !HasMultipleUses();
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Integer32();
}
virtual HType CalculateInferredType() { return HType::Boolean(); }
DECLARE_CONCRETE_INSTRUCTION(CompareConstantEq);
protected:
virtual bool DataEquals(HValue* other) {
HCompareConstantEq* other_instr = HCompareConstantEq::cast(other);
return (op_ == other_instr->op_ &&
right_ == other_instr->right_);
}
private:
const Token::Value op_;
const int right_;
};
class HUnaryPredicate: public HUnaryOperation {
public:
explicit HUnaryPredicate(HValue* value) : HUnaryOperation(value) {
......@@ -2694,6 +2756,10 @@ class HHasInstanceType: public HUnaryPredicate {
InstanceType from() { return from_; }
InstanceType to() { return to_; }
virtual bool EmitAtUses() {
return !HasSideEffects() && !HasMultipleUses();
}
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType)
......
This diff is collapsed.
......@@ -898,18 +898,37 @@ class HGraphBuilder: public AstVisitor {
LookupResult* result,
bool smi_and_map_check);
HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
HInstruction* BuildLoadKeyedFastElement(HValue* object,
HValue* key,
Property* expr);
HInstruction* BuildLoadKeyedSpecializedArrayElement(HValue* object,
HValue* key,
Property* expr);
HInstruction* BuildLoadKeyedGeneric(HValue* object,
HValue* key);
HInstruction* BuildLoadKeyed(HValue* obj,
HValue* key,
Property* prop);
HInstruction* BuildExternalArrayElementAccess(
HValue* external_elements,
HValue* checked_key,
HValue* val,
JSObject::ElementsKind elements_kind,
bool is_store);
HInstruction* BuildMonomorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
Expression* expr,
bool is_store);
HValue* HandlePolymorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
Expression* prop,
int ast_id,
int position,
bool is_store,
bool* has_side_effects);
HValue* HandleKeyedElementAccess(HValue* obj,
HValue* key,
HValue* val,
Expression* expr,
int ast_id,
int position,
bool is_store,
bool* has_side_effects);
HInstruction* BuildLoadNamed(HValue* object,
Property* prop,
......@@ -931,22 +950,6 @@ class HGraphBuilder: public AstVisitor {
HValue* key,
HValue* value);
HInstruction* BuildStoreKeyedFastElement(HValue* object,
HValue* key,
HValue* val,
Expression* expr);
HInstruction* BuildStoreKeyedSpecializedArrayElement(
HValue* object,
HValue* key,
HValue* val,
Expression* expr);
HInstruction* BuildStoreKeyed(HValue* object,
HValue* key,
HValue* value,
Expression* assignment);
HValue* BuildContextChainWalk(Variable* var);
void AddCheckConstantFunction(Call* expr,
......
......@@ -1215,6 +1215,21 @@ void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
}
void LCodeGen::DoElementsKind(LElementsKind* instr) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
// Load map into |result|.
__ mov(result, FieldOperand(input, HeapObject::kMapOffset));
// Load the map's "bit field 2" into |result|. We only need the first byte,
// but the following masking takes care of that anyway.
__ mov(result, FieldOperand(result, Map::kBitField2Offset));
// Retrieve elements_kind from bit field 2.
__ and_(result, Map::kElementsKindMask);
__ shr(result, Map::kElementsKindShift);
}
void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -1583,6 +1598,29 @@ void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) {
}
void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label done;
__ cmp(left, instr->hydrogen()->right());
__ mov(result, factory()->true_value());
__ j(equal, &done, Label::kNear);
__ mov(result, factory()->false_value());
__ bind(&done);
}
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
__ cmp(left, instr->hydrogen()->right());
EmitBranch(true_block, false_block, equal);
}
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -2366,7 +2404,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
Register input = ToRegister(instr->InputAt(0));
__ mov(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
Label done;
Label done, ok, fail;
__ cmp(FieldOperand(result, HeapObject::kMapOffset),
Immediate(factory()->fixed_array_map()));
__ j(equal, &done, Label::kNear);
......@@ -2376,11 +2414,19 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
Register temp((result.is(eax)) ? ebx : eax);
__ push(temp);
__ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
__ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
__ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
__ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
__ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Map::kElementsKindMask);
__ shr(temp, Map::kElementsKindShift);
__ cmp(temp, JSObject::FAST_ELEMENTS);
__ j(equal, &ok, Label::kNear);
__ cmp(temp, JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less, &fail, Label::kNear);
__ cmp(temp, JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less_equal, &ok, Label::kNear);
__ bind(&fail);
__ Abort("Check for fast or external elements failed.");
__ bind(&ok);
__ pop(temp);
__ Check(below, "Check for fast elements or pixel array failed.");
__ bind(&done);
}
}
......
......@@ -1114,6 +1114,9 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
} else if (v->IsCompareConstantEq()) {
HCompareConstantEq* compare = HCompareConstantEq::cast(v);
return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
......@@ -1543,6 +1546,13 @@ LInstruction* LChunkBuilder::DoCompareSymbolEq(
}
LInstruction* LChunkBuilder::DoCompareConstantEq(
HCompareConstantEq* instr) {
LOperand* left = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LCmpConstantEq(left));
}
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
......@@ -1628,6 +1638,12 @@ LInstruction* LChunkBuilder::DoExternalArrayLength(
}
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
LOperand* object = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LElementsKind(object));
}
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object, TempRegister());
......
......@@ -77,10 +77,12 @@ class LCodeGen;
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
V(CmpJSObjectEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpSymbolEq) \
V(CmpSymbolEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
V(CmpConstantEq) \
V(CmpConstantEqAndBranch) \
V(ConstantD) \
V(ConstantI) \
V(ConstantT) \
......@@ -89,6 +91,7 @@ class LCodeGen;
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
......@@ -664,6 +667,29 @@ class LCmpSymbolEqAndBranch: public LControlInstruction<2, 0> {
};
class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCmpConstantEq(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
public:
explicit LCmpConstantEqAndBranch(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
"cmp-constant-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
......@@ -1078,6 +1104,17 @@ class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
};
class LElementsKind: public LTemplateInstruction<1, 1, 0> {
public:
explicit LElementsKind(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind")
DECLARE_HYDROGEN_ACCESSOR(ElementsKind)
};
class LValueOf: public LTemplateInstruction<1, 1, 1> {
public:
LValueOf(LOperand* value, LOperand* temp) {
......
......@@ -1653,7 +1653,7 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
// If the maximum number of receiver maps has been exceeded, use the generic
// version of the IC.
if (target_receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) {
if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
return generic_stub;
}
......
......@@ -345,8 +345,6 @@ class KeyedIC: public IC {
explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
virtual ~KeyedIC() {}
static const int kMaxKeyedPolymorphism = 4;
virtual MaybeObject* GetFastElementStubWithoutMapCheck(
bool is_js_array) = 0;
......
......@@ -2060,6 +2060,8 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
SMI_ACCESSORS(ByteArray, length, kLengthOffset)
// TODO(jkummerow): Investigate if it's possible to s/INT/SMI/ here (and
// subsequently unify H{Fixed,External}ArrayLength).
INT_ACCESSORS(ExternalArray, length, kLengthOffset)
......
......@@ -4518,8 +4518,7 @@ class PolymorphicCodeCacheHashTableKey : public HashTableKey {
MapList* maps_; // weak.
int code_flags_;
static const int kDefaultListAllocationSize =
KeyedIC::kMaxKeyedPolymorphism + 1;
static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
};
......@@ -7152,7 +7151,7 @@ void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
if (name != NULL) {
PrintF(out, "extra_ic_state = %s\n", name);
} else {
PrintF(out, "etra_ic_state = %d\n", extra);
PrintF(out, "extra_ic_state = %d\n", extra);
}
}
......
......@@ -3758,7 +3758,6 @@ class Code: public HeapObject {
static const int kOptimizableOffset = kKindSpecificFlagsOffset;
static const int kStackSlotsOffset = kKindSpecificFlagsOffset;
static const int kCheckTypeOffset = kKindSpecificFlagsOffset;
static const int kExternalArrayTypeOffset = kKindSpecificFlagsOffset;
static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
static const int kUnaryOpTypeOffset = kStubMajorKeyOffset + 1;
......
......@@ -28,6 +28,7 @@
#include "v8.h"
#include "ast.h"
#include "code-stubs.h"
#include "compiler.h"
#include "ic.h"
#include "macro-assembler.h"
......@@ -88,6 +89,19 @@ bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) {
}
bool TypeFeedbackOracle::LoadIsMegamorphicWithTypeInfo(Property* expr) {
Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
Builtins* builtins = Isolate::Current()->builtins();
return code->is_keyed_load_stub() &&
*code != builtins->builtin(Builtins::kKeyedLoadIC_Generic) &&
code->ic_state() == MEGAMORPHIC;
}
return false;
}
bool TypeFeedbackOracle::StoreIsMonomorphicNormal(Expression* expr) {
Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsMap()) return true;
......@@ -101,6 +115,19 @@ bool TypeFeedbackOracle::StoreIsMonomorphicNormal(Expression* expr) {
}
bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(Expression* expr) {
Handle<Object> map_or_code(GetInfo(expr->id()));
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
Builtins* builtins = Isolate::Current()->builtins();
return code->is_keyed_store_stub() &&
*code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) &&
code->ic_state() == MEGAMORPHIC;
}
return false;
}
bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
Handle<Object> value = GetInfo(expr->id());
return value->IsMap() || value->IsSmi();
......@@ -390,6 +417,27 @@ ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
}
void TypeFeedbackOracle::CollectKeyedReceiverTypes(
unsigned ast_id,
ZoneMapList* types) {
Handle<Object> object = GetInfo(ast_id);
if (!object->IsCode()) return;
Handle<Code> code = Handle<Code>::cast(object);
if (code->kind() == Code::KEYED_LOAD_IC ||
code->kind() == Code::KEYED_STORE_IC) {
AssertNoAllocation no_allocation;
int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
for (RelocIterator it(*code, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
Object* object = info->target_object();
if (object->IsMap()) {
types->Add(Handle<Map>(Map::cast(object)));
}
}
}
}
void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
......
......@@ -36,6 +36,8 @@
namespace v8 {
namespace internal {
const int kMaxKeyedPolymorphism = 4;
// Unknown
// | \____________
// | |
......@@ -216,7 +218,9 @@ class TypeFeedbackOracle BASE_EMBEDDED {
TypeFeedbackOracle(Handle<Code> code, Handle<Context> global_context);
bool LoadIsMonomorphicNormal(Property* expr);
bool LoadIsMegamorphicWithTypeInfo(Property* expr);
bool StoreIsMonomorphicNormal(Expression* expr);
bool StoreIsMegamorphicWithTypeInfo(Expression* expr);
bool CallIsMonomorphic(Call* expr);
Handle<Map> LoadMonomorphicReceiverType(Property* expr);
......@@ -227,6 +231,8 @@ class TypeFeedbackOracle BASE_EMBEDDED {
ZoneMapList* CallReceiverTypes(Call* expr,
Handle<String> name,
CallKind call_kind);
void CollectKeyedReceiverTypes(unsigned ast_id,
ZoneMapList* types);
CheckType GetCallCheckType(Call* expr);
Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
......
......@@ -1216,6 +1216,20 @@ void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
}
void LCodeGen::DoElementsKind(LElementsKind* instr) {
Register result = ToRegister(instr->result());
Register input = ToRegister(instr->InputAt(0));
// Load map into |result|.
__ movq(result, FieldOperand(input, HeapObject::kMapOffset));
// Load the map's "bit field 2" into |result|. We only need the first byte.
__ movzxbq(result, FieldOperand(result, Map::kBitField2Offset));
// Retrieve elements_kind from bit field 2.
__ and_(result, Immediate(Map::kElementsKindMask));
__ shr(result, Immediate(Map::kElementsKindShift));
}
void LCodeGen::DoValueOf(LValueOf* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -1594,6 +1608,29 @@ void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) {
}
void LCodeGen::DoCmpConstantEq(LCmpConstantEq* instr) {
Register left = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
Label done;
__ cmpq(left, Immediate(instr->hydrogen()->right()));
__ LoadRoot(result, Heap::kTrueValueRootIndex);
__ j(equal, &done, Label::kNear);
__ LoadRoot(result, Heap::kFalseValueRootIndex);
__ bind(&done);
}
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
Register left = ToRegister(instr->InputAt(0));
int true_block = chunk_->LookupDestination(instr->true_block_id());
int false_block = chunk_->LookupDestination(instr->false_block_id());
__ cmpq(left, Immediate(instr->hydrogen()->right()));
EmitBranch(true_block, false_block, equal);
}
void LCodeGen::DoIsNull(LIsNull* instr) {
Register reg = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
......@@ -2380,7 +2417,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
Register input = ToRegister(instr->InputAt(0));
__ movq(result, FieldOperand(input, JSObject::kElementsOffset));
if (FLAG_debug_code) {
Label done;
Label done, ok, fail;
__ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
Heap::kFixedArrayMapRootIndex);
__ j(equal, &done, Label::kNear);
......@@ -2390,11 +2427,19 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) {
Register temp((result.is(rax)) ? rbx : rax);
__ push(temp);
__ movq(temp, FieldOperand(result, HeapObject::kMapOffset));
__ movzxbq(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
__ subq(temp, Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
__ cmpq(temp, Immediate(kExternalArrayTypeCount));
__ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Immediate(Map::kElementsKindMask));
__ shr(temp, Immediate(Map::kElementsKindShift));
__ cmpl(temp, Immediate(JSObject::FAST_ELEMENTS));
__ j(equal, &ok, Label::kNear);
__ cmpl(temp, Immediate(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ j(less, &fail, Label::kNear);
__ cmpl(temp, Immediate(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ j(less_equal, &ok, Label::kNear);
__ bind(&fail);
__ Abort("Check for fast or external elements failed");
__ bind(&ok);
__ pop(temp);
__ Check(below, "Check for fast elements failed.");
__ bind(&done);
}
}
......
......@@ -1108,6 +1108,9 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HCompareSymbolEq* compare = HCompareSymbolEq::cast(v);
return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()),
UseRegisterAtStart(compare->right()));
} else if (v->IsCompareConstantEq()) {
HCompareConstantEq* compare = HCompareConstantEq::cast(v);
return new LCmpConstantEqAndBranch(UseRegisterAtStart(compare->value()));
} else if (v->IsTypeofIs()) {
HTypeofIs* typeof_is = HTypeofIs::cast(v);
return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
......@@ -1519,6 +1522,13 @@ LInstruction* LChunkBuilder::DoCompareSymbolEq(
}
LInstruction* LChunkBuilder::DoCompareConstantEq(
HCompareConstantEq* instr) {
LOperand* left = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LCmpConstantEq(left));
}
LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
......@@ -1601,6 +1611,12 @@ LInstruction* LChunkBuilder::DoExternalArrayLength(
}
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
LOperand* object = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LElementsKind(object));
}
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object);
......
......@@ -79,6 +79,8 @@ class LCodeGen;
V(ClampTToUint8) \
V(ClassOfTest) \
V(ClassOfTestAndBranch) \
V(CmpConstantEq) \
V(CmpConstantEqAndBranch) \
V(CmpID) \
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
......@@ -95,6 +97,7 @@ class LCodeGen;
V(Deoptimize) \
V(DivI) \
V(DoubleToI) \
V(ElementsKind) \
V(ExternalArrayLength) \
V(FixedArrayLength) \
V(FunctionLiteral) \
......@@ -662,6 +665,29 @@ class LCmpSymbolEqAndBranch: public LControlInstruction<2, 0> {
};
class LCmpConstantEq: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCmpConstantEq(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEq, "cmp-constant-eq")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> {
public:
explicit LCmpConstantEqAndBranch(LOperand* left) {
inputs_[0] = left;
}
DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch,
"cmp-constant-eq-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareConstantEq)
};
class LIsNull: public LTemplateInstruction<1, 1, 0> {
public:
explicit LIsNull(LOperand* value) {
......@@ -1063,6 +1089,17 @@ class LFixedArrayLength: public LTemplateInstruction<1, 1, 0> {
};
class LElementsKind: public LTemplateInstruction<1, 1, 0> {
public:
explicit LElementsKind(LOperand* value) {
inputs_[0] = value;
}
DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind")
DECLARE_HYDROGEN_ACCESSOR(ElementsKind)
};
class LValueOf: public LTemplateInstruction<1, 1, 0> {
public:
explicit LValueOf(LOperand* value) {
......
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