Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 07d7fc5cf428ca6eb9c8c4df4e2e8f58d3264fb4..5af3a7d0d5ceba0fea1f2a6ec91d74d4c9043187 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -227,7 +227,7 @@ void HBasicBlock::Goto(HBasicBlock* block, |
FunctionState* state, |
bool add_simulate) { |
bool drop_extra = state != NULL && |
- state->inlining_kind() == DROP_EXTRA_ON_RETURN; |
+ state->inlining_kind() == NORMAL_RETURN; |
if (block->IsInlineReturnTarget()) { |
HEnvironment* env = last_environment(); |
@@ -248,7 +248,7 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, |
FunctionState* state, |
int position) { |
HBasicBlock* target = state->function_return(); |
- bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; |
+ bool drop_extra = state->inlining_kind() == NORMAL_RETURN; |
ASSERT(target->IsInlineReturnTarget()); |
ASSERT(return_value != NULL); |
@@ -304,6 +304,12 @@ bool HBasicBlock::Dominates(HBasicBlock* other) const { |
} |
+bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const { |
+ if (this == other) return true; |
+ return Dominates(other); |
+} |
+ |
+ |
int HBasicBlock::LoopNestingDepth() const { |
const HBasicBlock* current = this; |
int result = (current->IsLoopHeader()) ? 1 : 0; |
@@ -1289,6 +1295,13 @@ HValue* HGraphBuilder::BuildCheckString(HValue* string) { |
HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { |
if (object->type().IsJSObject()) return object; |
+ if (function->IsConstant() && |
+ HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
+ Handle<JSFunction> f = Handle<JSFunction>::cast( |
+ HConstant::cast(function)->handle(isolate())); |
+ SharedFunctionInfo* shared = f->shared(); |
+ if (!shared->is_classic_mode() || shared->native()) return object; |
+ } |
return Add<HWrapReceiver>(object, function); |
} |
@@ -4926,10 +4939,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(); |
} |
@@ -4938,8 +4954,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; |
} |
@@ -5440,7 +5456,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; |
} |
@@ -5475,13 +5491,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 |
@@ -5509,8 +5538,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()); |
} |
@@ -5536,14 +5566,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; |
} |
@@ -5556,7 +5587,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; |
@@ -5566,19 +5597,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; |
@@ -5589,16 +5613,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; |
} |
@@ -5606,10 +5639,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) { |
@@ -5633,14 +5673,20 @@ 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())) { |
+ 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()); |
@@ -5657,36 +5703,93 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
// Something did not match; must use a polymorphic load. |
int count = 0; |
HBasicBlock* join = NULL; |
+ HBasicBlock* number_block = NULL; |
+ bool handled_string = false; |
+ |
+ 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.type()->Is(HeapType::String())) { |
+ if (handled_string) continue; |
+ handled_string = true; |
+ } |
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; |
+ HControlInstruction* smi_check = NULL; |
+ handled_string = false; |
- HInstruction* load = BuildLoadMonomorphic( |
- &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining); |
- if (load == NULL) { |
- if (HasStackOverflow()) return; |
+ 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; |
+ |
+ 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 |
@@ -5870,7 +5973,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())); |
} |
@@ -5917,15 +6020,22 @@ 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) { |
+ HValue* function = Add<HConstant>(setter); |
+ instr = New<HCallFunction>(function, 2, WRAP_AND_CALL); |
+ } else { |
+ instr = BuildCallConstantFunction(setter, 2); |
+ } |
} else { |
Drop(2); |
CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
@@ -6256,7 +6366,9 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) { |
HValue* value = environment()->Pop(); |
if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
- Add<HThrow>(value); |
+ Add<HPushArgument>(value); |
+ Add<HCallRuntime>(isolate()->factory()->empty_string(), |
+ Runtime::FunctionForId(Runtime::kThrow), 1); |
Add<HSimulate>(expr->id()); |
// If the throw definitely exits the function, we can finish with a dummy |
@@ -6319,7 +6431,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
HValue* object, |
Handle<String> name, |
Property* expr) { |
- if (expr->IsUninitialized()) { |
+ if (!expr->IsForCall() && expr->IsUninitialized()) { |
Add<HDeoptimize>("Insufficient type feedback for generic named load", |
Deoptimizer::SOFT); |
} |
@@ -6610,7 +6722,7 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
if (monomorphic) { |
Handle<Map> map = types->first(); |
- if (map->has_slow_elements_kind()) { |
+ if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { |
instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
: BuildLoadKeyedGeneric(obj, key); |
AddInstruction(instr); |
@@ -6776,14 +6888,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); |
@@ -6879,18 +6993,6 @@ void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, |
} |
-void HOptimizedGraphBuilder::AddCheckConstantFunction( |
- Handle<JSObject> holder, |
- HValue* receiver, |
- Handle<Map> receiver_map) { |
- // Constant functions have the nice property that the map will change if they |
- // are overwritten. Therefore it is enough to check the map of the holder and |
- // its prototypes. |
- AddCheckMap(receiver, receiver_map); |
- AddCheckPrototypeMaps(holder, receiver_map); |
-} |
- |
- |
HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( |
HValue* fun, int argument_count, bool pass_argument_count) { |
return New<HCallJSFunction>( |
@@ -6931,6 +7033,9 @@ HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction( |
bool can_invoke_directly = |
dont_adapt_arguments || formal_parameter_count == arity; |
if (can_invoke_directly) { |
+ if (jsfun.is_identical_to(current_info()->closure())) { |
+ graph()->MarkRecursive(); |
+ } |
return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); |
} else { |
HValue* param_count_value = Add<HConstant>(formal_parameter_count); |
@@ -6945,33 +7050,6 @@ HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction( |
} |
-HInstruction* HOptimizedGraphBuilder::NewCallNamed( |
- Handle<String> name, int argument_count) { |
- CallInterfaceDescriptor* descriptor = |
- isolate()->call_descriptor(Isolate::NamedCall); |
- HValue* op_vals[] = { context(), Add<HConstant>(name) }; |
- int arity = argument_count - 1; |
- Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity); |
- |
- return New<HCallWithDescriptor>( |
- Add<HConstant>(ic), argument_count, descriptor, |
- Vector<HValue*>(op_vals, descriptor->environment_length())); |
-} |
- |
- |
-HInstruction* HOptimizedGraphBuilder::NewCallKeyed( |
- HValue* key, int argument_count) { |
- CallInterfaceDescriptor* descriptor = |
- isolate()->call_descriptor(Isolate::KeyedCall); |
- HValue* op_vals[] = { context(), key }; |
- int arity = argument_count - 1; |
- Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); |
- |
- return New<HCallWithDescriptor>( |
- Add<HConstant>(ic), argument_count, descriptor, |
- Vector<HValue*>(op_vals, descriptor->environment_length())); |
-} |
- |
class FunctionSorter { |
public: |
FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } |
@@ -7003,73 +7081,34 @@ inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { |
} |
-bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( |
- Call* expr, |
- HValue* receiver, |
- SmallMapList* types, |
- Handle<String> name) { |
- if (types->length() > kMaxCallPolymorphism) return false; |
- |
- PropertyAccessInfo info(isolate(), types->at(0), name); |
- if (!info.CanLoadAsMonomorphic(types)) return false; |
- if (!expr->ComputeTarget(info.map(), name)) return false; |
- |
- BuildCheckHeapObject(receiver); |
- Add<HCheckMaps>(receiver, types); |
- AddCheckPrototypeMaps(expr->holder(), info.map()); |
- if (FLAG_trace_inlining) { |
- Handle<JSFunction> caller = current_info()->closure(); |
- SmartArrayPointer<char> caller_name = |
- caller->shared()->DebugName()->ToCString(); |
- PrintF("Trying to inline the polymorphic call to %s from %s\n", |
- name->ToCString().get(), caller_name.get()); |
- } |
- |
- if (!TryInlineCall(expr)) { |
- int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
- HInstruction* call = BuildCallConstantFunction( |
- expr->target(), argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
- AddInstruction(call); |
- if (!ast_context()->IsEffect()) Push(call); |
- Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
- if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
- } |
- |
- return true; |
-} |
- |
- |
void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
Call* expr, |
HValue* receiver, |
SmallMapList* types, |
Handle<String> name) { |
- if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; |
- |
int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
- HBasicBlock* join = NULL; |
FunctionSorter order[kMaxCallPolymorphism]; |
- int ordered_functions = 0; |
- |
- Handle<Map> initial_string_map( |
- isolate()->native_context()->string_function()->initial_map()); |
- Handle<Map> string_marker_map( |
- JSObject::cast(initial_string_map->prototype())->map()); |
- Handle<Map> initial_number_map( |
- isolate()->native_context()->number_function()->initial_map()); |
- Handle<Map> number_marker_map( |
- JSObject::cast(initial_number_map->prototype())->map()); |
- Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
bool handle_smi = false; |
+ bool handled_string = false; |
+ int ordered_functions = 0; |
for (int i = 0; |
i < types->length() && ordered_functions < kMaxCallPolymorphism; |
++i) { |
- Handle<Map> map = types->at(i); |
- if (expr->ComputeTarget(map, name)) { |
- if (map.is_identical_to(number_marker_map)) handle_smi = true; |
+ PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
+ if (info.CanLoadMonomorphic() && |
+ info.lookup()->IsConstant() && |
+ info.constant()->IsJSFunction()) { |
+ if (info.type()->Is(HeapType::String())) { |
+ if (handled_string) continue; |
+ handled_string = true; |
+ } |
+ Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
+ if (info.type()->Is(HeapType::Number())) { |
+ handle_smi = true; |
+ } |
+ expr->set_target(target); |
order[ordered_functions++] = |
FunctionSorter(i, |
expr->target()->shared()->profiler_ticks(), |
@@ -7081,11 +7120,23 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
std::sort(order, order + ordered_functions); |
HBasicBlock* number_block = NULL; |
+ HBasicBlock* join = NULL; |
+ handled_string = false; |
+ int count = 0; |
for (int fn = 0; fn < ordered_functions; ++fn) { |
int i = order[fn].index(); |
- Handle<Map> map = types->at(i); |
- if (fn == 0) { |
+ PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
+ if (info.type()->Is(HeapType::String())) { |
+ if (handled_string) continue; |
+ handled_string = true; |
+ } |
+ // Reloads the target. |
+ info.CanLoadMonomorphic(); |
+ Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
+ |
+ expr->set_target(target); |
+ if (count == 0) { |
// Only needed once. |
join = graph()->CreateBasicBlock(); |
if (handle_smi) { |
@@ -7100,37 +7151,39 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
BuildCheckHeapObject(receiver); |
} |
} |
+ ++count; |
HBasicBlock* if_true = graph()->CreateBasicBlock(); |
HBasicBlock* if_false = graph()->CreateBasicBlock(); |
HUnaryControlInstruction* compare; |
- if (handle_smi && map.is_identical_to(number_marker_map)) { |
+ Handle<Map> map = info.map(); |
+ if (info.type()->Is(HeapType::Number())) { |
+ Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
- map = initial_number_map; |
- expr->set_number_check( |
- Handle<JSObject>(JSObject::cast(map->prototype()))); |
- } else if (map.is_identical_to(string_marker_map)) { |
+ } else if (info.type()->Is(HeapType::String())) { |
compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
- map = initial_string_map; |
- expr->set_string_check( |
- Handle<JSObject>(JSObject::cast(map->prototype()))); |
} else { |
compare = New<HCompareMap>(receiver, map, if_true, if_false); |
- expr->set_map_check(); |
} |
- |
FinishCurrentBlock(compare); |
- if (expr->check_type() == NUMBER_CHECK) { |
+ if (info.type()->Is(HeapType::Number())) { |
Goto(if_true, number_block); |
if_true = number_block; |
number_block->SetJoinId(expr->id()); |
} |
+ |
set_current_block(if_true); |
- expr->ComputeTarget(map, name); |
- AddCheckPrototypeMaps(expr->holder(), map); |
- if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
+ AddCheckPrototypeMaps(info.holder(), map); |
+ |
+ HValue* function = Add<HConstant>(expr->target()); |
+ environment()->SetExpressionStackAt(0, function); |
+ Push(receiver); |
+ CHECK_ALIVE(VisitExpressions(expr->arguments())); |
+ bool needs_wrapping = NeedsWrappingFor(info.type(), target); |
+ bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping; |
+ if (FLAG_trace_inlining && try_inline) { |
Handle<JSFunction> caller = current_info()->closure(); |
SmartArrayPointer<char> caller_name = |
caller->shared()->DebugName()->ToCString(); |
@@ -7138,15 +7191,22 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
name->ToCString().get(), |
caller_name.get()); |
} |
- if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
+ if (try_inline && TryInlineCall(expr)) { |
// Trying to inline will signal that we should bailout from the |
// entire compilation by setting stack overflow on the visitor. |
if (HasStackOverflow()) return; |
} else { |
- HInstruction* call = BuildCallConstantFunction( |
- expr->target(), argument_count); |
+ // Since HWrapReceiver currently cannot actually wrap numbers and strings, |
+ // use the regular CallFunctionStub for method calls to wrap the receiver. |
+ // TODO(verwaest): Support creation of value wrappers directly in |
+ // HWrapReceiver. |
+ HInstruction* call = needs_wrapping |
+ ? NewUncasted<HCallFunction>( |
+ function, argument_count, WRAP_AND_CALL) |
+ : BuildCallConstantFunction(target, argument_count); |
PushArgumentsFromEnvironment(argument_count); |
AddInstruction(call); |
+ Drop(1); // Drop the function. |
if (!ast_context()->IsEffect()) Push(call); |
} |
@@ -7161,13 +7221,29 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
// Because the deopt may be the only path in the polymorphic call, make sure |
// that the environment stack matches the depth on deopt that it otherwise |
// would have had after a successful call. |
- Drop(argument_count); |
+ Drop(1); // Drop receiver. |
if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); |
} else { |
- HInstruction* call = NewCallNamed(name, argument_count); |
+ Property* prop = expr->expression()->AsProperty(); |
+ HInstruction* function = BuildLoadNamedGeneric(receiver, name, prop); |
+ AddInstruction(function); |
+ Push(function); |
+ AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
+ |
+ environment()->SetExpressionStackAt(1, function); |
+ environment()->SetExpressionStackAt(0, receiver); |
+ CHECK_ALIVE(VisitExpressions(expr->arguments())); |
+ |
+ CallFunctionFlags flags = receiver->type().IsJSObject() |
+ ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
+ HInstruction* call = New<HCallFunction>( |
+ function, argument_count, flags); |
+ |
PushArgumentsFromEnvironment(argument_count); |
+ Drop(1); // Function. |
+ |
if (join != NULL) { |
AddInstruction(call); |
if (!ast_context()->IsEffect()) Push(call); |
@@ -7548,13 +7624,13 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
} |
-bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { |
+bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { |
return TryInline(expr->target(), |
expr->arguments()->length(), |
NULL, |
expr->id(), |
expr->ReturnId(), |
- drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); |
+ NORMAL_RETURN); |
} |
@@ -7605,8 +7681,7 @@ bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, |
} |
-bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, |
- bool drop_extra) { |
+bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
switch (id) { |
@@ -7620,9 +7695,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, |
case kMathLog: |
if (expr->arguments()->length() == 1) { |
HValue* argument = Pop(); |
- Drop(1); // Receiver. |
+ Drop(2); // Receiver and function. |
HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
- if (drop_extra) Drop(1); // Optionally drop the function. |
ast_context()->ReturnInstruction(op, expr->id()); |
return true; |
} |
@@ -7631,9 +7705,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, |
if (expr->arguments()->length() == 2) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
- Drop(1); // Receiver. |
+ Drop(2); // Receiver and function. |
HInstruction* op = HMul::NewImul(zone(), context(), left, right); |
- if (drop_extra) Drop(1); // Optionally drop the function. |
ast_context()->ReturnInstruction(op, expr->id()); |
return true; |
} |
@@ -7649,9 +7722,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, |
bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
Call* expr, |
HValue* receiver, |
- Handle<Map> receiver_map, |
- CheckType check_type) { |
- ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
+ Handle<Map> receiver_map) { |
// Try to inline calls like Math.* as operations in the calling function. |
if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
@@ -7659,13 +7730,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
switch (id) { |
case kStringCharCodeAt: |
case kStringCharAt: |
- if (argument_count == 2 && check_type == STRING_CHECK) { |
+ if (argument_count == 2) { |
HValue* index = Pop(); |
HValue* string = Pop(); |
- ASSERT(!expr->holder().is_null()); |
- BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck( |
- STRING_CHECK, expr->holder()->GetIsolate()), |
- expr->holder()); |
+ Drop(1); // Function. |
HInstruction* char_code = |
BuildStringCharCodeAt(string, index); |
if (id == kStringCharCodeAt) { |
@@ -7679,10 +7747,9 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
} |
break; |
case kStringFromCharCode: |
- if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
+ if (argument_count == 2) { |
HValue* argument = Pop(); |
- Drop(1); // Receiver. |
+ Drop(2); // Receiver and function. |
HInstruction* result = NewUncasted<HStringCharFromCode>(argument); |
ast_context()->ReturnInstruction(result, expr->id()); |
return true; |
@@ -7696,21 +7763,19 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
case kMathAbs: |
case kMathSqrt: |
case kMathLog: |
- if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
+ if (argument_count == 2) { |
HValue* argument = Pop(); |
- Drop(1); // Receiver. |
+ Drop(2); // Receiver and function. |
HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
ast_context()->ReturnInstruction(op, expr->id()); |
return true; |
} |
break; |
case kMathPow: |
- if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
+ if (argument_count == 3) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
- Pop(); // Pop receiver. |
+ Drop(2); // Receiver and function. |
HInstruction* result = NULL; |
// Use sqrt() if exponent is 0.5 or -0.5. |
if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
@@ -7739,11 +7804,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
break; |
case kMathMax: |
case kMathMin: |
- if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
+ if (argument_count == 3) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
- Drop(1); // Receiver. |
+ Drop(2); // Receiver and function. |
HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin |
: HMathMinMax::kMathMax; |
HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); |
@@ -7752,24 +7816,20 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
} |
break; |
case kMathImul: |
- if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { |
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
+ if (argument_count == 3) { |
HValue* right = Pop(); |
HValue* left = Pop(); |
- Drop(1); // Receiver. |
+ Drop(2); // Receiver and function. |
HInstruction* result = HMul::NewImul(zone(), context(), left, right); |
ast_context()->ReturnInstruction(result, expr->id()); |
return true; |
} |
break; |
case kArrayPop: { |
- if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
- return false; |
- } |
+ if (receiver_map.is_null()) return false; |
if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
ElementsKind elements_kind = receiver_map->elements_kind(); |
if (!IsFastElementsKind(elements_kind)) return false; |
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
Drop(expr->arguments()->length()); |
HValue* result; |
@@ -7781,6 +7841,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
checked_object, static_cast<HValue*>(NULL), |
HObjectAccess::ForArrayLength(elements_kind)); |
+ Drop(1); // Function. |
+ |
{ NoObservableSideEffectsScope scope(this); |
IfBuilder length_checker(this); |
@@ -7826,13 +7888,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
return true; |
} |
case kArrayPush: { |
- if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
- return false; |
- } |
+ if (receiver_map.is_null()) return false; |
if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
ElementsKind elements_kind = receiver_map->elements_kind(); |
if (!IsFastElementsKind(elements_kind)) return false; |
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
HValue* op_vals[] = { |
context(), |
@@ -7857,6 +7916,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
HInstruction* call = New<HCallWithDescriptor>( |
code_value, argc + 1, descriptor, |
Vector<HValue*>(op_vals, descriptor->environment_length())); |
+ Drop(1); // Drop function. |
ast_context()->ReturnInstruction(call, expr->id()); |
return true; |
} |
@@ -7868,12 +7928,113 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
} |
+bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
+ HValue* receiver) { |
+ return TryInlineApiCall( |
+ expr, receiver, Handle<Map>::null(), true); |
+} |
+ |
+ |
+bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, |
+ HValue* receiver, |
+ Handle<Map> receiver_map) { |
+ return TryInlineApiCall(expr, receiver, receiver_map, false); |
+} |
+ |
+bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, |
+ HValue* receiver, |
+ Handle<Map> receiver_map, |
+ bool is_function_call) { |
+ if (!expr->IsMonomorphic()) return false; |
+ CallOptimization optimization(expr->target()); |
+ if (!optimization.is_simple_api_call()) return false; |
+ Handle<Map> holder_map; |
+ if (is_function_call) { |
+ // Cannot embed a direct reference to the global proxy map |
+ // as it maybe dropped on deserialization. |
+ CHECK(!Serializer::enabled()); |
+ receiver_map = Handle<Map>( |
+ expr->target()->context()->global_object()->global_receiver()->map()); |
+ } |
+ CallOptimization::HolderLookup holder_lookup = |
+ CallOptimization::kHolderNotFound; |
+ Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
+ receiver_map, &holder_lookup); |
+ if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
+ |
+ if (FLAG_trace_inlining) { |
+ PrintF("Inlining api function "); |
+ expr->target()->ShortPrint(); |
+ PrintF("\n"); |
+ } |
+ |
+ const int argc = expr->arguments()->length(); |
+ // Includes receiver. |
+ PushArgumentsFromEnvironment(argc + 1); |
+ |
+ // Need to ensure the chain between receiver and api_holder is intact |
+ AddCheckMap(receiver, receiver_map); |
+ if (holder_lookup == CallOptimization::kHolderFound) { |
+ AddCheckPrototypeMaps(api_holder, receiver_map); |
+ } else { |
+ ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
+ } |
+ |
+ HValue* holder = NULL; |
+ switch (holder_lookup) { |
+ case CallOptimization::kHolderFound: |
+ holder = Add<HConstant>(api_holder); |
+ break; |
+ case CallOptimization::kHolderIsReceiver: |
+ holder = receiver; |
+ break; |
+ case CallOptimization::kHolderNotFound: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
+ Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
+ bool call_data_is_undefined = call_data_obj->IsUndefined(); |
+ HValue* call_data = Add<HConstant>(call_data_obj); |
+ ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
+ ExternalReference ref = ExternalReference(&fun, |
+ ExternalReference::DIRECT_API_CALL, |
+ isolate()); |
+ HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
+ |
+ HValue* op_vals[] = { |
+ // callee |
+ Add<HConstant>(expr->target()), |
+ call_data, |
+ holder, |
+ api_function_address, |
+ context() |
+ }; |
+ |
+ CallInterfaceDescriptor* descriptor = |
+ isolate()->call_descriptor(Isolate::ApiFunctionCall); |
+ |
+ CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
+ Handle<Code> code = stub.GetCode(isolate()); |
+ HConstant* code_value = Add<HConstant>(code); |
+ |
+ ASSERT((sizeof(op_vals) / kPointerSize) == |
+ descriptor->environment_length()); |
+ |
+ HInstruction* call = New<HCallWithDescriptor>( |
+ code_value, argc + 1, descriptor, |
+ Vector<HValue*>(op_vals, descriptor->environment_length())); |
+ |
+ Drop(1); // Drop function. |
+ ast_context()->ReturnInstruction(call, expr->id()); |
+ return true; |
+} |
+ |
+ |
bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
- Expression* callee = expr->expression(); |
- Property* prop = callee->AsProperty(); |
- ASSERT(prop != NULL); |
+ ASSERT(expr->expression()->IsProperty()); |
- if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { |
+ if (!expr->IsMonomorphic()) { |
return false; |
} |
Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
@@ -7894,15 +8055,10 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
// Found pattern f.apply(receiver, arguments). |
- CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true); |
- HValue* function = Top(); |
- |
- AddCheckConstantFunction(expr->holder(), function, function_map); |
- |
CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
- HValue* receiver = Pop(); |
- |
- Drop(1); // Pop the function. |
+ HValue* receiver = Pop(); // receiver |
+ HValue* function = Pop(); // f |
+ Drop(1); // apply |
if (function_state()->outer() == NULL) { |
HInstruction* elements = Add<HArgumentsElements>(false); |
@@ -7922,6 +8078,7 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
HArgumentsObject* args = function_state()->entry()->arguments_object(); |
const ZoneList<HValue*>* arguments_values = args->arguments_values(); |
int arguments_count = arguments_values->length(); |
+ Push(function); |
Push(BuildWrapReceiver(receiver, function)); |
for (int i = 1; i < arguments_count; i++) { |
Push(arguments_values->at(i)); |
@@ -7936,16 +8093,10 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
if (TryInlineApply(known_function, expr, args_count)) return true; |
} |
- Drop(arguments_count - 1); |
- Push(Add<HPushArgument>(Pop())); |
- for (int i = 1; i < arguments_count; i++) { |
- Push(Add<HPushArgument>(arguments_values->at(i))); |
- } |
- |
- HInvokeFunction* call = New<HInvokeFunction>(function, |
- known_function, |
- arguments_count); |
- Drop(arguments_count); |
+ PushArgumentsFromEnvironment(arguments_count); |
+ HInvokeFunction* call = New<HInvokeFunction>( |
+ function, known_function, arguments_count); |
+ Drop(1); // Function. |
ast_context()->ReturnInstruction(call, expr->id()); |
return true; |
} |
@@ -7956,16 +8107,12 @@ HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
Handle<JSFunction> target) { |
SharedFunctionInfo* shared = target->shared(); |
if (shared->is_classic_mode() && !shared->native()) { |
- HValue* context = Add<HLoadNamedField>( |
- function, static_cast<HValue*>(NULL), |
- HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset)); |
- HValue* global_object = Add<HLoadNamedField>( |
- context, static_cast<HValue*>(NULL), |
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
- return Add<HLoadNamedField>( |
- global_object, static_cast<HValue*>(NULL), |
- HObjectAccess::ForJSObjectOffset( |
- GlobalObject::kGlobalReceiverOffset)); |
+ // Cannot embed a direct reference to the global proxy |
+ // as is it dropped on deserialization. |
+ CHECK(!Serializer::enabled()); |
+ Handle<JSObject> global_receiver( |
+ target->context()->global_object()->global_receiver()); |
+ return Add<HConstant>(global_receiver); |
} |
return graph()->GetConstantUndefined(); |
} |
@@ -7981,87 +8128,78 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
Property* prop = callee->AsProperty(); |
if (prop != NULL) { |
- if (!prop->key()->IsPropertyName()) { |
- // Keyed function call. |
- CHECK_ALIVE(VisitForValue(prop->obj())); |
- CHECK_ALIVE(VisitForValue(prop->key())); |
- |
- // Push receiver and key like the non-optimized code generator expects it. |
- HValue* key = Pop(); |
- HValue* receiver = Pop(); |
- Push(key); |
- Push(Add<HPushArgument>(receiver)); |
- CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
- |
- if (expr->IsMonomorphic()) { |
- BuildCheckHeapObject(receiver); |
- ElementsKind kind = expr->KeyedArrayCallIsHoley() |
- ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; |
- |
- Handle<Map> map(isolate()->get_initial_js_array_map(kind)); |
+ CHECK_ALIVE(VisitForValue(prop->obj())); |
+ HValue* receiver = Top(); |
- HValue* function = BuildMonomorphicElementAccess( |
- receiver, key, NULL, NULL, map, false, STANDARD_STORE); |
+ SmallMapList* types; |
+ ComputeReceiverTypes(expr, receiver, &types); |
- call = New<HCallFunction>(function, argument_count); |
- } else { |
- call = NewCallKeyed(key, argument_count); |
+ if (prop->key()->IsPropertyName() && types->length() > 0) { |
+ Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
+ PropertyAccessInfo info(this, IC::MapToType(types->first()), name); |
+ if (!info.CanLoadAsMonomorphic(types)) { |
+ HandlePolymorphicCallNamed(expr, receiver, types, name); |
+ return; |
} |
- Drop(argument_count + 1); // 1 is the key. |
- return ast_context()->ReturnInstruction(call, expr->id()); |
} |
- // Named function call. |
- if (TryCallApply(expr)) return; |
+ HValue* key = NULL; |
+ if (!prop->key()->IsPropertyName()) { |
+ CHECK_ALIVE(VisitForValue(prop->key())); |
+ key = Pop(); |
+ } |
+ |
+ CHECK_ALIVE(PushLoad(prop, receiver, key)); |
+ HValue* function = Pop(); |
- CHECK_ALIVE(VisitForValue(prop->obj())); |
- CHECK_ALIVE(VisitExpressions(expr->arguments())); |
+ // Push the function under the receiver. |
+ environment()->SetExpressionStackAt(0, function); |
- Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
- HValue* receiver = |
- environment()->ExpressionStackAt(expr->arguments()->length()); |
+ Push(receiver); |
- SmallMapList* types; |
- bool was_monomorphic = expr->IsMonomorphic(); |
- bool monomorphic = ComputeReceiverTypes(expr, receiver, &types); |
- if (!was_monomorphic && monomorphic) { |
- monomorphic = expr->ComputeTarget(types->first(), name); |
- } |
+ if (function->IsConstant() && |
+ HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
+ Handle<JSFunction> known_function = Handle<JSFunction>::cast( |
+ HConstant::cast(function)->handle(isolate())); |
+ expr->set_target(known_function); |
- if (monomorphic) { |
- Handle<Map> map = types->first(); |
- if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { |
+ if (TryCallApply(expr)) return; |
+ CHECK_ALIVE(VisitExpressions(expr->arguments())); |
+ |
+ Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
+ if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
if (FLAG_trace_inlining) { |
PrintF("Inlining builtin "); |
- expr->target()->ShortPrint(); |
+ known_function->ShortPrint(); |
PrintF("\n"); |
} |
return; |
} |
- |
- if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || |
- expr->check_type() != RECEIVER_MAP_CHECK) { |
- // When the target has a custom call IC generator, use the IC, |
- // because it is likely to generate better code. Also use the IC |
- // when a primitive receiver check is required. |
- call = NewCallNamed(name, argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
+ if (TryInlineApiMethodCall(expr, receiver, map)) return; |
+ |
+ // Wrap the receiver if necessary. |
+ if (NeedsWrappingFor(IC::MapToType(types->first()), known_function)) { |
+ // Since HWrapReceiver currently cannot actually wrap numbers and |
+ // strings, use the regular CallFunctionStub for method calls to wrap |
+ // the receiver. |
+ // TODO(verwaest): Support creation of value wrappers directly in |
+ // HWrapReceiver. |
+ call = New<HCallFunction>( |
+ function, argument_count, WRAP_AND_CALL); |
+ } else if (TryInlineCall(expr)) { |
+ return; |
} else { |
- AddCheckConstantFunction(expr->holder(), receiver, map); |
- |
- if (TryInlineCall(expr)) return; |
- call = BuildCallConstantFunction(expr->target(), argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
+ call = BuildCallConstantFunction(known_function, argument_count); |
} |
- } else if (types != NULL && types->length() > 1) { |
- ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
- HandlePolymorphicCallNamed(expr, receiver, types, name); |
- return; |
} else { |
- call = NewCallNamed(name, argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
+ CHECK_ALIVE(VisitExpressions(expr->arguments())); |
+ CallFunctionFlags flags = receiver->type().IsJSObject() |
+ ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
+ call = New<HCallFunction>(function, argument_count, flags); |
} |
+ PushArgumentsFromEnvironment(argument_count); |
+ |
} else { |
VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
@@ -8082,26 +8220,21 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
Handle<GlobalObject> global(current_info()->global_object()); |
known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
} |
+ CHECK_ALIVE(VisitForValue(expr->expression())); |
+ HValue* function = Top(); |
if (known_global_function) { |
- // Push the global object instead of the global receiver because |
- // code generated by the full code generator expects it. |
- HValue* global_object = Add<HLoadNamedField>( |
- context(), static_cast<HValue*>(NULL), |
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
- Push(global_object); |
+ Add<HCheckValue>(function, expr->target()); |
+ // Placeholder for the receiver. |
+ Push(graph()->GetConstantUndefined()); |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
- CHECK_ALIVE(VisitForValue(expr->expression())); |
- HValue* function = Pop(); |
- Add<HCheckValue>(function, expr->target()); |
- |
// Patch the global object on the stack by the expected receiver. |
HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
const int receiver_index = argument_count - 1; |
environment()->SetExpressionStackAt(receiver_index, receiver); |
- if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. |
+ if (TryInlineBuiltinFunctionCall(expr)) { |
if (FLAG_trace_inlining) { |
PrintF("Inlining builtin "); |
expr->target()->ShortPrint(); |
@@ -8109,36 +8242,15 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
} |
return; |
} |
+ if (TryInlineApiFunctionCall(expr, receiver)) return; |
if (TryInlineCall(expr)) return; |
- if (expr->target().is_identical_to(current_info()->closure())) { |
- graph()->MarkRecursive(); |
- } |
- |
- if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { |
- // We're about to install a contextual IC, which expects the global |
- // object as receiver rather than the global proxy. |
- HValue* global_object = Add<HLoadNamedField>( |
- context(), static_cast<HValue*>(NULL), |
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
- const int receiver_index = argument_count - 1; |
- environment()->SetExpressionStackAt(receiver_index, global_object); |
- // When the target has a custom call IC generator, use the IC, |
- // because it is likely to generate better code. |
- call = NewCallNamed(var->name(), argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
- } else { |
- call = BuildCallConstantFunction(expr->target(), argument_count); |
- PushArgumentsFromEnvironment(argument_count); |
- } |
+ PushArgumentsFromEnvironment(argument_count); |
+ call = BuildCallConstantFunction(expr->target(), argument_count); |
} else { |
- HValue* receiver = Add<HLoadNamedField>( |
- context(), static_cast<HValue*>(NULL), |
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
- Push(Add<HPushArgument>(receiver)); |
+ Push(Add<HPushArgument>(graph()->GetConstantUndefined())); |
CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
- |
- call = NewCallNamed(var->name(), argument_count); |
+ call = New<HCallFunction>(function, argument_count); |
Drop(argument_count); |
} |
@@ -8150,12 +8262,14 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
Add<HCheckValue>(function, expr->target()); |
- HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
- Push(receiver); |
- |
+ Push(graph()->GetConstantUndefined()); |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
- if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. |
+ HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
+ const int receiver_index = argument_count - 1; |
+ environment()->SetExpressionStackAt(receiver_index, receiver); |
+ |
+ if (TryInlineBuiltinFunctionCall(expr)) { |
if (FLAG_trace_inlining) { |
PrintF("Inlining builtin "); |
expr->target()->ShortPrint(); |
@@ -8163,14 +8277,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
} |
return; |
} |
+ if (TryInlineApiFunctionCall(expr, receiver)) return; |
- if (TryInlineCall(expr, true)) { // Drop function from environment. |
- return; |
- } else { |
- call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), |
- argument_count)); |
- Drop(1); // The function. |
- } |
+ if (TryInlineCall(expr)) return; |
+ |
+ call = PreProcessCall(New<HInvokeFunction>( |
+ function, expr->target(), argument_count)); |
} else { |
CHECK_ALIVE(VisitForValue(expr->expression())); |
@@ -8178,12 +8290,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
HValue* receiver = graph()->GetConstantUndefined(); |
Push(Add<HPushArgument>(receiver)); |
CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
- call = New<HCallFunction>( |
- function, argument_count, NORMAL_CONTEXTUAL_CALL); |
- Drop(argument_count + 1); |
+ call = New<HCallFunction>(function, argument_count); |
+ Drop(argument_count); |
} |
} |
+ Drop(1); // Drop the function. |
return ast_context()->ReturnInstruction(call, expr->id()); |
} |
@@ -10332,9 +10444,27 @@ void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) { |
void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) { |
ASSERT(call->arguments()->length() == 1); |
CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
- HValue* value = Pop(); |
- HValueOf* result = New<HValueOf>(value); |
- return ast_context()->ReturnInstruction(result, call->id()); |
+ HValue* object = Pop(); |
+ |
+ IfBuilder if_objectisvalue(this); |
+ HValue* objectisvalue = if_objectisvalue.If<HHasInstanceTypeAndBranch>( |
+ object, JS_VALUE_TYPE); |
+ if_objectisvalue.Then(); |
+ { |
+ // Return the actual value. |
+ Push(Add<HLoadNamedField>( |
+ object, objectisvalue, |
+ HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset))); |
+ Add<HSimulate>(call->id(), FIXED_SIMULATE); |
+ } |
+ if_objectisvalue.Else(); |
+ { |
+ // If the object is not a value return the object. |
+ Push(object); |
+ Add<HSimulate>(call->id(), FIXED_SIMULATE); |
+ } |
+ if_objectisvalue.End(); |
+ return ast_context()->ReturnValue(Pop()); |
} |
@@ -10607,12 +10737,6 @@ void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
} |
-// Check whether two RegExps are equivalent |
-void HOptimizedGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { |
- return Bailout(kInlinedRuntimeFunctionIsRegExpEquivalent); |
-} |
- |
- |
void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { |
ASSERT(call->arguments()->length() == 1); |
CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |