| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 74262b965cb2b440cb7e781268ffd0d9c864514e..3c7bf5064b1683c2c8609a52ff6057d5eadda29d 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -4924,10 +4924,13 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
|
| }
|
|
|
|
|
| -static bool CanInlinePropertyAccess(Map* type) {
|
| - return type->IsJSObjectMap() &&
|
| - !type->is_dictionary_map() &&
|
| - !type->has_named_interceptor();
|
| +static bool CanInlinePropertyAccess(Handle<HeapType> type) {
|
| + if (type->Is(HeapType::NumberOrString())) return true;
|
| + if (!type->IsClass()) return false;
|
| + Handle<Map> map = type->AsClass();
|
| + return map->IsJSObjectMap() &&
|
| + !map->is_dictionary_map() &&
|
| + !map->has_named_interceptor();
|
| }
|
|
|
|
|
| @@ -4936,8 +4939,8 @@ static void LookupInPrototypes(Handle<Map> map,
|
| LookupResult* lookup) {
|
| while (map->prototype()->IsJSObject()) {
|
| Handle<JSObject> holder(JSObject::cast(map->prototype()));
|
| - map = Handle<Map>(holder->map());
|
| - if (!CanInlinePropertyAccess(*map)) break;
|
| + map = handle(holder->map());
|
| + if (!CanInlinePropertyAccess(IC::MapToType(map))) break;
|
| map->LookupDescriptor(*holder, *name, lookup);
|
| if (lookup->IsFound()) return;
|
| }
|
| @@ -5438,7 +5441,7 @@ static bool ComputeStoreField(Handle<Map> type,
|
| LookupResult* lookup,
|
| bool lookup_transition = true) {
|
| ASSERT(!type->is_observed());
|
| - if (!CanInlinePropertyAccess(*type)) {
|
| + if (!CanInlinePropertyAccess(IC::MapToType(type))) {
|
| lookup->NotFound();
|
| return false;
|
| }
|
| @@ -5473,13 +5476,26 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
|
|
|
| bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
|
| PropertyAccessInfo* info) {
|
| - if (!CanInlinePropertyAccess(*map_)) return false;
|
| + if (!CanInlinePropertyAccess(type_)) return false;
|
| +
|
| + // Currently only handle HeapType::Number as a polymorphic case.
|
| + // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
|
| + // instruction.
|
| + if (type_->Is(HeapType::Number())) return false;
|
| +
|
| + // Values are only compatible for monomorphic load if they all behave the same
|
| + // regarding value wrappers.
|
| + if (type_->Is(HeapType::NumberOrString())) {
|
| + if (!info->type_->Is(HeapType::NumberOrString())) return false;
|
| + } else {
|
| + if (info->type_->Is(HeapType::NumberOrString())) return false;
|
| + }
|
|
|
| if (!LookupDescriptor()) return false;
|
|
|
| if (!lookup_.IsFound()) {
|
| return (!info->lookup_.IsFound() || info->has_holder()) &&
|
| - map_->prototype() == info->map_->prototype();
|
| + map()->prototype() == info->map()->prototype();
|
| }
|
|
|
| // Mismatch if the other access info found the property in the prototype
|
| @@ -5507,8 +5523,9 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
|
|
|
|
|
| bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
|
| - map_->LookupDescriptor(NULL, *name_, &lookup_);
|
| - return LoadResult(map_);
|
| + if (!type_->IsClass()) return true;
|
| + map()->LookupDescriptor(NULL, *name_, &lookup_);
|
| + return LoadResult(map());
|
| }
|
|
|
|
|
| @@ -5534,14 +5551,15 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
|
|
|
|
|
| bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
|
| - Handle<Map> map = map_;
|
| + Handle<Map> map = this->map();
|
| +
|
| while (map->prototype()->IsJSObject()) {
|
| holder_ = handle(JSObject::cast(map->prototype()));
|
| if (holder_->map()->is_deprecated()) {
|
| JSObject::TryMigrateInstance(holder_);
|
| }
|
| map = Handle<Map>(holder_->map());
|
| - if (!CanInlinePropertyAccess(*map)) {
|
| + if (!CanInlinePropertyAccess(IC::MapToType(map))) {
|
| lookup_.NotFound();
|
| return false;
|
| }
|
| @@ -5554,7 +5572,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
|
|
|
|
|
| bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
|
| - if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
|
| + if (!CanInlinePropertyAccess(type_)) return false;
|
| if (IsJSObjectFieldAccessor()) return true;
|
| if (!LookupDescriptor()) return false;
|
| if (lookup_.IsFound()) return true;
|
| @@ -5564,19 +5582,12 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
|
|
|
| bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
|
| SmallMapList* types) {
|
| - ASSERT(map_.is_identical_to(types->first()));
|
| + ASSERT(type_->Is(IC::MapToType(types->first())));
|
| if (!CanLoadMonomorphic()) return false;
|
| if (types->length() > kMaxLoadPolymorphism) return false;
|
|
|
| - if (IsStringLength()) {
|
| - for (int i = 1; i < types->length(); ++i) {
|
| - if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
|
| - }
|
| - return true;
|
| - }
|
| -
|
| if (IsArrayLength()) {
|
| - bool is_fast = IsFastElementsKind(map_->elements_kind());
|
| + bool is_fast = IsFastElementsKind(map()->elements_kind());
|
| for (int i = 1; i < types->length(); ++i) {
|
| Handle<Map> test_map = types->at(i);
|
| if (test_map->instance_type() != JS_ARRAY_TYPE) return false;
|
| @@ -5587,16 +5598,25 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
|
| return true;
|
| }
|
|
|
| - if (IsJSObjectFieldAccessor()) {
|
| - InstanceType instance_type = map_->instance_type();
|
| + HObjectAccess access = HObjectAccess::ForMap(); // bogus default
|
| + if (GetJSObjectFieldAccess(&access)) {
|
| for (int i = 1; i < types->length(); ++i) {
|
| - if (types->at(i)->instance_type() != instance_type) return false;
|
| + PropertyAccessInfo test_info(
|
| + builder_, IC::MapToType(types->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;
|
| }
|
| return true;
|
| }
|
|
|
| + // Currently only handle HeapType::Number as a polymorphic case.
|
| + // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
|
| + // instruction.
|
| + if (type_->Is(HeapType::Number())) return false;
|
| +
|
| for (int i = 1; i < types->length(); ++i) {
|
| - PropertyAccessInfo test_info(isolate(), types->at(i), name_);
|
| + PropertyAccessInfo test_info(builder_, IC::MapToType(types->at(i)), name_);
|
| if (!test_info.IsCompatibleForLoad(this)) return false;
|
| }
|
|
|
| @@ -5604,10 +5624,17 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
|
| }
|
|
|
|
|
| +static bool NeedsWrappingFor(Handle<HeapType> type, Handle<JSFunction> target) {
|
| + return type->Is(HeapType::NumberOrString()) &&
|
| + target->shared()->is_classic_mode() &&
|
| + !target->shared()->native();
|
| +}
|
| +
|
| +
|
| HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
|
| PropertyAccessInfo* info,
|
| HValue* object,
|
| - HInstruction* checked_object,
|
| + HValue* checked_object,
|
| BailoutId ast_id,
|
| BailoutId return_id,
|
| bool can_inline_accessor) {
|
| @@ -5631,14 +5658,21 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
|
| }
|
|
|
| if (info->lookup()->IsPropertyCallbacks()) {
|
| - Push(checked_object);
|
| - if (FLAG_inline_accessors &&
|
| - can_inline_accessor &&
|
| - TryInlineGetter(info->accessor(), ast_id, return_id)) {
|
| - return NULL;
|
| + if (NeedsWrappingFor(info->type(), info->accessor())) {
|
| + return New<HLoadNamedGeneric>(checked_object, info->name());
|
| + // HValue* function = Add<HConstant>(info->accessor());
|
| + // Add<HPushArgument>(checked_object);
|
| + // return New<HCallFunction>(function, 1, WRAP_AND_CALL);
|
| + } else {
|
| + Push(checked_object);
|
| + if (FLAG_inline_accessors &&
|
| + can_inline_accessor &&
|
| + TryInlineGetter(info->accessor(), ast_id, return_id)) {
|
| + return NULL;
|
| + }
|
| + Add<HPushArgument>(Pop());
|
| + return BuildCallConstantFunction(info->accessor(), 1);
|
| }
|
| - Add<HPushArgument>(Pop());
|
| - return BuildCallConstantFunction(info->accessor(), 1);
|
| }
|
|
|
| ASSERT(info->lookup()->IsConstant());
|
| @@ -5655,36 +5689,88 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
|
| // Something did not match; must use a polymorphic load.
|
| int count = 0;
|
| HBasicBlock* join = NULL;
|
| + HBasicBlock* number_block = NULL;
|
| +
|
| + bool handle_smi = false;
|
| for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
|
| - PropertyAccessInfo info(isolate(), types->at(i), name);
|
| + PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
|
| if (info.CanLoadMonomorphic()) {
|
| - if (count == 0) {
|
| - BuildCheckHeapObject(object);
|
| - join = graph()->CreateBasicBlock();
|
| + count++;
|
| + if (info.type()->Is(HeapType::Number())) {
|
| + handle_smi = true;
|
| + break;
|
| }
|
| - ++count;
|
| - HBasicBlock* if_true = graph()->CreateBasicBlock();
|
| - HBasicBlock* if_false = graph()->CreateBasicBlock();
|
| - HCompareMap* compare = New<HCompareMap>(
|
| - object, info.map(), if_true, if_false);
|
| - FinishCurrentBlock(compare);
|
| + }
|
| + }
|
|
|
| - set_current_block(if_true);
|
| + count = 0;
|
| + bool handled_string = false;
|
| + HControlInstruction* smi_check = NULL;
|
| +
|
| + for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
|
| + PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name);
|
| + if (info.type()->Is(HeapType::String())) {
|
| + if (handled_string) continue;
|
| + handled_string = true;
|
| + }
|
| + if (!info.CanLoadMonomorphic()) continue;
|
|
|
| - HInstruction* load = BuildLoadMonomorphic(
|
| - &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining);
|
| - if (load == NULL) {
|
| - if (HasStackOverflow()) return;
|
| + if (count == 0) {
|
| + join = graph()->CreateBasicBlock();
|
| + if (handle_smi) {
|
| + HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
|
| + HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
|
| + number_block = graph()->CreateBasicBlock();
|
| + smi_check = New<HIsSmiAndBranch>(
|
| + object, empty_smi_block, not_smi_block);
|
| + FinishCurrentBlock(smi_check);
|
| + Goto(empty_smi_block, number_block);
|
| + set_current_block(not_smi_block);
|
| } else {
|
| - if (!load->IsLinked()) {
|
| - AddInstruction(load);
|
| - }
|
| - if (!ast_context()->IsEffect()) Push(load);
|
| + BuildCheckHeapObject(object);
|
| }
|
| + }
|
| + ++count;
|
| + HBasicBlock* if_true = graph()->CreateBasicBlock();
|
| + HBasicBlock* if_false = graph()->CreateBasicBlock();
|
| + HUnaryControlInstruction* compare;
|
|
|
| - if (current_block() != NULL) Goto(join);
|
| - set_current_block(if_false);
|
| + HValue* dependency;
|
| + if (info.type()->Is(HeapType::Number())) {
|
| + 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(HeapType::String())) {
|
| + compare = New<HIsStringAndBranch>(object, if_true, if_false);
|
| + dependency = compare;
|
| + } else {
|
| + compare = New<HCompareMap>(object, info.map(), if_true, if_false);
|
| + dependency = compare;
|
| }
|
| + FinishCurrentBlock(compare);
|
| +
|
| + if (info.type()->Is(HeapType::Number())) {
|
| + Goto(if_true, number_block);
|
| + if_true = number_block;
|
| + number_block->SetJoinId(ast_id);
|
| + }
|
| +
|
| + set_current_block(if_true);
|
| +
|
| + HInstruction* load = BuildLoadMonomorphic(
|
| + &info, object, dependency, ast_id,
|
| + return_id, FLAG_polymorphic_inlining);
|
| + if (load == NULL) {
|
| + if (HasStackOverflow()) return;
|
| + } else {
|
| + if (!load->IsLinked()) {
|
| + AddInstruction(load);
|
| + }
|
| + if (!ast_context()->IsEffect()) Push(load);
|
| + }
|
| +
|
| + if (current_block() != NULL) Goto(join);
|
| + set_current_block(if_false);
|
| }
|
|
|
| // Finish up. Unconditionally deoptimize if we've handled all the maps we
|
| @@ -5868,7 +5954,7 @@ static bool ComputeReceiverTypes(Expression* expr,
|
| types->FilterForPossibleTransitions(root_map);
|
| monomorphic = types->length() == 1;
|
| }
|
| - return monomorphic && CanInlinePropertyAccess(*types->first());
|
| + return monomorphic && CanInlinePropertyAccess(IC::MapToType(types->first()));
|
| }
|
|
|
|
|
| @@ -5915,15 +6001,21 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
|
| Handle<JSFunction> setter;
|
| Handle<JSObject> holder;
|
| if (LookupSetter(map, name, &setter, &holder)) {
|
| - AddCheckConstantFunction(holder, object, map);
|
| - if (FLAG_inline_accessors &&
|
| - TryInlineSetter(setter, ast_id, return_id, value)) {
|
| + AddCheckMap(object, map);
|
| + AddCheckPrototypeMaps(holder, map);
|
| + bool needs_wrapping = NeedsWrappingFor(IC::MapToType(map), setter);
|
| + bool try_inline = FLAG_inline_accessors && !needs_wrapping;
|
| + if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) {
|
| return;
|
| }
|
| Drop(2);
|
| - Add<HPushArgument>(object);
|
| - Add<HPushArgument>(value);
|
| - instr = BuildCallConstantFunction(setter, 2);
|
| + if (needs_wrapping) {
|
| + instr = BuildStoreNamedGeneric(object, name, value);
|
| + } else {
|
| + Add<HPushArgument>(object);
|
| + Add<HPushArgument>(value);
|
| + instr = BuildCallConstantFunction(setter, 2);
|
| + }
|
| } else {
|
| Drop(2);
|
| CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
|
| @@ -6776,14 +6868,16 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
|
| ASSERT(types != NULL);
|
|
|
| if (types->length() > 0) {
|
| - PropertyAccessInfo info(isolate(), types->first(), name);
|
| + PropertyAccessInfo info(this, IC::MapToType(types->first()), name);
|
| if (!info.CanLoadAsMonomorphic(types)) {
|
| return HandlePolymorphicLoadNamedField(
|
| ast_id, expr->LoadId(), object, types, name);
|
| }
|
|
|
| + HValue* checked_object;
|
| + // HeapType::Number() is only supported by polymorphic load/call handling.
|
| + ASSERT(!info.type()->Is(HeapType::Number()));
|
| BuildCheckHeapObject(object);
|
| - HInstruction* checked_object;
|
| if (AreStringTypes(types)) {
|
| checked_object =
|
| Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
|
| @@ -7010,7 +7104,7 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
|
| Handle<String> name) {
|
| if (types->length() > kMaxCallPolymorphism) return false;
|
|
|
| - PropertyAccessInfo info(isolate(), types->at(0), name);
|
| + PropertyAccessInfo info(this, IC::MapToType(types->at(0)), name);
|
| if (!info.CanLoadAsMonomorphic(types)) return false;
|
| if (!expr->ComputeTarget(info.map(), name)) return false;
|
|
|
|
|