Stop using HeapType in IC and Crankshaft
BUG= Review URL: https://codereview.chromium.org/935603002 Cr-Commit-Position: refs/heads/master@{#26696}
This commit is contained in:
parent
0a4047a69b
commit
119cb56617
@ -69,20 +69,10 @@ static V8_INLINE bool CheckForName(Handle<Name> name,
|
||||
|
||||
// Returns true for properties that are accessors to object fields.
|
||||
// If true, *object_offset contains offset of object field.
|
||||
template <class T>
|
||||
bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type,
|
||||
Handle<Name> name,
|
||||
bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
|
||||
int* object_offset) {
|
||||
Isolate* isolate = name->GetIsolate();
|
||||
|
||||
if (type->Is(T::String())) {
|
||||
return CheckForName(name, isolate->factory()->length_string(),
|
||||
String::kLengthOffset, object_offset);
|
||||
}
|
||||
|
||||
if (!type->IsClass()) return false;
|
||||
Handle<Map> map = type->AsClass()->Map();
|
||||
|
||||
switch (map->instance_type()) {
|
||||
case JS_ARRAY_TYPE:
|
||||
return
|
||||
@ -107,23 +97,16 @@ bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type,
|
||||
CheckForName(name, isolate->factory()->byte_offset_string(),
|
||||
JSDataView::kByteOffsetOffset, object_offset);
|
||||
default:
|
||||
if (map->instance_type() < FIRST_NONSTRING_TYPE) {
|
||||
return CheckForName(name, isolate->factory()->length_string(),
|
||||
String::kLengthOffset, object_offset);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template
|
||||
bool Accessors::IsJSObjectFieldAccessor<Type>(Type* type,
|
||||
Handle<Name> name,
|
||||
int* object_offset);
|
||||
|
||||
|
||||
template
|
||||
bool Accessors::IsJSObjectFieldAccessor<HeapType>(Handle<HeapType> type,
|
||||
Handle<Name> name,
|
||||
int* object_offset);
|
||||
|
||||
|
||||
bool SetPropertyOnInstanceIfInherited(
|
||||
Isolate* isolate, const v8::PropertyCallbackInfo<void>& info,
|
||||
v8::Local<v8::Name> name, Handle<Object> value) {
|
||||
|
@ -78,9 +78,7 @@ class Accessors : public AllStatic {
|
||||
|
||||
// Returns true for properties that are accessors to object fields.
|
||||
// If true, *object_offset contains offset of object field.
|
||||
template <class T>
|
||||
static bool IsJSObjectFieldAccessor(typename T::TypeHandle type,
|
||||
Handle<Name> name,
|
||||
static bool IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
|
||||
int* object_offset);
|
||||
|
||||
static Handle<AccessorInfo> MakeAccessor(
|
||||
|
244
src/hydrogen.cc
244
src/hydrogen.cc
@ -4472,11 +4472,6 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
|
||||
}
|
||||
|
||||
|
||||
Type* HOptimizedGraphBuilder::ToType(Handle<Map> map) {
|
||||
return IC::MapToType<Type>(map, zone());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
|
||||
for (int i = 0; i < statements->length(); i++) {
|
||||
Statement* stmt = statements->at(i);
|
||||
@ -5445,10 +5440,9 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
|
||||
}
|
||||
|
||||
|
||||
static bool CanInlinePropertyAccess(Type* type) {
|
||||
if (type->Is(Type::NumberOrString())) return true;
|
||||
if (!type->IsClass()) return false;
|
||||
Handle<Map> map = type->AsClass()->Map();
|
||||
static bool CanInlinePropertyAccess(Handle<Map> map) {
|
||||
if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
|
||||
if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
|
||||
return map->IsJSObjectMap() &&
|
||||
!map->is_dictionary_map() &&
|
||||
!map->has_named_interceptor();
|
||||
@ -5618,7 +5612,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
CHECK_ALIVE(store = BuildNamedGeneric(
|
||||
STORE, NULL, literal, name, value));
|
||||
} else {
|
||||
PropertyAccessInfo info(this, STORE, ToType(map), name);
|
||||
PropertyAccessInfo info(this, STORE, map, name);
|
||||
if (info.CanAccessMonomorphic()) {
|
||||
HValue* checked_literal = Add<HCheckMaps>(literal, map);
|
||||
DCHECK(!info.IsAccessorConstant());
|
||||
@ -5907,20 +5901,16 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
|
||||
|
||||
bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
|
||||
PropertyAccessInfo* info) {
|
||||
if (!CanInlinePropertyAccess(type_)) return false;
|
||||
if (!CanInlinePropertyAccess(map_)) return false;
|
||||
|
||||
// Currently only handle Type::Number as a polymorphic case.
|
||||
// TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
|
||||
// instruction.
|
||||
if (type_->Is(Type::Number())) return false;
|
||||
if (IsNumberType()) return false;
|
||||
|
||||
// Values are only compatible for monomorphic load if they all behave the same
|
||||
// regarding value wrappers.
|
||||
if (type_->Is(Type::NumberOrString())) {
|
||||
if (!info->type_->Is(Type::NumberOrString())) return false;
|
||||
} else {
|
||||
if (info->type_->Is(Type::NumberOrString())) return false;
|
||||
}
|
||||
if (IsValueWrapped() != info->IsValueWrapped()) return false;
|
||||
|
||||
if (!LookupDescriptor()) return false;
|
||||
|
||||
@ -5979,9 +5969,9 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
|
||||
|
||||
|
||||
bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
|
||||
if (!type_->IsClass()) return true;
|
||||
map()->LookupDescriptor(NULL, *name_, &lookup_);
|
||||
return LoadResult(map());
|
||||
if (!map_->IsJSObjectMap()) return true;
|
||||
map_->LookupDescriptor(NULL, *name_, &lookup_);
|
||||
return LoadResult(map_);
|
||||
}
|
||||
|
||||
|
||||
@ -6009,9 +5999,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
|
||||
CallOptimization call_optimization(accessor);
|
||||
if (call_optimization.is_simple_api_call()) {
|
||||
CallOptimization::HolderLookup holder_lookup;
|
||||
Handle<Map> receiver_map = this->map();
|
||||
api_holder_ = call_optimization.LookupHolderOfExpectedType(
|
||||
receiver_map, &holder_lookup);
|
||||
api_holder_ =
|
||||
call_optimization.LookupHolderOfExpectedType(map_, &holder_lookup);
|
||||
}
|
||||
}
|
||||
accessor_ = accessor;
|
||||
@ -6069,7 +6058,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
|
||||
JSObject::TryMigrateInstance(holder_);
|
||||
}
|
||||
map = Handle<Map>(holder_->map());
|
||||
if (!CanInlinePropertyAccess(ToType(map))) {
|
||||
if (!CanInlinePropertyAccess(map)) {
|
||||
lookup_.NotFound();
|
||||
return false;
|
||||
}
|
||||
@ -6082,10 +6071,9 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
|
||||
|
||||
|
||||
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
||||
if (!CanInlinePropertyAccess(type_)) return false;
|
||||
if (!CanInlinePropertyAccess(map_)) return false;
|
||||
if (IsJSObjectFieldAccessor()) return IsLoad();
|
||||
if (this->map()->function_with_prototype() &&
|
||||
!this->map()->has_non_instance_prototype() &&
|
||||
if (map_->function_with_prototype() && !map_->has_non_instance_prototype() &&
|
||||
name_.is_identical_to(isolate()->factory()->prototype_string())) {
|
||||
return IsLoad();
|
||||
}
|
||||
@ -6095,18 +6083,17 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
||||
if (IsLoad()) return true;
|
||||
|
||||
if (IsAccessorConstant()) return true;
|
||||
Handle<Map> map = this->map();
|
||||
map->LookupTransition(NULL, *name_, NONE, &lookup_);
|
||||
if (lookup_.IsTransitionToData() && map->unused_property_fields() > 0) {
|
||||
map_->LookupTransition(NULL, *name_, NONE, &lookup_);
|
||||
if (lookup_.IsTransitionToData() && map_->unused_property_fields() > 0) {
|
||||
// Construct the object field access.
|
||||
int descriptor = transition()->LastAdded();
|
||||
int index =
|
||||
transition()->instance_descriptors()->GetFieldIndex(descriptor) -
|
||||
map->inobject_properties();
|
||||
map_->inobject_properties();
|
||||
PropertyDetails details =
|
||||
transition()->instance_descriptors()->GetDetails(descriptor);
|
||||
Representation representation = details.representation();
|
||||
access_ = HObjectAccess::ForField(map, index, representation, name_);
|
||||
access_ = HObjectAccess::ForField(map_, index, representation, name_);
|
||||
|
||||
// Load field map for heap objects.
|
||||
LoadFieldMaps(transition());
|
||||
@ -6117,17 +6104,16 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
||||
|
||||
|
||||
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
|
||||
SmallMapList* types) {
|
||||
DCHECK(type_->Is(ToType(types->first())));
|
||||
SmallMapList* maps) {
|
||||
DCHECK(map_.is_identical_to(maps->first()));
|
||||
if (!CanAccessMonomorphic()) return false;
|
||||
STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
|
||||
if (types->length() > kMaxLoadPolymorphism) return false;
|
||||
if (maps->length() > kMaxLoadPolymorphism) return false;
|
||||
|
||||
HObjectAccess access = HObjectAccess::ForMap(); // bogus default
|
||||
if (GetJSObjectFieldAccess(&access)) {
|
||||
for (int i = 1; i < types->length(); ++i) {
|
||||
PropertyAccessInfo test_info(
|
||||
builder_, access_type_, ToType(types->at(i)), name_);
|
||||
for (int i = 1; i < maps->length(); ++i) {
|
||||
PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
|
||||
HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
|
||||
if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
|
||||
if (!access.Equals(test_access)) return false;
|
||||
@ -6135,18 +6121,17 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Currently only handle Type::Number as a polymorphic case.
|
||||
// Currently only handle numbers as a polymorphic case.
|
||||
// TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
|
||||
// instruction.
|
||||
if (type_->Is(Type::Number())) return false;
|
||||
if (IsNumberType()) return false;
|
||||
|
||||
// Multiple maps cannot transition to the same target map.
|
||||
DCHECK(!IsLoad() || !IsTransition());
|
||||
if (IsTransition() && types->length() > 1) return false;
|
||||
if (IsTransition() && maps->length() > 1) return false;
|
||||
|
||||
for (int i = 1; i < types->length(); ++i) {
|
||||
PropertyAccessInfo test_info(
|
||||
builder_, access_type_, ToType(types->at(i)), name_);
|
||||
for (int i = 1; i < maps->length(); ++i) {
|
||||
PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
|
||||
if (!test_info.IsCompatible(this)) return false;
|
||||
}
|
||||
|
||||
@ -6156,19 +6141,25 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
|
||||
|
||||
Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() {
|
||||
JSFunction* ctor = IC::GetRootConstructor(
|
||||
type_, current_info()->closure()->context()->native_context());
|
||||
*map_, current_info()->closure()->context()->native_context());
|
||||
if (ctor != NULL) return handle(ctor->initial_map());
|
||||
return type_->AsClass()->Map();
|
||||
return map_;
|
||||
}
|
||||
|
||||
|
||||
static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) {
|
||||
return type->Is(Type::NumberOrString()) &&
|
||||
static bool NeedsWrapping(Handle<Map> map, Handle<JSFunction> target) {
|
||||
return !map->IsJSObjectMap() &&
|
||||
is_sloppy(target->shared()->language_mode()) &&
|
||||
!target->shared()->native();
|
||||
}
|
||||
|
||||
|
||||
bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor(
|
||||
Handle<JSFunction> target) const {
|
||||
return NeedsWrapping(map_, target);
|
||||
}
|
||||
|
||||
|
||||
HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
|
||||
PropertyAccessInfo* info,
|
||||
HValue* object,
|
||||
@ -6222,7 +6213,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
|
||||
Push(value);
|
||||
}
|
||||
|
||||
if (NeedsWrappingFor(info->type(), info->accessor())) {
|
||||
if (info->NeedsWrappingFor(info->accessor())) {
|
||||
HValue* function = Add<HConstant>(info->accessor());
|
||||
PushArgumentsFromEnvironment(argument_count);
|
||||
return New<HCallFunction>(function, argument_count, WRAP_AND_CALL);
|
||||
@ -6248,13 +6239,8 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
|
||||
PropertyAccessType access_type,
|
||||
Expression* expr,
|
||||
BailoutId ast_id,
|
||||
BailoutId return_id,
|
||||
HValue* object,
|
||||
HValue* value,
|
||||
SmallMapList* types,
|
||||
PropertyAccessType access_type, Expression* expr, BailoutId ast_id,
|
||||
BailoutId return_id, HValue* object, HValue* value, SmallMapList* maps,
|
||||
Handle<String> name) {
|
||||
// Something did not match; must use a polymorphic load.
|
||||
int count = 0;
|
||||
@ -6265,33 +6251,33 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
|
||||
bool handle_smi = false;
|
||||
STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
|
||||
int i;
|
||||
for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
|
||||
PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
|
||||
if (info.type()->Is(Type::String())) {
|
||||
for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
|
||||
PropertyAccessInfo info(this, access_type, maps->at(i), name);
|
||||
if (info.IsStringType()) {
|
||||
if (handled_string) continue;
|
||||
handled_string = true;
|
||||
}
|
||||
if (info.CanAccessMonomorphic()) {
|
||||
count++;
|
||||
if (info.type()->Is(Type::Number())) {
|
||||
if (info.IsNumberType()) {
|
||||
handle_smi = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i < types->length()) {
|
||||
if (i < maps->length()) {
|
||||
count = -1;
|
||||
types->Clear();
|
||||
maps->Clear();
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
HControlInstruction* smi_check = NULL;
|
||||
handled_string = false;
|
||||
|
||||
for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
|
||||
PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
|
||||
if (info.type()->Is(Type::String())) {
|
||||
for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
|
||||
PropertyAccessInfo info(this, access_type, maps->at(i), name);
|
||||
if (info.IsStringType()) {
|
||||
if (handled_string) continue;
|
||||
handled_string = true;
|
||||
}
|
||||
@ -6318,11 +6304,11 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
|
||||
HUnaryControlInstruction* compare;
|
||||
|
||||
HValue* dependency;
|
||||
if (info.type()->Is(Type::Number())) {
|
||||
if (info.IsNumberType()) {
|
||||
Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
|
||||
compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
|
||||
dependency = smi_check;
|
||||
} else if (info.type()->Is(Type::String())) {
|
||||
} else if (info.IsStringType()) {
|
||||
compare = New<HIsStringAndBranch>(object, if_true, if_false);
|
||||
dependency = compare;
|
||||
} else {
|
||||
@ -6331,7 +6317,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
|
||||
}
|
||||
FinishCurrentBlock(compare);
|
||||
|
||||
if (info.type()->Is(Type::Number())) {
|
||||
if (info.IsNumberType()) {
|
||||
GotoNoSimulate(if_true, number_block);
|
||||
if_true = number_block;
|
||||
}
|
||||
@ -6366,7 +6352,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
|
||||
// Finish up. Unconditionally deoptimize if we've handled all the maps we
|
||||
// know about and do not want to handle ones we've never seen. Otherwise
|
||||
// use a generic IC.
|
||||
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
|
||||
if (count == maps->length() && FLAG_deoptimize_uncommon_cases) {
|
||||
FinishExitWithHardDeoptimization(
|
||||
Deoptimizer::kUnknownMapInPolymorphicAccess);
|
||||
} else {
|
||||
@ -6399,22 +6385,21 @@ static bool ComputeReceiverTypes(Expression* expr,
|
||||
HValue* receiver,
|
||||
SmallMapList** t,
|
||||
Zone* zone) {
|
||||
SmallMapList* types = expr->GetReceiverTypes();
|
||||
*t = types;
|
||||
SmallMapList* maps = expr->GetReceiverTypes();
|
||||
*t = maps;
|
||||
bool monomorphic = expr->IsMonomorphic();
|
||||
if (types != NULL && receiver->HasMonomorphicJSObjectType()) {
|
||||
if (maps != NULL && receiver->HasMonomorphicJSObjectType()) {
|
||||
Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
|
||||
types->FilterForPossibleTransitions(root_map);
|
||||
monomorphic = types->length() == 1;
|
||||
maps->FilterForPossibleTransitions(root_map);
|
||||
monomorphic = maps->length() == 1;
|
||||
}
|
||||
return monomorphic &&
|
||||
CanInlinePropertyAccess(IC::MapToType<Type>(types->first(), zone));
|
||||
return monomorphic && CanInlinePropertyAccess(maps->first());
|
||||
}
|
||||
|
||||
|
||||
static bool AreStringTypes(SmallMapList* types) {
|
||||
for (int i = 0; i < types->length(); i++) {
|
||||
if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
|
||||
static bool AreStringTypes(SmallMapList* maps) {
|
||||
for (int i = 0; i < maps->length(); i++) {
|
||||
if (maps->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -7191,8 +7176,8 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
|
||||
DCHECK(!expr->IsPropertyName());
|
||||
HInstruction* instr = NULL;
|
||||
|
||||
SmallMapList* types;
|
||||
bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone());
|
||||
SmallMapList* maps;
|
||||
bool monomorphic = ComputeReceiverTypes(expr, obj, &maps, zone());
|
||||
|
||||
bool force_generic = false;
|
||||
if (expr->GetKeyType() == PROPERTY) {
|
||||
@ -7202,13 +7187,13 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
|
||||
force_generic = true;
|
||||
monomorphic = false;
|
||||
} else if (access_type == STORE &&
|
||||
(monomorphic || (types != NULL && !types->is_empty()))) {
|
||||
(monomorphic || (maps != NULL && !maps->is_empty()))) {
|
||||
// Stores can't be mono/polymorphic if their prototype chain has dictionary
|
||||
// elements. However a receiver map that has dictionary elements itself
|
||||
// should be left to normal mono/poly behavior (the other maps may benefit
|
||||
// from highly optimized stores).
|
||||
for (int i = 0; i < types->length(); i++) {
|
||||
Handle<Map> current_map = types->at(i);
|
||||
for (int i = 0; i < maps->length(); i++) {
|
||||
Handle<Map> current_map = maps->at(i);
|
||||
if (current_map->DictionaryElementsInPrototypeChainOnly()) {
|
||||
force_generic = true;
|
||||
monomorphic = false;
|
||||
@ -7216,13 +7201,13 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
|
||||
}
|
||||
}
|
||||
} else if (access_type == LOAD && !monomorphic &&
|
||||
(types != NULL && !types->is_empty())) {
|
||||
(maps != NULL && !maps->is_empty())) {
|
||||
// Polymorphic loads have to go generic if any of the maps are strings.
|
||||
// If some, but not all of the maps are strings, we should go generic
|
||||
// because polymorphic access wants to key on ElementsKind and isn't
|
||||
// compatible with strings.
|
||||
for (int i = 0; i < types->length(); i++) {
|
||||
Handle<Map> current_map = types->at(i);
|
||||
for (int i = 0; i < maps->length(); i++) {
|
||||
Handle<Map> current_map = maps->at(i);
|
||||
if (current_map->IsStringMap()) {
|
||||
force_generic = true;
|
||||
break;
|
||||
@ -7231,7 +7216,7 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
|
||||
}
|
||||
|
||||
if (monomorphic) {
|
||||
Handle<Map> map = types->first();
|
||||
Handle<Map> map = maps->first();
|
||||
if (!CanInlineElementAccess(map)) {
|
||||
instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key,
|
||||
val));
|
||||
@ -7240,10 +7225,10 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
|
||||
instr = BuildMonomorphicElementAccess(
|
||||
obj, key, val, NULL, map, access_type, expr->GetStoreMode());
|
||||
}
|
||||
} else if (!force_generic && (types != NULL && !types->is_empty())) {
|
||||
return HandlePolymorphicElementAccess(
|
||||
expr, obj, key, val, types, access_type,
|
||||
expr->GetStoreMode(), has_side_effects);
|
||||
} else if (!force_generic && (maps != NULL && !maps->is_empty())) {
|
||||
return HandlePolymorphicElementAccess(expr, obj, key, val, maps,
|
||||
access_type, expr->GetStoreMode(),
|
||||
has_side_effects);
|
||||
} else {
|
||||
if (access_type == STORE) {
|
||||
if (expr->IsAssignment() &&
|
||||
@ -7352,27 +7337,27 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedAccess(
|
||||
Handle<String> name,
|
||||
HValue* value,
|
||||
bool is_uninitialized) {
|
||||
SmallMapList* types;
|
||||
ComputeReceiverTypes(expr, object, &types, zone());
|
||||
DCHECK(types != NULL);
|
||||
SmallMapList* maps;
|
||||
ComputeReceiverTypes(expr, object, &maps, zone());
|
||||
DCHECK(maps != NULL);
|
||||
|
||||
if (types->length() > 0) {
|
||||
PropertyAccessInfo info(this, access, ToType(types->first()), name);
|
||||
if (!info.CanAccessAsMonomorphic(types)) {
|
||||
HandlePolymorphicNamedFieldAccess(
|
||||
access, expr, ast_id, return_id, object, value, types, name);
|
||||
if (maps->length() > 0) {
|
||||
PropertyAccessInfo info(this, access, maps->first(), name);
|
||||
if (!info.CanAccessAsMonomorphic(maps)) {
|
||||
HandlePolymorphicNamedFieldAccess(access, expr, ast_id, return_id, object,
|
||||
value, maps, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HValue* checked_object;
|
||||
// Type::Number() is only supported by polymorphic load/call handling.
|
||||
DCHECK(!info.type()->Is(Type::Number()));
|
||||
DCHECK(!info.IsNumberType());
|
||||
BuildCheckHeapObject(object);
|
||||
if (AreStringTypes(types)) {
|
||||
if (AreStringTypes(maps)) {
|
||||
checked_object =
|
||||
Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
|
||||
} else {
|
||||
checked_object = Add<HCheckMaps>(object, types);
|
||||
checked_object = Add<HCheckMaps>(object, maps);
|
||||
}
|
||||
return BuildMonomorphicAccess(
|
||||
&info, object, checked_object, value, ast_id, return_id);
|
||||
@ -7562,11 +7547,10 @@ inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
Call* expr,
|
||||
HValue* receiver,
|
||||
SmallMapList* types,
|
||||
Handle<String> name) {
|
||||
void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
|
||||
HValue* receiver,
|
||||
SmallMapList* maps,
|
||||
Handle<String> name) {
|
||||
int argument_count = expr->arguments()->length() + 1; // Includes receiver.
|
||||
FunctionSorter order[kMaxCallPolymorphism];
|
||||
|
||||
@ -7575,17 +7559,17 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
int ordered_functions = 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < types->length() && ordered_functions < kMaxCallPolymorphism;
|
||||
for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism;
|
||||
++i) {
|
||||
PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
|
||||
PropertyAccessInfo info(this, LOAD, maps->at(i), name);
|
||||
if (info.CanAccessMonomorphic() && info.IsDataConstant() &&
|
||||
info.constant()->IsJSFunction()) {
|
||||
if (info.type()->Is(Type::String())) {
|
||||
if (info.IsStringType()) {
|
||||
if (handled_string) continue;
|
||||
handled_string = true;
|
||||
}
|
||||
Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
|
||||
if (info.type()->Is(Type::Number())) {
|
||||
if (info.IsNumberType()) {
|
||||
handle_smi = true;
|
||||
}
|
||||
expr->set_target(target);
|
||||
@ -7596,8 +7580,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
|
||||
std::sort(order, order + ordered_functions);
|
||||
|
||||
if (i < types->length()) {
|
||||
types->Clear();
|
||||
if (i < maps->length()) {
|
||||
maps->Clear();
|
||||
ordered_functions = -1;
|
||||
}
|
||||
|
||||
@ -7608,8 +7592,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
|
||||
for (int fn = 0; fn < ordered_functions; ++fn) {
|
||||
int i = order[fn].index();
|
||||
PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
|
||||
if (info.type()->Is(Type::String())) {
|
||||
PropertyAccessInfo info(this, LOAD, maps->at(i), name);
|
||||
if (info.IsStringType()) {
|
||||
if (handled_string) continue;
|
||||
handled_string = true;
|
||||
}
|
||||
@ -7639,17 +7623,17 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
HUnaryControlInstruction* compare;
|
||||
|
||||
Handle<Map> map = info.map();
|
||||
if (info.type()->Is(Type::Number())) {
|
||||
if (info.IsNumberType()) {
|
||||
Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
|
||||
compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
|
||||
} else if (info.type()->Is(Type::String())) {
|
||||
} else if (info.IsStringType()) {
|
||||
compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
|
||||
} else {
|
||||
compare = New<HCompareMap>(receiver, map, if_true, if_false);
|
||||
}
|
||||
FinishCurrentBlock(compare);
|
||||
|
||||
if (info.type()->Is(Type::Number())) {
|
||||
if (info.IsNumberType()) {
|
||||
GotoNoSimulate(if_true, number_block);
|
||||
if_true = number_block;
|
||||
}
|
||||
@ -7662,7 +7646,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
environment()->SetExpressionStackAt(0, function);
|
||||
Push(receiver);
|
||||
CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
||||
bool needs_wrapping = NeedsWrappingFor(info.type(), target);
|
||||
bool needs_wrapping = info.NeedsWrappingFor(target);
|
||||
bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping;
|
||||
if (FLAG_trace_inlining && try_inline) {
|
||||
Handle<JSFunction> caller = current_info()->closure();
|
||||
@ -7698,7 +7682,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
// Finish up. Unconditionally deoptimize if we've handled all the maps we
|
||||
// know about and do not want to handle ones we've never seen. Otherwise
|
||||
// use a generic IC.
|
||||
if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) {
|
||||
if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) {
|
||||
FinishExitWithHardDeoptimization(Deoptimizer::kUnknownMapInPolymorphicCall);
|
||||
} else {
|
||||
Property* prop = expr->expression()->AsProperty();
|
||||
@ -9135,14 +9119,14 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
CHECK_ALIVE(VisitForValue(prop->obj()));
|
||||
HValue* receiver = Top();
|
||||
|
||||
SmallMapList* types;
|
||||
ComputeReceiverTypes(expr, receiver, &types, zone());
|
||||
SmallMapList* maps;
|
||||
ComputeReceiverTypes(expr, receiver, &maps, zone());
|
||||
|
||||
if (prop->key()->IsPropertyName() && types->length() > 0) {
|
||||
if (prop->key()->IsPropertyName() && maps->length() > 0) {
|
||||
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
|
||||
PropertyAccessInfo info(this, LOAD, ToType(types->first()), name);
|
||||
if (!info.CanAccessAsMonomorphic(types)) {
|
||||
HandlePolymorphicCallNamed(expr, receiver, types, name);
|
||||
PropertyAccessInfo info(this, LOAD, maps->first(), name);
|
||||
if (!info.CanAccessAsMonomorphic(maps)) {
|
||||
HandlePolymorphicCallNamed(expr, receiver, maps, name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -9171,7 +9155,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
if (TryIndirectCall(expr)) return;
|
||||
CHECK_ALIVE(VisitExpressions(expr->arguments()));
|
||||
|
||||
Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
|
||||
Handle<Map> map = maps->length() == 1 ? maps->first() : Handle<Map>();
|
||||
if (TryInlineBuiltinMethodCall(expr, known_function, map,
|
||||
expr->arguments()->length())) {
|
||||
if (FLAG_trace_inlining) {
|
||||
@ -9181,10 +9165,10 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (TryInlineApiMethodCall(expr, receiver, types)) return;
|
||||
if (TryInlineApiMethodCall(expr, receiver, maps)) return;
|
||||
|
||||
// Wrap the receiver if necessary.
|
||||
if (NeedsWrappingFor(ToType(types->first()), known_function)) {
|
||||
if (NeedsWrapping(maps->first(), known_function)) {
|
||||
// Since HWrapReceiver currently cannot actually wrap numbers and
|
||||
// strings, use the regular CallFunctionStub for method calls to wrap
|
||||
// the receiver.
|
||||
|
@ -2282,8 +2282,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
AST_NODE_LIST(DECLARE_VISIT)
|
||||
#undef DECLARE_VISIT
|
||||
|
||||
Type* ToType(Handle<Map> map);
|
||||
|
||||
private:
|
||||
// Helpers for flow graph construction.
|
||||
enum GlobalPropertyAccess {
|
||||
@ -2434,16 +2432,15 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
class PropertyAccessInfo {
|
||||
public:
|
||||
PropertyAccessInfo(HOptimizedGraphBuilder* builder,
|
||||
PropertyAccessType access_type,
|
||||
Type* type,
|
||||
PropertyAccessType access_type, Handle<Map> map,
|
||||
Handle<String> name)
|
||||
: lookup_(builder->isolate()),
|
||||
builder_(builder),
|
||||
access_type_(access_type),
|
||||
type_(type),
|
||||
map_(map),
|
||||
name_(name),
|
||||
field_type_(HType::Tagged()),
|
||||
access_(HObjectAccess::ForMap()) { }
|
||||
access_(HObjectAccess::ForMap()) {}
|
||||
|
||||
// Checkes whether this PropertyAccessInfo can be handled as a monomorphic
|
||||
// load named. It additionally fills in the fields necessary to generate the
|
||||
@ -2458,22 +2455,23 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
// PropertyAccessInfo is built for types->first().
|
||||
bool CanAccessAsMonomorphic(SmallMapList* types);
|
||||
|
||||
bool NeedsWrappingFor(Handle<JSFunction> target) const;
|
||||
|
||||
Handle<Map> map();
|
||||
Type* type() const { return type_; }
|
||||
Handle<String> name() const { return name_; }
|
||||
|
||||
bool IsJSObjectFieldAccessor() {
|
||||
int offset; // unused
|
||||
return Accessors::IsJSObjectFieldAccessor<Type>(type_, name_, &offset);
|
||||
return Accessors::IsJSObjectFieldAccessor(map(), name_, &offset);
|
||||
}
|
||||
|
||||
bool GetJSObjectFieldAccess(HObjectAccess* access) {
|
||||
int offset;
|
||||
if (Accessors::IsJSObjectFieldAccessor<Type>(type_, name_, &offset)) {
|
||||
if (type_->Is(Type::String())) {
|
||||
if (Accessors::IsJSObjectFieldAccessor(map(), name_, &offset)) {
|
||||
if (IsStringType()) {
|
||||
DCHECK(String::Equals(isolate()->factory()->length_string(), name_));
|
||||
*access = HObjectAccess::ForStringLength();
|
||||
} else if (type_->Is(Type::Array())) {
|
||||
} else if (IsArrayType()) {
|
||||
DCHECK(String::Equals(isolate()->factory()->length_string(), name_));
|
||||
*access = HObjectAccess::ForArrayLength(map()->elements_kind());
|
||||
} else {
|
||||
@ -2506,6 +2504,11 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
bool IsConfigurable() const { return lookup_.IsConfigurable(); }
|
||||
bool IsReadOnly() const { return lookup_.IsReadOnly(); }
|
||||
|
||||
bool IsStringType() { return map_->instance_type() < FIRST_NONSTRING_TYPE; }
|
||||
bool IsNumberType() { return map_->instance_type() == HEAP_NUMBER_TYPE; }
|
||||
bool IsValueWrapped() { return IsStringType() || IsNumberType(); }
|
||||
bool IsArrayType() { return map_->instance_type() == JS_ARRAY_TYPE; }
|
||||
|
||||
private:
|
||||
Handle<Object> GetAccessorsFromMap(Handle<Map> map) const {
|
||||
return handle(lookup_.GetValueFromMap(*map), isolate());
|
||||
@ -2524,7 +2527,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
}
|
||||
Representation representation() const { return lookup_.representation(); }
|
||||
|
||||
Type* ToType(Handle<Map> map) { return builder_->ToType(map); }
|
||||
Zone* zone() { return builder_->zone(); }
|
||||
CompilationInfo* top_info() { return builder_->top_info(); }
|
||||
CompilationInfo* current_info() { return builder_->current_info(); }
|
||||
@ -2543,7 +2545,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
LookupResult lookup_;
|
||||
HOptimizedGraphBuilder* builder_;
|
||||
PropertyAccessType access_type_;
|
||||
Type* type_;
|
||||
Handle<Map> map_;
|
||||
Handle<String> name_;
|
||||
Handle<JSObject> holder_;
|
||||
Handle<JSFunction> accessor_;
|
||||
|
@ -17,9 +17,8 @@ namespace internal {
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : receiver
|
||||
// -- r2 : name
|
||||
@ -32,7 +31,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
DCHECK(!holder.is(scratch));
|
||||
DCHECK(!receiver.is(scratch));
|
||||
// Call the JavaScript getter with the receiver on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Swap in the global receiver.
|
||||
__ ldr(scratch,
|
||||
FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
@ -57,9 +56,8 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
|
||||
|
||||
void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
@ -74,7 +72,7 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
DCHECK(!receiver.is(scratch));
|
||||
DCHECK(!value().is(scratch));
|
||||
// Call the JavaScript setter with receiver and value on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Swap in the global receiver.
|
||||
__ ldr(scratch,
|
||||
FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
@ -415,7 +413,7 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Register object_reg, Register holder_reg, Register scratch1,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
Handle<Map> receiver_map = map();
|
||||
|
||||
// Make sure there's no overlap between holder and object registers.
|
||||
DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
|
||||
@ -427,8 +425,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type()->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
if (receiver_map->IsJSGlobalObjectMap()) {
|
||||
current = isolate()->global_object();
|
||||
}
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
|
@ -32,7 +32,7 @@ void PropertyICCompiler::GenerateRuntimeSetProperty(
|
||||
#define __ ACCESS_MASM(masm())
|
||||
|
||||
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(MapHandleList* maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
@ -59,7 +59,7 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
}
|
||||
|
||||
Label number_case;
|
||||
Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
|
||||
Label* smi_target = IncludesNumberMap(maps) ? &number_case : &miss;
|
||||
__ JumpIfSmi(receiver(), smi_target);
|
||||
|
||||
// Polymorphic keyed stores may use the map register
|
||||
@ -67,17 +67,16 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
DCHECK(kind() != Code::KEYED_STORE_IC ||
|
||||
map_reg.is(ElementTransitionAndStoreDescriptor::MapRegister()));
|
||||
|
||||
int receiver_count = types->length();
|
||||
int receiver_count = maps->length();
|
||||
int number_of_handled_maps = 0;
|
||||
__ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
for (int current = 0; current < receiver_count; ++current) {
|
||||
Handle<HeapType> type = types->at(current);
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
Handle<Map> map = maps->at(current);
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (type->Is(HeapType::Number())) {
|
||||
if (map->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
}
|
||||
|
@ -223,9 +223,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
|
||||
|
||||
|
||||
void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
@ -241,7 +240,7 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
DCHECK(!AreAliased(receiver, scratch));
|
||||
DCHECK(!AreAliased(value(), scratch));
|
||||
// Call the JavaScript setter with receiver and value on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Swap in the global receiver.
|
||||
__ Ldr(scratch,
|
||||
FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
@ -269,9 +268,8 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
|
||||
@ -279,7 +277,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
DCHECK(!AreAliased(holder, scratch));
|
||||
DCHECK(!AreAliased(receiver, scratch));
|
||||
// Call the JavaScript getter with the receiver on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Swap in the global receiver.
|
||||
__ Ldr(scratch,
|
||||
FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
@ -465,7 +463,7 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Register object_reg, Register holder_reg, Register scratch1,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
Handle<Map> receiver_map = map();
|
||||
|
||||
// object_reg and holder_reg registers can alias.
|
||||
DCHECK(!AreAliased(object_reg, scratch1, scratch2));
|
||||
@ -476,8 +474,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type()->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
if (receiver_map->IsJSGlobalObjectMap()) {
|
||||
current = isolate()->global_object();
|
||||
}
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
|
@ -33,7 +33,7 @@ void PropertyICCompiler::GenerateRuntimeSetProperty(
|
||||
#define __ ACCESS_MASM(masm())
|
||||
|
||||
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(MapHandleList* maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
@ -59,7 +59,7 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
}
|
||||
|
||||
Label number_case;
|
||||
Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
|
||||
Label* smi_target = IncludesNumberMap(maps) ? &number_case : &miss;
|
||||
__ JumpIfSmi(receiver(), smi_target);
|
||||
|
||||
// Polymorphic keyed stores may use the map register
|
||||
@ -67,18 +67,17 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
DCHECK(kind() != Code::KEYED_STORE_IC ||
|
||||
map_reg.is(ElementTransitionAndStoreDescriptor::MapRegister()));
|
||||
__ Ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||
int receiver_count = types->length();
|
||||
int receiver_count = maps->length();
|
||||
int number_of_handled_maps = 0;
|
||||
for (int current = 0; current < receiver_count; ++current) {
|
||||
Handle<HeapType> type = types->at(current);
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
Handle<Map> map = maps->at(current);
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
Label try_next;
|
||||
__ B(ne, &try_next);
|
||||
if (type->Is(HeapType::Number())) {
|
||||
if (map->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ Bind(&number_case);
|
||||
}
|
||||
|
@ -51,12 +51,12 @@ bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
|
||||
DCHECK(is_simple_api_call());
|
||||
if (!receiver->IsHeapObject()) return false;
|
||||
Handle<Map> map(HeapObject::cast(*receiver)->map());
|
||||
return IsCompatibleReceiverType(map, holder);
|
||||
return IsCompatibleReceiverMap(map, holder);
|
||||
}
|
||||
|
||||
|
||||
bool CallOptimization::IsCompatibleReceiverType(Handle<Map> map,
|
||||
Handle<JSObject> holder) const {
|
||||
bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
|
||||
Handle<JSObject> holder) const {
|
||||
HolderLookup holder_lookup;
|
||||
Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
|
||||
switch (holder_lookup) {
|
||||
|
@ -46,8 +46,8 @@ class CallOptimization BASE_EMBEDDED {
|
||||
Handle<JSObject> holder) const;
|
||||
|
||||
// Check if the api holder is between the receiver and the holder.
|
||||
bool IsCompatibleReceiverType(Handle<Map> receiver_map,
|
||||
Handle<JSObject> holder) const;
|
||||
bool IsCompatibleReceiverMap(Handle<Map> receiver_map,
|
||||
Handle<JSObject> holder) const;
|
||||
|
||||
private:
|
||||
void Initialize(Handle<JSFunction> function);
|
||||
|
@ -26,9 +26,8 @@ Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
|
||||
|
||||
|
||||
Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
|
||||
Handle<Name> name, Handle<HeapType> type) {
|
||||
Handle<Name> name, Handle<Map> receiver_map) {
|
||||
Isolate* isolate = name->GetIsolate();
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type, isolate);
|
||||
if (receiver_map->prototype()->IsNull()) {
|
||||
// TODO(jkummerow/verwaest): If there is no prototype and the property
|
||||
// is nonexistent, introduce a builtin to handle this (fast properties
|
||||
@ -37,7 +36,7 @@ Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
|
||||
}
|
||||
CacheHolderFlag flag;
|
||||
Handle<Map> stub_holder_map =
|
||||
IC::GetHandlerCacheHolder(*type, false, isolate, &flag);
|
||||
IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
|
||||
|
||||
// If no dictionary mode objects are present in the prototype chain, the load
|
||||
// nonexistent IC stub can be shared for all names for a given map and we use
|
||||
@ -62,7 +61,7 @@ Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
|
||||
cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
|
||||
if (!handler.is_null()) return handler;
|
||||
|
||||
NamedLoadHandlerCompiler compiler(isolate, type, last, flag);
|
||||
NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
|
||||
handler = compiler.CompileLoadNonexistent(cache_name);
|
||||
Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
|
||||
return handler;
|
||||
@ -82,11 +81,6 @@ Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
|
||||
}
|
||||
|
||||
|
||||
void PropertyHandlerCompiler::set_type_for_object(Handle<Object> object) {
|
||||
type_ = IC::CurrentTypeOf(object, isolate());
|
||||
}
|
||||
|
||||
|
||||
#define __ ACCESS_MASM(masm())
|
||||
|
||||
|
||||
@ -95,13 +89,13 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
Label* miss) {
|
||||
PrototypeCheckType check_type = CHECK_ALL_MAPS;
|
||||
int function_index = -1;
|
||||
if (type()->Is(HeapType::String())) {
|
||||
if (map()->instance_type() < FIRST_NONSTRING_TYPE) {
|
||||
function_index = Context::STRING_FUNCTION_INDEX;
|
||||
} else if (type()->Is(HeapType::Symbol())) {
|
||||
} else if (map()->instance_type() == SYMBOL_TYPE) {
|
||||
function_index = Context::SYMBOL_FUNCTION_INDEX;
|
||||
} else if (type()->Is(HeapType::Number())) {
|
||||
} else if (map()->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
function_index = Context::NUMBER_FUNCTION_INDEX;
|
||||
} else if (type()->Is(HeapType::Boolean())) {
|
||||
} else if (*map() == isolate()->heap()->boolean_map()) {
|
||||
function_index = Context::BOOLEAN_FUNCTION_INDEX;
|
||||
} else {
|
||||
check_type = SKIP_RECEIVER;
|
||||
@ -112,7 +106,8 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
scratch1(), miss);
|
||||
Object* function = isolate()->native_context()->get(function_index);
|
||||
Object* prototype = JSFunction::cast(function)->instance_prototype();
|
||||
set_type_for_object(handle(prototype, isolate()));
|
||||
Handle<Map> map(JSObject::cast(prototype)->map());
|
||||
set_map(map);
|
||||
object_reg = scratch1();
|
||||
}
|
||||
|
||||
@ -155,7 +150,7 @@ void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
|
||||
Handle<Map> last_map;
|
||||
if (holder().is_null()) {
|
||||
holder_reg = receiver();
|
||||
last_map = IC::TypeToMap(*type(), isolate());
|
||||
last_map = map();
|
||||
// If |type| has null as its prototype, |holder()| is
|
||||
// Handle<JSObject>::null().
|
||||
DCHECK(last_map->prototype() == isolate()->heap()->null_value());
|
||||
@ -168,7 +163,7 @@ void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
|
||||
if (last_map->IsJSGlobalObjectMap()) {
|
||||
Handle<JSGlobalObject> global =
|
||||
holder().is_null()
|
||||
? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
|
||||
? Handle<JSGlobalObject>::cast(isolate()->global_object())
|
||||
: Handle<JSGlobalObject>::cast(holder());
|
||||
GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
|
||||
} else {
|
||||
@ -236,8 +231,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
|
||||
int accessor_index) {
|
||||
DCHECK(call_optimization.is_simple_api_call());
|
||||
Register holder = Frontend(name);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
|
||||
GenerateApiAccessorCall(masm(), call_optimization, receiver_map, receiver(),
|
||||
GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
|
||||
scratch2(), false, no_reg, holder, accessor_index);
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
@ -296,8 +290,8 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(accessors);
|
||||
inline_followup = info->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(
|
||||
isolate(), info, type());
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverMap(
|
||||
isolate(), info, map());
|
||||
} else if (accessors->IsAccessorPair()) {
|
||||
Handle<JSObject> property_holder(it->GetHolder<JSObject>());
|
||||
Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
|
||||
@ -306,9 +300,9 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
|
||||
if (!property_holder->HasFastProperties()) break;
|
||||
auto function = Handle<JSFunction>::cast(getter);
|
||||
CallOptimization call_optimization(function);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
|
||||
Handle<Map> receiver_map = map();
|
||||
inline_followup = call_optimization.is_simple_api_call() &&
|
||||
call_optimization.IsCompatibleReceiverType(
|
||||
call_optimization.IsCompatibleReceiverMap(
|
||||
receiver_map, property_holder);
|
||||
}
|
||||
}
|
||||
@ -335,7 +329,8 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
LookupIterator* it, Register interceptor_reg) {
|
||||
Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
|
||||
|
||||
set_type_for_object(holder());
|
||||
Handle<Map> holder_map(holder()->map());
|
||||
set_map(holder_map);
|
||||
set_holder(real_named_property_holder);
|
||||
|
||||
Label miss;
|
||||
@ -369,8 +364,7 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
auto function = handle(JSFunction::cast(
|
||||
AccessorPair::cast(*it->GetAccessors())->getter()));
|
||||
CallOptimization call_optimization(function);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
|
||||
GenerateApiAccessorCall(masm(), call_optimization, receiver_map,
|
||||
GenerateApiAccessorCall(masm(), call_optimization, holder_map,
|
||||
receiver(), scratch2(), false, no_reg, reg,
|
||||
it->GetAccessorIndex());
|
||||
}
|
||||
@ -381,7 +375,7 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
|
||||
Handle<Name> name, int accessor_index, int expected_arguments) {
|
||||
Register holder = Frontend(name);
|
||||
GenerateLoadViaGetter(masm(), type(), receiver(), holder, accessor_index,
|
||||
GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
|
||||
expected_arguments, scratch2());
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
}
|
||||
@ -471,7 +465,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
|
||||
Handle<JSObject> object, Handle<Name> name, int accessor_index,
|
||||
int expected_arguments) {
|
||||
Register holder = Frontend(name);
|
||||
GenerateStoreViaSetter(masm(), type(), receiver(), holder, accessor_index,
|
||||
GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
|
||||
expected_arguments, scratch2());
|
||||
|
||||
return GetCode(kind(), Code::FAST, name);
|
||||
|
@ -21,11 +21,10 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
|
||||
CacheHolderFlag cache_holder, Code::StubType type);
|
||||
|
||||
protected:
|
||||
PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind,
|
||||
Handle<HeapType> type, Handle<JSObject> holder,
|
||||
CacheHolderFlag cache_holder)
|
||||
PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map,
|
||||
Handle<JSObject> holder, CacheHolderFlag cache_holder)
|
||||
: PropertyAccessCompiler(isolate, kind, cache_holder),
|
||||
type_(type),
|
||||
map_(map),
|
||||
holder_(holder) {}
|
||||
|
||||
virtual ~PropertyHandlerCompiler() {}
|
||||
@ -99,23 +98,23 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
|
||||
PrototypeCheckType check = CHECK_ALL_MAPS);
|
||||
|
||||
Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name);
|
||||
void set_type_for_object(Handle<Object> object);
|
||||
void set_holder(Handle<JSObject> holder) { holder_ = holder; }
|
||||
Handle<HeapType> type() const { return type_; }
|
||||
Handle<Map> map() const { return map_; }
|
||||
void set_map(Handle<Map> map) { map_ = map; }
|
||||
Handle<JSObject> holder() const { return holder_; }
|
||||
|
||||
private:
|
||||
Handle<HeapType> type_;
|
||||
Handle<Map> map_;
|
||||
Handle<JSObject> holder_;
|
||||
};
|
||||
|
||||
|
||||
class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
|
||||
public:
|
||||
NamedLoadHandlerCompiler(Isolate* isolate, Handle<HeapType> type,
|
||||
NamedLoadHandlerCompiler(Isolate* isolate, Handle<Map> map,
|
||||
Handle<JSObject> holder,
|
||||
CacheHolderFlag cache_holder)
|
||||
: PropertyHandlerCompiler(isolate, Code::LOAD_IC, type, holder,
|
||||
: PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder,
|
||||
cache_holder) {}
|
||||
|
||||
virtual ~NamedLoadHandlerCompiler() {}
|
||||
@ -144,16 +143,16 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
|
||||
|
||||
// Static interface
|
||||
static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
|
||||
Handle<HeapType> type);
|
||||
Handle<Map> map);
|
||||
|
||||
static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<HeapType> type,
|
||||
static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map,
|
||||
Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments,
|
||||
Register scratch);
|
||||
|
||||
static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) {
|
||||
GenerateLoadViaGetter(masm, Handle<HeapType>::null(), no_reg, no_reg, -1,
|
||||
-1, no_reg);
|
||||
GenerateLoadViaGetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
|
||||
no_reg);
|
||||
}
|
||||
|
||||
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
|
||||
@ -213,9 +212,9 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
|
||||
|
||||
class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
|
||||
public:
|
||||
explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<HeapType> type,
|
||||
explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
|
||||
Handle<JSObject> holder)
|
||||
: PropertyHandlerCompiler(isolate, Code::STORE_IC, type, holder,
|
||||
: PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
|
||||
kCacheOnReceiver) {}
|
||||
|
||||
virtual ~NamedStoreHandlerCompiler() {}
|
||||
@ -233,14 +232,14 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
|
||||
int expected_arguments);
|
||||
Handle<Code> CompileStoreInterceptor(Handle<Name> name);
|
||||
|
||||
static void GenerateStoreViaSetter(MacroAssembler* masm,
|
||||
Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index,
|
||||
int expected_arguments, Register scratch);
|
||||
static void GenerateStoreViaSetter(MacroAssembler* masm, Handle<Map> map,
|
||||
Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments,
|
||||
Register scratch);
|
||||
|
||||
static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) {
|
||||
GenerateStoreViaSetter(masm, Handle<HeapType>::null(), no_reg, no_reg, -1,
|
||||
-1, no_reg);
|
||||
GenerateStoreViaSetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
|
||||
no_reg);
|
||||
}
|
||||
|
||||
static void GenerateSlow(MacroAssembler* masm);
|
||||
@ -284,8 +283,8 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler {
|
||||
public:
|
||||
explicit ElementHandlerCompiler(Isolate* isolate)
|
||||
: PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
|
||||
Handle<HeapType>::null(),
|
||||
Handle<JSObject>::null(), kCacheOnReceiver) {}
|
||||
Handle<Map>::null(), Handle<JSObject>::null(),
|
||||
kCacheOnReceiver) {}
|
||||
|
||||
virtual ~ElementHandlerCompiler() {}
|
||||
|
||||
|
@ -17,9 +17,8 @@ namespace internal {
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
|
||||
@ -27,7 +26,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
DCHECK(!holder.is(scratch));
|
||||
DCHECK(!receiver.is(scratch));
|
||||
// Call the JavaScript getter with the receiver on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Swap in the global receiver.
|
||||
__ mov(scratch,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
@ -237,9 +236,8 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
|
||||
|
||||
void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -----------------------------------
|
||||
@ -254,7 +252,7 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
DCHECK(!receiver.is(scratch));
|
||||
DCHECK(!value().is(scratch));
|
||||
// Call the JavaScript setter with receiver and value on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
__ mov(scratch,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
receiver = scratch;
|
||||
@ -418,7 +416,7 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Register object_reg, Register holder_reg, Register scratch1,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
Handle<Map> receiver_map = map();
|
||||
|
||||
// Make sure there's no overlap between holder and object registers.
|
||||
DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
|
||||
@ -430,8 +428,9 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type()->IsConstant())
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
if (receiver_map->IsJSGlobalObjectMap()) {
|
||||
current = isolate()->global_object();
|
||||
}
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
Handle<Map> holder_map(holder()->map());
|
||||
|
@ -36,7 +36,7 @@ void PropertyICCompiler::GenerateRuntimeSetProperty(
|
||||
#undef __
|
||||
#define __ ACCESS_MASM(masm())
|
||||
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(MapHandleList* maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
@ -63,7 +63,7 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
}
|
||||
|
||||
Label number_case;
|
||||
Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
|
||||
Label* smi_target = IncludesNumberMap(maps) ? &number_case : &miss;
|
||||
__ JumpIfSmi(receiver(), smi_target);
|
||||
|
||||
// Polymorphic keyed stores may use the map register
|
||||
@ -71,16 +71,15 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
DCHECK(kind() != Code::KEYED_STORE_IC ||
|
||||
map_reg.is(ElementTransitionAndStoreDescriptor::MapRegister()));
|
||||
__ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
int receiver_count = types->length();
|
||||
int receiver_count = maps->length();
|
||||
int number_of_handled_maps = 0;
|
||||
for (int current = 0; current < receiver_count; ++current) {
|
||||
Handle<HeapType> type = types->at(current);
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
Handle<Map> map = maps->at(current);
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (type->Is(HeapType::Number())) {
|
||||
if (map->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
}
|
||||
|
@ -25,30 +25,30 @@ Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
|
||||
}
|
||||
|
||||
|
||||
bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) {
|
||||
for (int i = 0; i < types->length(); ++i) {
|
||||
if (types->at(i)->Is(HeapType::Number())) return true;
|
||||
bool PropertyICCompiler::IncludesNumberMap(MapHandleList* maps) {
|
||||
for (int i = 0; i < maps->length(); ++i) {
|
||||
if (maps->at(i)->instance_type() == HEAP_NUMBER_TYPE) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type,
|
||||
Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<Map> map,
|
||||
Handle<Code> handler,
|
||||
Handle<Name> name,
|
||||
IcCheckType check) {
|
||||
TypeHandleList types(1);
|
||||
MapHandleList maps(1);
|
||||
CodeHandleList handlers(1);
|
||||
types.Add(type);
|
||||
maps.Add(map);
|
||||
handlers.Add(handler);
|
||||
Code::StubType stub_type = handler->type();
|
||||
return CompilePolymorphic(&types, &handlers, name, stub_type, check);
|
||||
return CompilePolymorphic(&maps, &handlers, name, stub_type, check);
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> PropertyICCompiler::ComputeMonomorphic(
|
||||
Code::Kind kind, Handle<Name> name, Handle<HeapType> type,
|
||||
Handle<Code> handler, ExtraICState extra_ic_state) {
|
||||
Code::Kind kind, Handle<Name> name, Handle<Map> map, Handle<Code> handler,
|
||||
ExtraICState extra_ic_state) {
|
||||
Isolate* isolate = name->GetIsolate();
|
||||
if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) ||
|
||||
handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) {
|
||||
@ -56,7 +56,7 @@ Handle<Code> PropertyICCompiler::ComputeMonomorphic(
|
||||
}
|
||||
|
||||
CacheHolderFlag flag;
|
||||
Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate, &flag);
|
||||
Handle<Map> stub_holder = IC::GetICCacheHolder(map, isolate, &flag);
|
||||
if (kind == Code::KEYED_STORE_IC) {
|
||||
// Always set the "property" bit.
|
||||
extra_ic_state =
|
||||
@ -72,14 +72,14 @@ Handle<Code> PropertyICCompiler::ComputeMonomorphic(
|
||||
// There are multiple string maps that all use the same prototype. That
|
||||
// prototype cannot hold multiple handlers, one for each of the string maps,
|
||||
// for a single name. Hence, turn off caching of the IC.
|
||||
bool can_be_cached = !type->Is(HeapType::String());
|
||||
bool can_be_cached = map->instance_type() >= FIRST_NONSTRING_TYPE;
|
||||
if (can_be_cached) {
|
||||
ic = Find(name, stub_holder, kind, extra_ic_state, flag);
|
||||
if (!ic.is_null()) return ic;
|
||||
}
|
||||
|
||||
PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
|
||||
ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY);
|
||||
ic = ic_compiler.CompileMonomorphic(map, handler, name, PROPERTY);
|
||||
|
||||
if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
|
||||
return ic;
|
||||
@ -98,9 +98,8 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
|
||||
|
||||
Handle<Code> stub = ComputeKeyedLoadMonomorphicHandler(receiver_map);
|
||||
PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
|
||||
Handle<Code> code =
|
||||
compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
|
||||
isolate->factory()->empty_string(), ELEMENT);
|
||||
Handle<Code> code = compiler.CompileMonomorphic(
|
||||
receiver_map, stub, isolate->factory()->empty_string(), ELEMENT);
|
||||
|
||||
Map::UpdateCodeCache(receiver_map, name, code);
|
||||
return code;
|
||||
@ -256,7 +255,6 @@ Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
|
||||
}
|
||||
|
||||
|
||||
// TODO(verwaest): Change this method so it takes in a TypeHandleList.
|
||||
Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
|
||||
MapHandleList* receiver_maps) {
|
||||
Isolate* isolate = receiver_maps->at(0)->GetIsolate();
|
||||
@ -267,17 +265,13 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
|
||||
Handle<Object> probe = cache->Lookup(receiver_maps, flags);
|
||||
if (probe->IsCode()) return Handle<Code>::cast(probe);
|
||||
|
||||
TypeHandleList types(receiver_maps->length());
|
||||
for (int i = 0; i < receiver_maps->length(); i++) {
|
||||
types.Add(HeapType::Class(receiver_maps->at(i), isolate));
|
||||
}
|
||||
CodeHandleList handlers(receiver_maps->length());
|
||||
ElementHandlerCompiler compiler(isolate);
|
||||
compiler.CompileElementHandlers(receiver_maps, &handlers);
|
||||
PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC);
|
||||
Handle<Code> code = ic_compiler.CompilePolymorphic(
|
||||
&types, &handlers, isolate->factory()->empty_string(), Code::NORMAL,
|
||||
ELEMENT);
|
||||
receiver_maps, &handlers, isolate->factory()->empty_string(),
|
||||
Code::NORMAL, ELEMENT);
|
||||
|
||||
isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
|
||||
|
||||
@ -287,13 +281,13 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
|
||||
|
||||
|
||||
Handle<Code> PropertyICCompiler::ComputePolymorphic(
|
||||
Code::Kind kind, TypeHandleList* types, CodeHandleList* handlers,
|
||||
int valid_types, Handle<Name> name, ExtraICState extra_ic_state) {
|
||||
Code::Kind kind, MapHandleList* maps, CodeHandleList* handlers,
|
||||
int valid_maps, Handle<Name> name, ExtraICState extra_ic_state) {
|
||||
Handle<Code> handler = handlers->at(0);
|
||||
Code::StubType type = valid_types == 1 ? handler->type() : Code::NORMAL;
|
||||
Code::StubType type = valid_maps == 1 ? handler->type() : Code::NORMAL;
|
||||
DCHECK(kind == Code::LOAD_IC || kind == Code::STORE_IC);
|
||||
PropertyICCompiler ic_compiler(name->GetIsolate(), kind, extra_ic_state);
|
||||
return ic_compiler.CompilePolymorphic(types, handlers, name, type, PROPERTY);
|
||||
return ic_compiler.CompilePolymorphic(maps, handlers, name, type, PROPERTY);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,10 +24,9 @@ class PropertyICCompiler : public PropertyAccessCompiler {
|
||||
ExtraICState extra_state);
|
||||
|
||||
static Handle<Code> ComputeMonomorphic(Code::Kind kind, Handle<Name> name,
|
||||
Handle<HeapType> type,
|
||||
Handle<Code> handler,
|
||||
Handle<Map> map, Handle<Code> handler,
|
||||
ExtraICState extra_ic_state);
|
||||
static Handle<Code> ComputePolymorphic(Code::Kind kind, TypeHandleList* types,
|
||||
static Handle<Code> ComputePolymorphic(Code::Kind kind, MapHandleList* maps,
|
||||
CodeHandleList* handlers,
|
||||
int number_of_valid_maps,
|
||||
Handle<Name> name,
|
||||
@ -76,11 +75,11 @@ class PropertyICCompiler : public PropertyAccessCompiler {
|
||||
Handle<Code> CompileStoreGeneric(Code::Flags flags);
|
||||
Handle<Code> CompileStoreMegamorphic(Code::Flags flags);
|
||||
|
||||
Handle<Code> CompileMonomorphic(Handle<HeapType> type, Handle<Code> handler,
|
||||
Handle<Code> CompileMonomorphic(Handle<Map> map, Handle<Code> handler,
|
||||
Handle<Name> name, IcCheckType check);
|
||||
Handle<Code> CompilePolymorphic(TypeHandleList* types,
|
||||
CodeHandleList* handlers, Handle<Name> name,
|
||||
Code::StubType type, IcCheckType check);
|
||||
Handle<Code> CompilePolymorphic(MapHandleList* maps, CodeHandleList* handlers,
|
||||
Handle<Name> name, Code::StubType type,
|
||||
IcCheckType check);
|
||||
|
||||
Handle<Code> CompileKeyedStoreMonomorphic(Handle<Map> receiver_map,
|
||||
KeyedAccessStoreMode store_mode);
|
||||
@ -90,7 +89,7 @@ class PropertyICCompiler : public PropertyAccessCompiler {
|
||||
CodeHandleList* handler_stubs,
|
||||
MapHandleList* transitioned_maps);
|
||||
|
||||
bool IncludesNumberType(TypeHandleList* types);
|
||||
bool IncludesNumberMap(MapHandleList* maps);
|
||||
|
||||
Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name,
|
||||
InlineCacheState state = MONOMORPHIC);
|
||||
|
@ -161,15 +161,15 @@ Code* IC::raw_target() const {
|
||||
void IC::UpdateTarget() { target_ = handle(raw_target(), isolate_); }
|
||||
|
||||
|
||||
template <class TypeClass>
|
||||
JSFunction* IC::GetRootConstructor(TypeClass* type, Context* native_context) {
|
||||
if (type->Is(TypeClass::Boolean())) {
|
||||
JSFunction* IC::GetRootConstructor(Map* receiver_map, Context* native_context) {
|
||||
Isolate* isolate = receiver_map->GetIsolate();
|
||||
if (receiver_map == isolate->heap()->boolean_map()) {
|
||||
return native_context->boolean_function();
|
||||
} else if (type->Is(TypeClass::Number())) {
|
||||
} else if (receiver_map->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
return native_context->number_function();
|
||||
} else if (type->Is(TypeClass::String())) {
|
||||
} else if (receiver_map->instance_type() < FIRST_NONSTRING_TYPE) {
|
||||
return native_context->string_function();
|
||||
} else if (type->Is(TypeClass::Symbol())) {
|
||||
} else if (receiver_map->instance_type() == SYMBOL_TYPE) {
|
||||
return native_context->symbol_function();
|
||||
} else {
|
||||
return NULL;
|
||||
@ -177,15 +177,15 @@ JSFunction* IC::GetRootConstructor(TypeClass* type, Context* native_context) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> IC::GetHandlerCacheHolder(HeapType* type, bool receiver_is_holder,
|
||||
Isolate* isolate, CacheHolderFlag* flag) {
|
||||
Handle<Map> receiver_map = TypeToMap(type, isolate);
|
||||
Handle<Map> IC::GetHandlerCacheHolder(Handle<Map> receiver_map,
|
||||
bool receiver_is_holder, Isolate* isolate,
|
||||
CacheHolderFlag* flag) {
|
||||
if (receiver_is_holder) {
|
||||
*flag = kCacheOnReceiver;
|
||||
return receiver_map;
|
||||
}
|
||||
Context* native_context = *isolate->native_context();
|
||||
JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
|
||||
JSFunction* builtin_ctor = GetRootConstructor(*receiver_map, native_context);
|
||||
if (builtin_ctor != NULL) {
|
||||
*flag = kCacheOnPrototypeReceiverIsPrimitive;
|
||||
return handle(HeapObject::cast(builtin_ctor->instance_prototype())->map());
|
||||
@ -198,16 +198,16 @@ Handle<Map> IC::GetHandlerCacheHolder(HeapType* type, bool receiver_is_holder,
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate,
|
||||
Handle<Map> IC::GetICCacheHolder(Handle<Map> map, Isolate* isolate,
|
||||
CacheHolderFlag* flag) {
|
||||
Context* native_context = *isolate->native_context();
|
||||
JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
|
||||
JSFunction* builtin_ctor = GetRootConstructor(*map, native_context);
|
||||
if (builtin_ctor != NULL) {
|
||||
*flag = kCacheOnPrototype;
|
||||
return handle(builtin_ctor->initial_map());
|
||||
}
|
||||
*flag = kCacheOnReceiver;
|
||||
return TypeToMap(type, isolate);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
|
210
src/ic/ic.cc
210
src/ic/ic.cc
@ -265,11 +265,10 @@ static void LookupForRead(LookupIterator* it) {
|
||||
bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
||||
Handle<String> name) {
|
||||
if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
|
||||
Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate());
|
||||
if (UseVector()) {
|
||||
maybe_handler_ = nexus()->FindHandlerForMap(receiver_map);
|
||||
maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
|
||||
} else {
|
||||
maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
|
||||
maybe_handler_ = target()->FindHandlerForMap(*receiver_map());
|
||||
}
|
||||
|
||||
// The current map wasn't handled yet. There's no reason to stay monomorphic,
|
||||
@ -278,21 +277,20 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
||||
// TODO(verwaest): Check if the current map is actually what the old map
|
||||
// would transition to.
|
||||
if (maybe_handler_.is_null()) {
|
||||
if (!receiver_map->IsJSObjectMap()) return false;
|
||||
if (!receiver_map()->IsJSObjectMap()) return false;
|
||||
Map* first_map = FirstTargetMap();
|
||||
if (first_map == NULL) return false;
|
||||
Handle<Map> old_map(first_map);
|
||||
if (old_map->is_deprecated()) return true;
|
||||
if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
|
||||
receiver_map->elements_kind())) {
|
||||
receiver_map()->elements_kind())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheHolderFlag flag;
|
||||
Handle<Map> ic_holder_map(
|
||||
GetICCacheHolder(*receiver_type(), isolate(), &flag));
|
||||
Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag));
|
||||
|
||||
DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject());
|
||||
DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
|
||||
@ -332,7 +330,7 @@ bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
|
||||
|
||||
|
||||
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
|
||||
update_receiver_type(receiver);
|
||||
update_receiver_map(receiver);
|
||||
if (!name->IsString()) return;
|
||||
if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
|
||||
if (receiver->IsUndefined() || receiver->IsNull()) return;
|
||||
@ -650,16 +648,16 @@ void IC::ConfigureVectorState(IC::State new_state) {
|
||||
}
|
||||
|
||||
|
||||
void IC::ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
|
||||
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
|
||||
Handle<Code> handler) {
|
||||
DCHECK(UseVector());
|
||||
if (kind() == Code::LOAD_IC) {
|
||||
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
|
||||
nexus->ConfigureMonomorphic(type, handler);
|
||||
nexus->ConfigureMonomorphic(map, handler);
|
||||
} else {
|
||||
DCHECK(kind() == Code::KEYED_LOAD_IC);
|
||||
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
|
||||
nexus->ConfigureMonomorphic(name, type, handler);
|
||||
nexus->ConfigureMonomorphic(name, map, handler);
|
||||
}
|
||||
|
||||
vector_set_ = true;
|
||||
@ -668,16 +666,16 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
|
||||
}
|
||||
|
||||
|
||||
void IC::ConfigureVectorState(Handle<Name> name, TypeHandleList* types,
|
||||
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
DCHECK(UseVector());
|
||||
if (kind() == Code::LOAD_IC) {
|
||||
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
|
||||
nexus->ConfigurePolymorphic(types, handlers);
|
||||
nexus->ConfigurePolymorphic(maps, handlers);
|
||||
} else {
|
||||
DCHECK(kind() == Code::KEYED_LOAD_IC);
|
||||
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
|
||||
nexus->ConfigurePolymorphic(name, types, handlers);
|
||||
nexus->ConfigurePolymorphic(name, maps, handlers);
|
||||
}
|
||||
|
||||
vector_set_ = true;
|
||||
@ -783,74 +781,70 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
|
||||
bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
|
||||
if (!code->is_handler()) return false;
|
||||
if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
|
||||
Handle<HeapType> type = receiver_type();
|
||||
TypeHandleList types;
|
||||
Handle<Map> map = receiver_map();
|
||||
MapHandleList maps;
|
||||
CodeHandleList handlers;
|
||||
|
||||
TargetTypes(&types);
|
||||
int number_of_types = types.length();
|
||||
int deprecated_types = 0;
|
||||
TargetMaps(&maps);
|
||||
int number_of_maps = maps.length();
|
||||
int deprecated_maps = 0;
|
||||
int handler_to_overwrite = -1;
|
||||
|
||||
for (int i = 0; i < number_of_types; i++) {
|
||||
Handle<HeapType> current_type = types.at(i);
|
||||
if (current_type->IsClass() &&
|
||||
current_type->AsClass()->Map()->is_deprecated()) {
|
||||
for (int i = 0; i < number_of_maps; i++) {
|
||||
Handle<Map> current_map = maps.at(i);
|
||||
if (current_map->is_deprecated()) {
|
||||
// Filter out deprecated maps to ensure their instances get migrated.
|
||||
++deprecated_types;
|
||||
} else if (type->NowIs(current_type)) {
|
||||
++deprecated_maps;
|
||||
} else if (map.is_identical_to(current_map)) {
|
||||
// If the receiver type is already in the polymorphic IC, this indicates
|
||||
// there was a prototoype chain failure. In that case, just overwrite the
|
||||
// handler.
|
||||
handler_to_overwrite = i;
|
||||
} else if (handler_to_overwrite == -1 && current_type->IsClass() &&
|
||||
type->IsClass() &&
|
||||
IsTransitionOfMonomorphicTarget(*current_type->AsClass()->Map(),
|
||||
*type->AsClass()->Map())) {
|
||||
} else if (handler_to_overwrite == -1 &&
|
||||
IsTransitionOfMonomorphicTarget(*current_map, *map)) {
|
||||
handler_to_overwrite = i;
|
||||
}
|
||||
}
|
||||
|
||||
int number_of_valid_types =
|
||||
number_of_types - deprecated_types - (handler_to_overwrite != -1);
|
||||
int number_of_valid_maps =
|
||||
number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
|
||||
|
||||
if (number_of_valid_types >= 4) return false;
|
||||
if (number_of_types == 0 && state() != MONOMORPHIC &&
|
||||
state() != POLYMORPHIC) {
|
||||
if (number_of_valid_maps >= 4) return false;
|
||||
if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
|
||||
return false;
|
||||
}
|
||||
if (UseVector()) {
|
||||
if (!nexus()->FindHandlers(&handlers, types.length())) return false;
|
||||
if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
|
||||
} else {
|
||||
if (!target()->FindHandlers(&handlers, types.length())) return false;
|
||||
if (!target()->FindHandlers(&handlers, maps.length())) return false;
|
||||
}
|
||||
|
||||
number_of_valid_types++;
|
||||
if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false;
|
||||
number_of_valid_maps++;
|
||||
if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false;
|
||||
Handle<Code> ic;
|
||||
if (number_of_valid_types == 1) {
|
||||
if (number_of_valid_maps == 1) {
|
||||
if (UseVector()) {
|
||||
ConfigureVectorState(name, receiver_type(), code);
|
||||
ConfigureVectorState(name, receiver_map(), code);
|
||||
} else {
|
||||
ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code,
|
||||
ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, map, code,
|
||||
extra_ic_state());
|
||||
}
|
||||
} else {
|
||||
if (handler_to_overwrite >= 0) {
|
||||
handlers.Set(handler_to_overwrite, code);
|
||||
if (!type->NowIs(types.at(handler_to_overwrite))) {
|
||||
types.Set(handler_to_overwrite, type);
|
||||
if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
|
||||
maps.Set(handler_to_overwrite, map);
|
||||
}
|
||||
} else {
|
||||
types.Add(type);
|
||||
maps.Add(map);
|
||||
handlers.Add(code);
|
||||
}
|
||||
|
||||
if (UseVector()) {
|
||||
ConfigureVectorState(name, &types, &handlers);
|
||||
ConfigureVectorState(name, &maps, &handlers);
|
||||
} else {
|
||||
ic = PropertyICCompiler::ComputePolymorphic(kind(), &types, &handlers,
|
||||
number_of_valid_types, name,
|
||||
ic = PropertyICCompiler::ComputePolymorphic(kind(), &maps, &handlers,
|
||||
number_of_valid_maps, name,
|
||||
extra_ic_state());
|
||||
}
|
||||
}
|
||||
@ -860,66 +854,25 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
|
||||
}
|
||||
|
||||
|
||||
Handle<HeapType> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) {
|
||||
return object->IsJSGlobalObject()
|
||||
? HeapType::Constant(Handle<JSGlobalObject>::cast(object), isolate)
|
||||
: HeapType::NowOf(object, isolate);
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> IC::TypeToMap(HeapType* type, Isolate* isolate) {
|
||||
if (type->Is(HeapType::Number()))
|
||||
return isolate->factory()->heap_number_map();
|
||||
if (type->Is(HeapType::Boolean())) return isolate->factory()->boolean_map();
|
||||
if (type->IsConstant()) {
|
||||
return handle(
|
||||
Handle<JSGlobalObject>::cast(type->AsConstant()->Value())->map());
|
||||
}
|
||||
DCHECK(type->IsClass());
|
||||
return type->AsClass()->Map();
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
typename T::TypeHandle IC::MapToType(Handle<Map> map,
|
||||
typename T::Region* region) {
|
||||
if (map->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
return T::Number(region);
|
||||
} else if (map->instance_type() == ODDBALL_TYPE) {
|
||||
// The only oddballs that can be recorded in ICs are booleans.
|
||||
return T::Boolean(region);
|
||||
} else {
|
||||
return T::Class(map, region);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template Type* IC::MapToType<Type>(Handle<Map> map, Zone* zone);
|
||||
|
||||
|
||||
template Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map,
|
||||
Isolate* region);
|
||||
|
||||
|
||||
void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
|
||||
DCHECK(handler->is_handler());
|
||||
if (UseVector()) {
|
||||
ConfigureVectorState(name, receiver_type(), handler);
|
||||
ConfigureVectorState(name, receiver_map(), handler);
|
||||
} else {
|
||||
Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
|
||||
kind(), name, receiver_type(), handler, extra_ic_state());
|
||||
kind(), name, receiver_map(), handler, extra_ic_state());
|
||||
set_target(*ic);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IC::CopyICToMegamorphicCache(Handle<Name> name) {
|
||||
TypeHandleList types;
|
||||
MapHandleList maps;
|
||||
CodeHandleList handlers;
|
||||
TargetTypes(&types);
|
||||
if (!target()->FindHandlers(&handlers, types.length())) return;
|
||||
for (int i = 0; i < types.length(); i++) {
|
||||
UpdateMegamorphicCache(*types.at(i), *name, *handlers.at(i));
|
||||
TargetMaps(&maps);
|
||||
if (!target()->FindHandlers(&handlers, maps.length())) return;
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -961,7 +914,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
|
||||
}
|
||||
// Fall through.
|
||||
case MEGAMORPHIC:
|
||||
UpdateMegamorphicCache(*receiver_type(), *name, *code);
|
||||
UpdateMegamorphicCache(*receiver_map(), *name, *code);
|
||||
// Indicate that we've handled this case.
|
||||
if (UseVector()) {
|
||||
vector_set_ = true;
|
||||
@ -1074,7 +1027,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
|
||||
} else if (!lookup->IsFound()) {
|
||||
if (kind() == Code::LOAD_IC) {
|
||||
code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
|
||||
receiver_type());
|
||||
receiver_map());
|
||||
// TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
|
||||
if (code.is_null()) code = slow_stub();
|
||||
} else {
|
||||
@ -1089,8 +1042,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
|
||||
}
|
||||
|
||||
|
||||
void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {
|
||||
Map* map = *TypeToMap(type, isolate());
|
||||
void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
|
||||
isolate()->stub_cache()->Set(name, map, code);
|
||||
}
|
||||
|
||||
@ -1100,7 +1052,7 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
|
||||
lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
|
||||
CacheHolderFlag flag;
|
||||
Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
|
||||
*receiver_type(), receiver_is_holder, isolate(), &flag);
|
||||
receiver_map(), receiver_is_holder, isolate(), &flag);
|
||||
|
||||
Handle<Code> code = PropertyHandlerCompiler::Find(
|
||||
lookup->name(), stub_holder_map, kind(), flag,
|
||||
@ -1173,14 +1125,13 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
return function_prototype_stub.GetCode();
|
||||
}
|
||||
|
||||
Handle<HeapType> type = receiver_type();
|
||||
Handle<Map> map = receiver_map();
|
||||
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
||||
bool receiver_is_holder = receiver.is_identical_to(holder);
|
||||
switch (lookup->state()) {
|
||||
case LookupIterator::INTERCEPTOR: {
|
||||
DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
|
||||
cache_holder);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
||||
// Perform a lookup behind the interceptor. Copy the LookupIterator since
|
||||
// the original iterator will be used to fetch the value.
|
||||
LookupIterator it = *lookup;
|
||||
@ -1195,8 +1146,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
DCHECK(receiver->IsJSObject());
|
||||
Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
|
||||
int object_offset;
|
||||
if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(),
|
||||
&object_offset)) {
|
||||
if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
|
||||
&object_offset)) {
|
||||
FieldIndex index =
|
||||
FieldIndex::ForInObjectOffset(object_offset, js_receiver->map());
|
||||
return SimpleFieldLoad(index);
|
||||
@ -1208,13 +1159,12 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(accessors);
|
||||
if (v8::ToCData<Address>(info->getter()) == 0) break;
|
||||
if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
|
||||
type)) {
|
||||
if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
|
||||
map)) {
|
||||
break;
|
||||
}
|
||||
if (!holder->HasFastProperties()) break;
|
||||
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
|
||||
cache_holder);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
||||
return compiler.CompileLoadCallback(lookup->name(), info);
|
||||
}
|
||||
if (accessors->IsAccessorPair()) {
|
||||
@ -1230,8 +1180,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
break;
|
||||
}
|
||||
CallOptimization call_optimization(function);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
|
||||
cache_holder);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
||||
if (call_optimization.is_simple_api_call() &&
|
||||
call_optimization.IsCompatibleReceiver(receiver, holder)) {
|
||||
return compiler.CompileLoadCallback(lookup->name(), call_optimization,
|
||||
@ -1249,15 +1198,15 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
if (lookup->is_dictionary_holder()) {
|
||||
if (kind() != Code::LOAD_IC) break;
|
||||
if (holder->IsGlobalObject()) {
|
||||
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
|
||||
NamedLoadHandlerCompiler compiler(isolate(), map, holder,
|
||||
cache_holder);
|
||||
Handle<PropertyCell> cell = lookup->GetPropertyCell();
|
||||
Handle<Code> code = compiler.CompileLoadGlobal(
|
||||
cell, lookup->name(), lookup->IsConfigurable());
|
||||
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
|
||||
CacheHolderFlag flag;
|
||||
Handle<Map> stub_holder_map = GetHandlerCacheHolder(
|
||||
*type, receiver_is_holder, isolate(), &flag);
|
||||
Handle<Map> stub_holder_map =
|
||||
GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag);
|
||||
Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
|
||||
return code;
|
||||
}
|
||||
@ -1275,8 +1224,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
if (receiver_is_holder) {
|
||||
return SimpleFieldLoad(field);
|
||||
}
|
||||
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
|
||||
cache_holder);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
||||
return compiler.CompileLoadField(lookup->name(), field);
|
||||
}
|
||||
|
||||
@ -1286,8 +1234,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
|
||||
return stub.GetCode();
|
||||
}
|
||||
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
|
||||
cache_holder);
|
||||
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
||||
return compiler.CompileLoadConstant(lookup->name(),
|
||||
lookup->GetConstantIndex());
|
||||
}
|
||||
@ -1334,7 +1281,7 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
|
||||
if (FLAG_vector_ics) {
|
||||
Handle<Code> handler =
|
||||
PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
|
||||
ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
|
||||
ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
|
||||
return null_handle;
|
||||
}
|
||||
return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
|
||||
@ -1354,7 +1301,7 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
|
||||
if (FLAG_vector_ics) {
|
||||
Handle<Code> handler =
|
||||
PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
|
||||
ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
|
||||
ConfigureVectorState(Handle<Name>::null(), receiver_map, handler);
|
||||
return null_handle;
|
||||
}
|
||||
return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
|
||||
@ -1382,11 +1329,8 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
|
||||
CodeHandleList handlers(target_receiver_maps.length());
|
||||
ElementHandlerCompiler compiler(isolate());
|
||||
compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
|
||||
TypeHandleList types(target_receiver_maps.length());
|
||||
for (int i = 0; i < target_receiver_maps.length(); i++) {
|
||||
types.Add(HeapType::Class(target_receiver_maps.at(i), isolate()));
|
||||
}
|
||||
ConfigureVectorState(Handle<Name>::null(), &types, &handlers);
|
||||
ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps,
|
||||
&handlers);
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
@ -1492,7 +1436,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
it->PrepareForDataProperty(value);
|
||||
// The previous receiver map might just have been deprecated,
|
||||
// so reload it.
|
||||
update_receiver_type(receiver);
|
||||
update_receiver_map(receiver);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1717,13 +1661,13 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
}
|
||||
|
||||
DCHECK(lookup->IsCacheableTransition());
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
||||
return compiler.CompileStoreTransition(transition, lookup->name());
|
||||
}
|
||||
|
||||
case LookupIterator::INTERCEPTOR: {
|
||||
DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
||||
return compiler.CompileStoreInterceptor(lookup->name());
|
||||
}
|
||||
|
||||
@ -1740,12 +1684,12 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
|
||||
break;
|
||||
}
|
||||
if (!ExecutableAccessorInfo::IsCompatibleReceiverType(
|
||||
isolate(), info, receiver_type())) {
|
||||
if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info,
|
||||
receiver_map())) {
|
||||
TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
|
||||
break;
|
||||
}
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
||||
return compiler.CompileStoreCallback(receiver, lookup->name(),
|
||||
lookup->GetAccessorIndex());
|
||||
} else if (accessors->IsAccessorPair()) {
|
||||
@ -1757,7 +1701,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
}
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
|
||||
CallOptimization call_optimization(function);
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
||||
if (call_optimization.is_simple_api_call() &&
|
||||
call_optimization.IsCompatibleReceiver(receiver, holder)) {
|
||||
return compiler.CompileStoreCallback(receiver, lookup->name(),
|
||||
@ -1801,7 +1745,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
lookup->representation());
|
||||
return stub.GetCode();
|
||||
}
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
||||
return compiler.CompileStoreField(lookup);
|
||||
}
|
||||
|
||||
|
48
src/ic/ic.h
48
src/ic/ic.h
@ -92,14 +92,14 @@ class IC {
|
||||
bool IsCallStub() const { return target()->is_call_stub(); }
|
||||
#endif
|
||||
|
||||
template <class TypeClass>
|
||||
static JSFunction* GetRootConstructor(TypeClass* type,
|
||||
Context* native_context);
|
||||
static inline Handle<Map> GetHandlerCacheHolder(HeapType* type,
|
||||
static inline JSFunction* GetRootConstructor(Map* receiver_map,
|
||||
Context* native_context);
|
||||
static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
|
||||
bool receiver_is_holder,
|
||||
Isolate* isolate,
|
||||
CacheHolderFlag* flag);
|
||||
static inline Handle<Map> GetICCacheHolder(HeapType* type, Isolate* isolate,
|
||||
static inline Handle<Map> GetICCacheHolder(Handle<Map> receiver_map,
|
||||
Isolate* isolate,
|
||||
CacheHolderFlag* flag);
|
||||
|
||||
static bool IsCleared(Code* code) {
|
||||
@ -112,19 +112,6 @@ class IC {
|
||||
return state == UNINITIALIZED || state == PREMONOMORPHIC;
|
||||
}
|
||||
|
||||
// Utility functions to convert maps to types and back. There are two special
|
||||
// cases:
|
||||
// - The heap_number_map is used as a marker which includes heap numbers as
|
||||
// well as smis.
|
||||
// - The oddball map is only used for booleans.
|
||||
static Handle<Map> TypeToMap(HeapType* type, Isolate* isolate);
|
||||
template <class T>
|
||||
static typename T::TypeHandle MapToType(Handle<Map> map,
|
||||
typename T::Region* region);
|
||||
|
||||
static Handle<HeapType> CurrentTypeOf(Handle<Object> object,
|
||||
Isolate* isolate);
|
||||
|
||||
static bool ICUseVector(Code::Kind kind) {
|
||||
return (FLAG_vector_ics &&
|
||||
(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC)) ||
|
||||
@ -163,10 +150,10 @@ class IC {
|
||||
// Configure for most states.
|
||||
void ConfigureVectorState(IC::State new_state);
|
||||
// Configure the vector for MONOMORPHIC.
|
||||
void ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
|
||||
void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
|
||||
Handle<Code> handler);
|
||||
// Configure the vector for POLYMORPHIC.
|
||||
void ConfigureVectorState(Handle<Name> name, TypeHandleList* types,
|
||||
void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
|
||||
CodeHandleList* handlers);
|
||||
|
||||
char TransitionMarkFromState(IC::State state);
|
||||
@ -204,7 +191,7 @@ class IC {
|
||||
|
||||
void UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name);
|
||||
bool UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code);
|
||||
void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code);
|
||||
void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
|
||||
|
||||
void CopyICToMegamorphicCache(Handle<Name> name);
|
||||
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
|
||||
@ -227,9 +214,13 @@ class IC {
|
||||
ExtraICState extra_ic_state() const { return extra_ic_state_; }
|
||||
void set_extra_ic_state(ExtraICState state) { extra_ic_state_ = state; }
|
||||
|
||||
Handle<HeapType> receiver_type() { return receiver_type_; }
|
||||
void update_receiver_type(Handle<Object> receiver) {
|
||||
receiver_type_ = CurrentTypeOf(receiver, isolate_);
|
||||
Handle<Map> receiver_map() { return receiver_map_; }
|
||||
void update_receiver_map(Handle<Object> receiver) {
|
||||
if (receiver->IsSmi()) {
|
||||
receiver_map_ = isolate_->factory()->heap_number_map();
|
||||
} else {
|
||||
receiver_map_ = handle(HeapObject::cast(*receiver)->map());
|
||||
}
|
||||
}
|
||||
|
||||
void TargetMaps(MapHandleList* list) {
|
||||
@ -239,13 +230,6 @@ class IC {
|
||||
}
|
||||
}
|
||||
|
||||
void TargetTypes(TypeHandleList* list) {
|
||||
FindTargetMaps();
|
||||
for (int i = 0; i < target_maps_.length(); i++) {
|
||||
list->Add(MapToType<HeapType>(target_maps_.at(i), isolate_));
|
||||
}
|
||||
}
|
||||
|
||||
Map* FirstTargetMap() {
|
||||
FindTargetMaps();
|
||||
return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
|
||||
@ -309,7 +293,7 @@ class IC {
|
||||
State old_state_; // For saving if we marked as prototype failure.
|
||||
State state_;
|
||||
Code::Kind kind_;
|
||||
Handle<HeapType> receiver_type_;
|
||||
Handle<Map> receiver_map_;
|
||||
MaybeHandle<Code> maybe_handler_;
|
||||
|
||||
ExtraICState extra_ic_state_;
|
||||
|
@ -215,9 +215,8 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
|
||||
|
||||
void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rsp[0] : return address
|
||||
// -----------------------------------
|
||||
@ -232,7 +231,7 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
DCHECK(!receiver.is(scratch));
|
||||
DCHECK(!value().is(scratch));
|
||||
// Call the JavaScript setter with receiver and value on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Swap in the global receiver.
|
||||
__ movp(scratch,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
@ -262,9 +261,8 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
|
||||
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
MacroAssembler* masm, Handle<HeapType> type, Register receiver,
|
||||
Register holder, int accessor_index, int expected_arguments,
|
||||
Register scratch) {
|
||||
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
|
||||
int accessor_index, int expected_arguments, Register scratch) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : receiver
|
||||
// -- rcx : name
|
||||
@ -277,7 +275,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
|
||||
DCHECK(!holder.is(scratch));
|
||||
DCHECK(!receiver.is(scratch));
|
||||
// Call the JavaScript getter with the receiver on the stack.
|
||||
if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Swap in the global receiver.
|
||||
__ movp(scratch,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
|
||||
@ -416,7 +414,7 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
Register object_reg, Register holder_reg, Register scratch1,
|
||||
Register scratch2, Handle<Name> name, Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
|
||||
Handle<Map> receiver_map = map();
|
||||
|
||||
// Make sure there's no overlap between holder and object registers.
|
||||
DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
|
||||
@ -430,8 +428,8 @@ Register PropertyHandlerCompiler::CheckPrototypes(
|
||||
int depth = 0;
|
||||
|
||||
Handle<JSObject> current = Handle<JSObject>::null();
|
||||
if (type()->IsConstant()) {
|
||||
current = Handle<JSObject>::cast(type()->AsConstant()->Value());
|
||||
if (receiver_map->IsJSGlobalObjectMap()) {
|
||||
current = isolate()->global_object();
|
||||
}
|
||||
Handle<JSObject> prototype = Handle<JSObject>::null();
|
||||
Handle<Map> current_map = receiver_map;
|
||||
|
@ -72,7 +72,7 @@ Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
Handle<Code> PropertyICCompiler::CompilePolymorphic(MapHandleList* maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
@ -99,7 +99,7 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
}
|
||||
|
||||
Label number_case;
|
||||
Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
|
||||
Label* smi_target = IncludesNumberMap(maps) ? &number_case : &miss;
|
||||
__ JumpIfSmi(receiver(), smi_target);
|
||||
|
||||
// Polymorphic keyed stores may use the map register
|
||||
@ -107,17 +107,16 @@ Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
|
||||
DCHECK(kind() != Code::KEYED_STORE_IC ||
|
||||
map_reg.is(ElementTransitionAndStoreDescriptor::MapRegister()));
|
||||
__ movp(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||
int receiver_count = types->length();
|
||||
int receiver_count = maps->length();
|
||||
int number_of_handled_maps = 0;
|
||||
for (int current = 0; current < receiver_count; ++current) {
|
||||
Handle<HeapType> type = types->at(current);
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||
Handle<Map> map = maps->at(current);
|
||||
if (!map->is_deprecated()) {
|
||||
number_of_handled_maps++;
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
// Check map and tail call if there's a match
|
||||
__ CmpWeakValue(map_reg, cell, scratch2());
|
||||
if (type->Is(HeapType::Number())) {
|
||||
if (map->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
DCHECK(!number_case.is_unused());
|
||||
__ bind(&number_case);
|
||||
}
|
||||
|
@ -331,11 +331,10 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
|
||||
}
|
||||
|
||||
|
||||
bool AccessorInfo::IsCompatibleReceiverType(Isolate* isolate,
|
||||
Handle<AccessorInfo> info,
|
||||
Handle<HeapType> type) {
|
||||
bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
|
||||
Handle<AccessorInfo> info,
|
||||
Handle<Map> map) {
|
||||
if (!info->HasExpectedReceiverType()) return true;
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate);
|
||||
if (!map->IsJSObjectMap()) return false;
|
||||
return FunctionTemplateInfo::cast(info->expected_receiver_type())
|
||||
->IsTemplateFor(*map);
|
||||
|
@ -10402,9 +10402,9 @@ class AccessorInfo: public Struct {
|
||||
inline void set_property_attributes(PropertyAttributes attributes);
|
||||
|
||||
// Checks whether the given receiver is compatible with this accessor.
|
||||
static bool IsCompatibleReceiverType(Isolate* isolate,
|
||||
Handle<AccessorInfo> info,
|
||||
Handle<HeapType> type);
|
||||
static bool IsCompatibleReceiverMap(Isolate* isolate,
|
||||
Handle<AccessorInfo> info,
|
||||
Handle<Map> map);
|
||||
inline bool IsCompatibleReceiver(Object* receiver);
|
||||
|
||||
DECLARE_CAST(AccessorInfo)
|
||||
|
@ -207,14 +207,13 @@ Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
|
||||
}
|
||||
|
||||
|
||||
void FeedbackNexus::InstallHandlers(int start_index, TypeHandleList* types,
|
||||
void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
Isolate* isolate = GetIsolate();
|
||||
Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate);
|
||||
int receiver_count = types->length();
|
||||
int receiver_count = maps->length();
|
||||
for (int current = 0; current < receiver_count; ++current) {
|
||||
Handle<HeapType> type = types->at(current);
|
||||
Handle<Map> map = IC::TypeToMap(*type, isolate);
|
||||
Handle<Map> map = maps->at(current);
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
array->set(start_index + (current * 2), *cell);
|
||||
array->set(start_index + (current * 2 + 1), *handlers->at(current));
|
||||
@ -333,10 +332,9 @@ void KeyedLoadICNexus::ConfigurePremonomorphic() {
|
||||
}
|
||||
|
||||
|
||||
void LoadICNexus::ConfigureMonomorphic(Handle<HeapType> type,
|
||||
void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
|
||||
Handle<Code> handler) {
|
||||
Handle<FixedArray> array = EnsureArrayOfSize(2);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
|
||||
array->set(0, *cell);
|
||||
array->set(1, *handler);
|
||||
@ -344,10 +342,9 @@ void LoadICNexus::ConfigureMonomorphic(Handle<HeapType> type,
|
||||
|
||||
|
||||
void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
|
||||
Handle<HeapType> type,
|
||||
Handle<Map> receiver_map,
|
||||
Handle<Code> handler) {
|
||||
Handle<FixedArray> array = EnsureArrayOfSize(3);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
|
||||
if (name.is_null()) {
|
||||
array->set(0, Smi::FromInt(0));
|
||||
} else {
|
||||
@ -359,25 +356,25 @@ void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
|
||||
}
|
||||
|
||||
|
||||
void LoadICNexus::ConfigurePolymorphic(TypeHandleList* types,
|
||||
void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
int receiver_count = types->length();
|
||||
int receiver_count = maps->length();
|
||||
EnsureArrayOfSize(receiver_count * 2);
|
||||
InstallHandlers(0, types, handlers);
|
||||
InstallHandlers(0, maps, handlers);
|
||||
}
|
||||
|
||||
|
||||
void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
|
||||
TypeHandleList* types,
|
||||
MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
int receiver_count = types->length();
|
||||
int receiver_count = maps->length();
|
||||
Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
|
||||
if (name.is_null()) {
|
||||
array->set(0, Smi::FromInt(0));
|
||||
} else {
|
||||
array->set(0, *name);
|
||||
}
|
||||
InstallHandlers(1, types, handlers);
|
||||
InstallHandlers(1, maps, handlers);
|
||||
}
|
||||
|
||||
|
||||
|
@ -262,7 +262,7 @@ class FeedbackNexus {
|
||||
}
|
||||
|
||||
Handle<FixedArray> EnsureArrayOfSize(int length);
|
||||
void InstallHandlers(int start_index, TypeHandleList* types,
|
||||
void InstallHandlers(int start_index, MapHandleList* maps,
|
||||
CodeHandleList* handlers);
|
||||
int ExtractMaps(int start_index, MapHandleList* maps) const;
|
||||
MaybeHandle<Code> FindHandlerForMap(int start_index, Handle<Map> map) const;
|
||||
@ -329,9 +329,9 @@ class LoadICNexus : public FeedbackNexus {
|
||||
|
||||
void ConfigureMegamorphic();
|
||||
void ConfigurePremonomorphic();
|
||||
void ConfigureMonomorphic(Handle<HeapType> type, Handle<Code> handler);
|
||||
void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Code> handler);
|
||||
|
||||
void ConfigurePolymorphic(TypeHandleList* types, CodeHandleList* handlers);
|
||||
void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
|
||||
|
||||
InlineCacheState StateFromFeedback() const OVERRIDE;
|
||||
int ExtractMaps(MapHandleList* maps) const OVERRIDE;
|
||||
@ -357,10 +357,10 @@ class KeyedLoadICNexus : public FeedbackNexus {
|
||||
void ConfigureMegamorphic();
|
||||
void ConfigurePremonomorphic();
|
||||
// name can be a null handle for element loads.
|
||||
void ConfigureMonomorphic(Handle<Name> name, Handle<HeapType> type,
|
||||
void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
|
||||
Handle<Code> handler);
|
||||
// name can be null.
|
||||
void ConfigurePolymorphic(Handle<Name> name, TypeHandleList* types,
|
||||
void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
|
||||
CodeHandleList* handlers);
|
||||
|
||||
InlineCacheState StateFromFeedback() const OVERRIDE;
|
||||
|
Loading…
Reference in New Issue
Block a user