Replace ICStub for array.length with hydrogen stub

BUG=

Review URL: https://codereview.chromium.org/12700006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14090 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
dslomov@chromium.org 2013-03-28 12:43:19 +00:00
parent 15ab3a0612
commit e357ddc249
11 changed files with 96 additions and 167 deletions

View File

@ -4488,35 +4488,6 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
}
void ArrayLengthStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
if (kind() == Code::KEYED_LOAD_IC) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
__ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
__ b(ne, &miss);
receiver = r1;
} else {
ASSERT(kind() == Code::LOAD_IC);
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- r0 : receiver
// -- sp[0] : receiver
// -----------------------------------
receiver = r0;
}
StubCompiler::GenerateLoadArrayLength(masm, receiver, r3, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
}
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;

View File

@ -414,12 +414,9 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle,
is_monomorphic_ = oracle->LoadIsMonomorphicNormal(this);
receiver_types_.Clear();
if (key()->IsPropertyName()) {
ArrayLengthStub array_stub(Code::LOAD_IC);
FunctionPrototypeStub proto_stub(Code::LOAD_IC);
StringLengthStub string_stub(Code::LOAD_IC, false);
if (oracle->LoadIsStub(this, &array_stub)) {
is_array_length_ = true;
} else if (oracle->LoadIsStub(this, &string_stub)) {
if (oracle->LoadIsStub(this, &string_stub)) {
is_string_length_ = true;
} else if (oracle->LoadIsStub(this, &proto_stub)) {
is_function_prototype_ = true;

View File

@ -1488,7 +1488,6 @@ class Property: public Expression {
virtual KeyedAccessStoreMode GetStoreMode() {
return STANDARD_STORE;
}
bool IsArrayLength() { return is_array_length_; }
bool IsUninitialized() { return is_uninitialized_; }
TypeFeedbackId PropertyFeedbackId() { return reuse(id()); }
@ -1504,7 +1503,6 @@ class Property: public Expression {
load_id_(GetNextId(isolate)),
is_monomorphic_(false),
is_uninitialized_(false),
is_array_length_(false),
is_string_length_(false),
is_string_access_(false),
is_function_prototype_(false) { }
@ -1518,7 +1516,6 @@ class Property: public Expression {
SmallMapList receiver_types_;
bool is_monomorphic_ : 1;
bool is_uninitialized_ : 1;
bool is_array_length_ : 1;
bool is_string_length_ : 1;
bool is_string_access_ : 1;
bool is_function_prototype_ : 1;

View File

@ -47,7 +47,6 @@ namespace internal {
V(Compare) \
V(CompareIC) \
V(MathPow) \
V(ArrayLength) \
V(StringLength) \
V(FunctionPrototype) \
V(StoreArrayLength) \
@ -597,16 +596,6 @@ class ICStub: public PlatformCodeStub {
};
class ArrayLengthStub: public ICStub {
public:
explicit ArrayLengthStub(Code::Kind kind) : ICStub(kind) { }
virtual void Generate(MacroAssembler* masm);
private:
virtual CodeStub::Major MajorKey() { return ArrayLength; }
};
class FunctionPrototypeStub: public ICStub {
public:
explicit FunctionPrototypeStub(Code::Kind kind) : ICStub(kind) { }

View File

@ -1235,6 +1235,13 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
}
HInstruction* HGraphBuilder::BuildFastArrayLengthLoad(HValue* object,
HValue* typecheck) {
Zone* zone = this->zone();
return new (zone) HJSArrayLength(object, typecheck, HType::Smi());
}
HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
ElementsKind kind,
HValue* capacity) {
@ -6287,6 +6294,12 @@ static int ComputeLoadStoreFieldIndex(Handle<Map> type,
}
void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) {
AddInstruction(new(zone()) HCheckNonSmi(object));
AddInstruction(new(zone()) HCheckMaps(object, map, zone()));
}
void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object,
Handle<Map> map) {
AddInstruction(new(zone()) HCheckNonSmi(object));
@ -6398,15 +6411,39 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
}
void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
bool HOptimizedGraphBuilder::HandlePolymorphicArrayLengthLoad(
Property* expr,
HValue* object,
SmallMapList* types,
Handle<String> name) {
if (!name->Equals(isolate()->heap()->length_string())) return false;
for (int i = 0; i < types->length(); i++) {
if (types->at(i)->instance_type() != JS_ARRAY_TYPE) return false;
}
AddInstruction(new(zone()) HCheckNonSmi(object));
HInstruction* typecheck =
AddInstruction(HCheckInstanceType::NewIsJSArray(object, zone()));
HInstruction* instr = BuildFastArrayLengthLoad(object, typecheck);
instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
return true;
}
void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
HValue* object,
SmallMapList* types,
Handle<String> name) {
int count = 0;
int previous_field_offset = 0;
bool previous_field_is_in_object = false;
bool is_monomorphic_field = true;
if (HandlePolymorphicArrayLengthLoad(expr, object, types, name))
return;
Handle<Map> map;
LookupResult lookup(isolate());
for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
@ -7042,16 +7079,25 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
Handle<Map> map) {
// Handle a load from a known field.
ASSERT(!map->is_dictionary_map());
// Handle access to various length properties
if (name->Equals(isolate()->heap()->length_string())) {
if (map->instance_type() == JS_ARRAY_TYPE) {
AddCheckMapsWithTransitions(object, map);
return BuildFastArrayLengthLoad(object, NULL);
}
}
LookupResult lookup(isolate());
map->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsField()) {
AddCheckMapsWithTransitions(object, map);
AddCheckMap(object, map);
return BuildLoadNamedField(object, map, &lookup);
}
// Handle a load of a constant known function.
if (lookup.IsConstantFunction()) {
AddCheckMapsWithTransitions(object, map);
AddCheckMap(object, map);
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map));
return new(zone()) HConstant(function, Representation::Tagged());
}
@ -7062,7 +7108,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
Handle<JSObject> prototype(JSObject::cast(map->prototype()));
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
AddCheckMapsWithTransitions(object, map);
AddCheckMap(object, map);
HInstruction* holder_value = AddInstruction(
new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
return BuildLoadNamedField(holder_value, holder_map, &lookup);
@ -7073,7 +7119,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
Handle<JSObject> prototype(JSObject::cast(map->prototype()));
Handle<JSObject> holder(lookup.holder());
Handle<Map> holder_map(holder->map());
AddCheckMapsWithTransitions(object, map);
AddCheckMap(object, map);
AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*holder_map));
return new(zone()) HConstant(function, Representation::Tagged());
@ -7533,13 +7579,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
CHECK_ALIVE(VisitForValue(expr->obj()));
HInstruction* instr = NULL;
if (expr->AsProperty()->IsArrayLength()) {
HValue* array = Pop();
AddInstruction(new(zone()) HCheckNonSmi(array));
HInstruction* mapcheck =
AddInstruction(HCheckInstanceType::NewIsJSArray(array, zone()));
instr = new(zone()) HJSArrayLength(array, mapcheck);
} else if (expr->IsStringLength()) {
if (expr->IsStringLength()) {
HValue* string = Pop();
AddInstruction(new(zone()) HCheckNonSmi(string));
AddInstruction(HCheckInstanceType::NewIsString(string, zone()));

View File

@ -939,6 +939,8 @@ class HGraphBuilder {
KeyedAccessStoreMode store_mode,
Representation checked_index_representation = Representation::None());
HInstruction* BuildFastArrayLengthLoad(HValue* object, HValue* typecheck);
HInstruction* BuildStoreMap(HValue* object, HValue* map, BailoutId id);
HInstruction* BuildStoreMap(HValue* object, Handle<Map> map, BailoutId id);
@ -1351,6 +1353,10 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
HValue* object,
SmallMapList* types,
Handle<String> name);
bool HandlePolymorphicArrayLengthLoad(Property* expr,
HValue* object,
SmallMapList* types,
Handle<String> name);
void HandlePolymorphicStoreNamedField(Assignment* expr,
HValue* object,
HValue* value,
@ -1425,6 +1431,8 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
Property* expr,
Handle<Map> map);
void AddCheckMap(HValue* object, Handle<Map> map);
void AddCheckMapsWithTransitions(HValue* object,
Handle<Map> map);

View File

@ -3304,25 +3304,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
}
void ArrayLengthStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ecx : name
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss;
if (kind() == Code::KEYED_LOAD_IC) {
__ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
__ j(not_equal, &miss);
}
StubCompiler::GenerateLoadArrayLength(masm, edx, eax, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
}
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ecx : name

View File

@ -857,28 +857,6 @@ MaybeObject* LoadIC::Load(State state,
return Smi::FromInt(String::cast(*string)->length());
}
// Use specialized code for getting the length of arrays.
if (object->IsJSArray() &&
name->Equals(isolate()->heap()->length_string())) {
Handle<Code> stub;
if (state == UNINITIALIZED) {
stub = pre_monomorphic_stub();
} else if (state == PREMONOMORPHIC) {
ArrayLengthStub array_length_stub(kind());
stub = array_length_stub.GetCode(isolate());
} else if (state != MEGAMORPHIC) {
ASSERT(state != GENERIC);
stub = megamorphic_stub();
}
if (!stub.is_null()) {
set_target(*stub);
#ifdef DEBUG
if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
#endif
}
return JSArray::cast(*object)->length();
}
// Use specialized code for getting prototype of functions.
if (object->IsJSFunction() &&
name->Equals(isolate()->heap()->prototype_string()) &&
@ -1037,6 +1015,22 @@ void IC::CopyICToMegamorphicCache(Handle<String> name) {
}
bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
AssertNoAllocation no_allocation;
Map* current_map = target()->FindFirstMap();
ElementsKind receiver_elements_kind = receiver_map->elements_kind();
bool more_general_transition =
IsMoreGeneralElementsKindTransition(
current_map->elements_kind(), receiver_elements_kind);
Map* transitioned_map = more_general_transition
? current_map->LookupElementsTransitionMap(receiver_elements_kind)
: NULL;
return transitioned_map == receiver_map;
}
// Since GC may have been invoked, by the time PatchCache is called, |state| is
// not necessarily equal to target()->state().
void IC::PatchCache(State state,
@ -1054,6 +1048,17 @@ void IC::PatchCache(State state,
// Only move to megamorphic if the target changes.
if (target() != *code) {
if (target()->is_load_stub()) {
bool is_same_handler = false;
{
AssertNoAllocation no_allocation;
Code* old_handler = target()->FindFirstCode();
is_same_handler = old_handler == *code;
}
if (is_same_handler
&& IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
UpdateMonomorphicIC(receiver, code, name);
break;
}
if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
break;
}
@ -1226,6 +1231,12 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
if (!holder->HasFastProperties()) break;
return isolate()->stub_cache()->ComputeLoadViaGetter(
name, receiver, holder, Handle<JSFunction>::cast(getter));
} else if (receiver->IsJSArray() &&
name->Equals(isolate()->heap()->length_string())) {
PropertyIndex lengthIndex =
PropertyIndex::NewHeaderIndex(JSArray::kLengthOffset / kPointerSize);
return isolate()->stub_cache()->ComputeLoadField(
name, receiver, holder, lengthIndex);
}
// TODO(dcarney): Handle correctly.
if (callback->IsDeclaredAccessorInfo()) break;
@ -1705,16 +1716,7 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
transitioned_receiver_map =
ComputeTransitionedMap(receiver, store_mode);
}
ElementsKind transitioned_kind =
transitioned_receiver_map->elements_kind();
bool more_general_transition =
IsMoreGeneralElementsKindTransition(
previous_receiver_map->elements_kind(),
transitioned_kind);
Map* transitioned_previous_map = more_general_transition
? previous_receiver_map->LookupElementsTransitionMap(transitioned_kind)
: NULL;
if (transitioned_previous_map == *transitioned_receiver_map) {
if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
// Element family is the same, use the "worst" case map.
store_mode = GetNonTransitioningStoreMode(store_mode);
return isolate()->stub_cache()->ComputeKeyedStoreElement(

View File

@ -176,6 +176,7 @@ class IC {
Handle<String> name,
Handle<Code> code);
void CopyICToMegamorphicCache(Handle<String> name);
bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
void PatchCache(State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,

View File

@ -4555,35 +4555,6 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
}
void ArrayLengthStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
if (kind() == Code::KEYED_LOAD_IC) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
// -- a1 : receiver
// -----------------------------------
__ Branch(&miss, ne, a0,
Operand(masm->isolate()->factory()->length_string()));
receiver = a1;
} else {
ASSERT(kind() == Code::LOAD_IC);
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -- a0 : receiver
// -- sp[0] : receiver
// -----------------------------------
receiver = a0;
}
StubCompiler::GenerateLoadArrayLength(masm, receiver, a3, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
}
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;

View File

@ -2386,34 +2386,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
}
void ArrayLengthStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;
if (kind() == Code::KEYED_LOAD_IC) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
__ Cmp(rax, masm->isolate()->factory()->length_string());
__ j(not_equal, &miss);
receiver = rdx;
} else {
ASSERT(kind() == Code::LOAD_IC);
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
// -- rsp[0] : return address
// -----------------------------------
receiver = rax;
}
StubCompiler::GenerateLoadArrayLength(masm, receiver, r8, &miss);
__ bind(&miss);
StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
}
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver;