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
This commit is contained in:
jkummerow@chromium.org 2011-06-20 10:19:00 +00:00
parent 404434628b
commit b789cb8c94
21 changed files with 769 additions and 219 deletions

View File

@ -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());

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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_);
}
}

View File

@ -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_;
};

View File

@ -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)

View File

@ -3444,7 +3444,16 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
value = Pop();
HValue* key = Pop();
HValue* object = Pop();
instr = BuildStoreKeyed(object, key, value, expr);
bool has_side_effects = false;
HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
expr->position(),
true, // is_store
&has_side_effects);
Push(value);
ASSERT(has_side_effects); // Stores always have side effects.
AddSimulate(expr->AssignmentId());
ast_context()->ReturnValue(Pop());
return;
}
Push(value);
instr->set_position(expr->position());
@ -3582,9 +3591,14 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
HInstruction* load = BuildLoadKeyed(obj, key, prop);
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId());
bool has_side_effects = false;
HValue* load = HandleKeyedElementAccess(
obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition,
false, // is_store
&has_side_effects);
Push(load);
if (has_side_effects) AddSimulate(expr->CompoundLoadId());
CHECK_ALIVE(VisitForValue(expr->value()));
HValue* right = Pop();
@ -3595,12 +3609,16 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
if (instr->HasSideEffects()) AddSimulate(operation->id());
expr->RecordTypeFeedback(oracle());
HInstruction* store = BuildStoreKeyed(obj, key, instr, expr);
AddInstruction(store);
HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
RelocInfo::kNoPosition,
true, // is_store
&has_side_effects);
// Drop the simulated receiver, key, and value. Return the value.
Drop(3);
Push(instr);
if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
ASSERT(has_side_effects); // Stores always have side effects.
AddSimulate(expr->AssignmentId());
ast_context()->ReturnValue(Pop());
}
@ -3778,19 +3796,79 @@ HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
}
HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
HValue* key,
Property* expr) {
ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
AddInstruction(new(zone()) HCheckNonSmi(object));
HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
HValue* external_elements,
HValue* checked_key,
HValue* val,
JSObject::ElementsKind elements_kind,
bool is_store) {
if (is_store) {
ASSERT(val != NULL);
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
HClampToUint8* clamp = new(zone()) HClampToUint8(val);
AddInstruction(clamp);
val = clamp;
break;
}
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
HToInt32* floor_val = new(zone()) HToInt32(val);
AddInstruction(floor_val);
val = floor_val;
break;
}
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
break;
case JSObject::FAST_ELEMENTS:
case JSObject::FAST_DOUBLE_ELEMENTS:
case JSObject::DICTIONARY_ELEMENTS:
case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
return new(zone()) HStoreKeyedSpecializedArrayElement(
external_elements, checked_key, val, elements_kind);
} else {
return new(zone()) HLoadKeyedSpecializedArrayElement(
external_elements, checked_key, elements_kind);
}
}
HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
Expression* expr,
bool is_store) {
ASSERT(expr->IsMonomorphic());
Handle<Map> map = expr->GetMonomorphicReceiverType();
ASSERT(map->has_fast_elements());
if (!map->has_fast_elements() && !map->has_external_array_elements()) {
return is_store ? BuildStoreKeyedGeneric(object, key, val)
: BuildLoadKeyedGeneric(object, key);
}
AddInstruction(new(zone()) HCheckNonSmi(object));
AddInstruction(new(zone()) HCheckMap(object, map));
bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
HLoadElements* elements = new(zone()) HLoadElements(object);
HInstruction* elements = new(zone()) HLoadElements(object);
HInstruction* length = NULL;
HInstruction* checked_key = NULL;
if (is_array) {
if (map->has_external_array_elements()) {
AddInstruction(elements);
length = AddInstruction(new(zone()) HExternalArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
return BuildExternalArrayElementAccess(external_elements, checked_key,
val, map->elements_kind(), is_store);
}
ASSERT(map->has_fast_elements());
if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
AddInstruction(elements);
@ -3799,51 +3877,181 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
}
return new(zone()) HLoadKeyedFastElement(elements, checked_key);
if (is_store) {
return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
} else {
return new(zone()) HLoadKeyedFastElement(elements, checked_key);
}
}
HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement(
HValue* object,
HValue* key,
Property* expr) {
ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
Expression* prop,
int ast_id,
int position,
bool is_store,
bool* has_side_effects) {
*has_side_effects = false;
AddInstruction(new(zone()) HCheckNonSmi(object));
Handle<Map> map = expr->GetMonomorphicReceiverType();
ASSERT(!map->has_fast_elements());
ASSERT(map->has_external_array_elements());
AddInstruction(new(zone()) HCheckMap(object, map));
HLoadElements* elements = new(zone()) HLoadElements(object);
AddInstruction(elements);
HInstruction* length = new(zone()) HExternalArrayLength(elements);
AddInstruction(length);
HInstruction* checked_key =
AddInstruction(new(zone()) HBoundsCheck(key, length));
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
HLoadKeyedSpecializedArrayElement* pixel_array_value =
new(zone()) HLoadKeyedSpecializedArrayElement(
external_elements, checked_key, map->elements_kind());
return pixel_array_value;
}
AddInstruction(HCheckInstanceType::NewIsSpecObject(object));
ZoneMapList* maps = prop->GetReceiverTypes();
bool todo_external_array = false;
static const int kNumElementTypes = JSObject::kElementsKindCount;
bool type_todo[kNumElementTypes];
for (int i = 0; i < kNumElementTypes; ++i) {
type_todo[i] = false;
}
HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj,
HValue* key,
Property* prop) {
if (prop->IsMonomorphic()) {
Handle<Map> receiver_type(prop->GetMonomorphicReceiverType());
// An object has either fast elements or pixel array elements, but never
// both. Pixel array maps that are assigned to pixel array elements are
// always created with the fast elements flag cleared.
if (receiver_type->has_external_array_elements()) {
return BuildLoadKeyedSpecializedArrayElement(obj, key, prop);
} else if (receiver_type->has_fast_elements()) {
return BuildLoadKeyedFastElement(obj, key, prop);
for (int i = 0; i < maps->length(); ++i) {
ASSERT(maps->at(i)->IsMap());
type_todo[maps->at(i)->elements_kind()] = true;
if (maps->at(i)->elements_kind()
>= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
todo_external_array = true;
}
}
return BuildLoadKeyedGeneric(obj, key);
// We can't treat dictionary elements here (need to deopt instead).
type_todo[JSObject::DICTIONARY_ELEMENTS] = false;
// Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt.
type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false;
HBasicBlock* join = graph()->CreateBasicBlock();
HInstruction* elements_kind_instr =
AddInstruction(new(zone()) HElementsKind(object));
HInstruction* elements = NULL;
HLoadExternalArrayPointer* external_elements = NULL;
HInstruction* checked_key = NULL;
// FAST_ELEMENTS is assumed to be the first case.
STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS;
elements_kind <= JSObject::LAST_ELEMENTS_KIND;
elements_kind = JSObject::ElementsKind(elements_kind + 1)) {
// After having handled FAST_ELEMENTS in the first run of the loop, we
// need to add some code that's executed for all other cases.
if (elements_kind == 1 && todo_external_array) {
elements = AddInstruction(new(zone()) HLoadElements(object));
// We need to forcibly prevent some ElementsKind-dependent instructions
// from being hoisted out of any loops they might occur in, because
// the current loop-invariant-code-motion algorithm isn't clever enough
// to deal with them properly.
// There's some performance to be gained by developing a smarter
// solution for this.
elements->ClearFlag(HValue::kUseGVN);
HInstruction* length =
AddInstruction(new(zone()) HExternalArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
external_elements = new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
}
if (type_todo[elements_kind]) {
HBasicBlock* if_true = graph()->CreateBasicBlock();
HBasicBlock* if_false = graph()->CreateBasicBlock();
HCompareConstantEq* compare = new(zone()) HCompareConstantEq(
elements_kind_instr,
elements_kind,
Token::EQ_STRICT);
AddInstruction(compare);
HTest* branch = new(zone()) HTest(compare, if_true, if_false);
current_block()->Finish(branch);
set_current_block(if_true);
HInstruction* access;
if (elements_kind == JSObject::FAST_ELEMENTS) {
HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
HInstruction* typecheck =
AddInstruction(new(zone()) HHasInstanceType(object, JS_ARRAY_TYPE));
HTest* test = new(zone()) HTest(typecheck, if_jsarray, if_fastobject);
current_block()->Finish(test);
set_current_block(if_jsarray);
HInstruction* length = new(zone()) HJSArrayLength(object);
AddInstruction(length);
length->ClearFlag(HValue::kUseGVN);
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
elements = AddInstruction(new(zone()) HLoadElements(object));
elements->ClearFlag(HValue::kUseGVN);
if (is_store) {
access = AddInstruction(
new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
} else {
access = AddInstruction(
new(zone()) HLoadKeyedFastElement(elements, checked_key));
Push(access);
}
*has_side_effects |= access->HasSideEffects();
if (position != -1) {
access->set_position(position);
}
if_jsarray->Goto(join);
set_current_block(if_fastobject);
elements = AddInstruction(new(zone()) HLoadElements(object));
elements->ClearFlag(HValue::kUseGVN);
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) {
access = AddInstruction(
new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
} else {
access = AddInstruction(
new(zone()) HLoadKeyedFastElement(elements, checked_key));
}
} else { // External array elements.
access = AddInstruction(BuildExternalArrayElementAccess(
external_elements, checked_key, val, elements_kind, is_store));
}
*has_side_effects |= access->HasSideEffects();
access->set_position(position);
if (!is_store) {
Push(access);
}
current_block()->Goto(join);
set_current_block(if_false);
}
}
// Deopt if none of the cases matched.
current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
join->SetJoinId(ast_id);
set_current_block(join);
return is_store ? NULL : Pop();
}
HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
HValue* key,
HValue* val,
Expression* expr,
int ast_id,
int position,
bool is_store,
bool* has_side_effects) {
ASSERT(!expr->IsPropertyName());
HInstruction* instr = NULL;
if (expr->IsMonomorphic()) {
instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store);
} else if (expr->GetReceiverTypes() != NULL &&
!expr->GetReceiverTypes()->is_empty()) {
return HandlePolymorphicElementAccess(
obj, key, val, expr, ast_id, position, is_store, has_side_effects);
} else {
if (is_store) {
instr = BuildStoreKeyedGeneric(obj, key, val);
} else {
instr = BuildLoadKeyedGeneric(obj, key);
}
}
instr->set_position(position);
AddInstruction(instr);
*has_side_effects = instr->HasSideEffects();
return instr;
}
@ -3859,112 +4067,6 @@ HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
function_strict_mode());
}
HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
HValue* key,
HValue* val,
Expression* expr) {
ASSERT(expr->IsMonomorphic());
AddInstruction(new(zone()) HCheckNonSmi(object));
Handle<Map> map = expr->GetMonomorphicReceiverType();
ASSERT(map->has_fast_elements());
AddInstruction(new(zone()) HCheckMap(object, map));
HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
HInstruction* length = NULL;
if (is_array) {
length = AddInstruction(new(zone()) HJSArrayLength(object));
} else {
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
}
HInstruction* checked_key =
AddInstruction(new(zone()) HBoundsCheck(key, length));
return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
}
HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement(
HValue* object,
HValue* key,
HValue* val,
Expression* expr) {
ASSERT(expr->IsMonomorphic());
AddInstruction(new(zone()) HCheckNonSmi(object));
Handle<Map> map = expr->GetMonomorphicReceiverType();
ASSERT(!map->has_fast_elements());
ASSERT(map->has_external_array_elements());
AddInstruction(new(zone()) HCheckMap(object, map));
HLoadElements* elements = new(zone()) HLoadElements(object);
AddInstruction(elements);
HInstruction* length = AddInstruction(
new(zone()) HExternalArrayLength(elements));
HInstruction* checked_key =
AddInstruction(new(zone()) HBoundsCheck(key, length));
HLoadExternalArrayPointer* external_elements =
new(zone()) HLoadExternalArrayPointer(elements);
AddInstruction(external_elements);
JSObject::ElementsKind elements_kind = map->elements_kind();
switch (elements_kind) {
case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
HClampToUint8* clamp = new(zone()) HClampToUint8(val);
AddInstruction(clamp);
val = clamp;
break;
}
case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case JSObject::EXTERNAL_SHORT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case JSObject::EXTERNAL_INT_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
HToInt32* floor_val = new(zone()) HToInt32(val);
AddInstruction(floor_val);
val = floor_val;
break;
}
case JSObject::EXTERNAL_FLOAT_ELEMENTS:
case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
break;
case JSObject::FAST_ELEMENTS:
case JSObject::FAST_DOUBLE_ELEMENTS:
case JSObject::DICTIONARY_ELEMENTS:
case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
return new(zone()) HStoreKeyedSpecializedArrayElement(
external_elements,
checked_key,
val,
map->elements_kind());
}
HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object,
HValue* key,
HValue* value,
Expression* expr) {
if (expr->IsMonomorphic()) {
Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
// An object has either fast elements or external array elements, but
// never both. Pixel array maps that are assigned to pixel array elements
// are always created with the fast elements flag cleared.
if (receiver_type->has_external_array_elements()) {
return BuildStoreKeyedSpecializedArrayElement(object,
key,
value,
expr);
} else if (receiver_type->has_fast_elements()) {
return BuildStoreKeyedFastElement(object, key, value, expr);
}
}
return BuildStoreKeyedGeneric(object, key, value);
}
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL) return false;
@ -4058,7 +4160,23 @@ void HGraphBuilder::VisitProperty(Property* expr) {
HValue* key = Pop();
HValue* obj = Pop();
instr = BuildLoadKeyed(obj, key, expr);
bool has_side_effects = false;
HValue* load = HandleKeyedElementAccess(
obj, key, NULL, expr, expr->id(), expr->position(),
false, // is_store
&has_side_effects);
if (has_side_effects) {
if (ast_context()->IsEffect()) {
AddSimulate(expr->id());
} else {
Push(load);
AddSimulate(expr->id());
Drop(1);
}
}
ast_context()->ReturnValue(load);
return;
}
instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
@ -5082,16 +5200,22 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
HValue* obj = environment()->ExpressionStackAt(1);
HValue* key = environment()->ExpressionStackAt(0);
HInstruction* load = BuildLoadKeyed(obj, key, prop);
PushAndAdd(load);
if (load->HasSideEffects()) AddSimulate(expr->CountId());
bool has_side_effects = false;
HValue* load = HandleKeyedElementAccess(
obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition,
false, // is_store
&has_side_effects);
Push(load);
if (has_side_effects) AddSimulate(expr->CountId());
after = BuildIncrement(returns_original_input, expr);
input = Pop();
expr->RecordTypeFeedback(oracle());
HInstruction* store = BuildStoreKeyed(obj, key, after, expr);
AddInstruction(store);
HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
RelocInfo::kNoPosition,
true, // is_store
&has_side_effects);
// Drop the key from the bailout environment. Overwrite the receiver
// with the result of the operation, and the placeholder with the
@ -5099,7 +5223,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
Drop(1);
environment()->SetExpressionStackAt(0, after);
if (returns_original_input) environment()->SetExpressionStackAt(1, input);
if (store->HasSideEffects()) AddSimulate(expr->AssignmentId());
ASSERT(has_side_effects); // Stores always have side effects.
AddSimulate(expr->AssignmentId());
}
}

View File

@ -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* BuildExternalArrayElementAccess(
HValue* external_elements,
HValue* checked_key,
HValue* val,
JSObject::ElementsKind elements_kind,
bool is_store);
HInstruction* BuildLoadKeyed(HValue* obj,
HValue* key,
Property* prop);
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,

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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) {