Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(441)

Unified Diff: src/hydrogen.cc

Issue 155723005: A64: Synchronize with r19001. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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)));
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698