If CallNew targets a constant global, set its state to monomorphic

BUG=

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

Cr-Commit-Position: refs/heads/master@{#27399}
This commit is contained in:
verwaest 2015-03-24 05:05:45 -07:00 committed by Commit bot
parent 310d75218e
commit c46a937220
3 changed files with 32 additions and 77 deletions

View File

@ -622,24 +622,6 @@ Call::CallType Call::GetCallType(Isolate* isolate) const {
}
bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
LookupIterator* it) {
target_ = Handle<JSFunction>::null();
DCHECK(it->IsFound() && it->GetHolder<JSObject>().is_identical_to(global));
Handle<PropertyCell> cell = it->GetPropertyCell();
if (cell->value()->IsJSFunction()) {
Handle<JSFunction> candidate(JSFunction::cast(cell->value()));
// If the function is in new space we assume it's more likely to
// change and thus prefer the general IC code.
if (!it->isolate()->heap()->InNewSpace(*candidate)) {
target_ = candidate;
return true;
}
}
return false;
}
// ----------------------------------------------------------------------------
// Implementation of AstVisitor

View File

@ -1849,11 +1849,14 @@ class Call FINAL : public Expression {
Handle<AllocationSite> allocation_site() { return allocation_site_; }
void SetKnownGlobalTarget(Handle<JSFunction> target) {
target_ = target;
set_is_uninitialized(false);
}
void set_target(Handle<JSFunction> target) { target_ = target; }
void set_allocation_site(Handle<AllocationSite> site) {
allocation_site_ = site;
}
bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupIterator* it);
static int num_ids() { return parent_num_ids() + 2; }
BailoutId ReturnId() const { return BailoutId(local_id(0)); }
@ -1954,6 +1957,10 @@ class CallNew FINAL : public Expression {
}
void set_is_monomorphic(bool monomorphic) { is_monomorphic_ = monomorphic; }
void set_target(Handle<JSFunction> target) { target_ = target; }
void SetKnownGlobalTarget(Handle<JSFunction> target) {
target_ = target;
is_monomorphic_ = true;
}
protected:
CallNew(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,

View File

@ -9106,10 +9106,10 @@ bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr,
return false;
}
BuildArrayCall(expr,
expr->arguments()->length(),
function,
expr->allocation_site());
Handle<AllocationSite> site = expr->allocation_site();
if (site.is_null()) return false;
BuildArrayCall(expr, expr->arguments()->length(), function, site);
return true;
}
@ -9231,58 +9231,21 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
// evaluation of the arguments.
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* function = Top();
if (expr->global_call()) {
Variable* var = proxy->var();
bool known_global_function = false;
// If there is a global property cell for the name at compile time and
// access check is not enabled we assume that the function will not change
// and generate optimized code for calling the function.
Handle<GlobalObject> global(current_info()->global_object());
LookupIterator it(global, var->name(),
LookupIterator::OWN_SKIP_INTERCEPTOR);
GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD);
if (type == kUseCell) {
known_global_function = expr->ComputeGlobalTarget(global, &it);
}
if (known_global_function) {
Add<HCheckValue>(function, expr->target());
if (function->IsConstant() &&
HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
Handle<Object> constant = HConstant::cast(function)->handle(isolate());
Handle<JSFunction> target = Handle<JSFunction>::cast(constant);
expr->SetKnownGlobalTarget(target);
}
// Placeholder for the receiver.
Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitExpressions(expr->arguments()));
// Placeholder for the receiver.
Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitExpressions(expr->arguments()));
// 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)) {
if (FLAG_trace_inlining) {
PrintF("Inlining builtin ");
expr->target()->ShortPrint();
PrintF("\n");
}
return;
}
if (TryInlineApiFunctionCall(expr, receiver)) return;
if (TryHandleArrayCall(expr, function)) return;
if (TryInlineCall(expr)) return;
PushArgumentsFromEnvironment(argument_count);
call = BuildCallConstantFunction(expr->target(), argument_count);
} else {
Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitExpressions(expr->arguments()));
PushArgumentsFromEnvironment(argument_count);
call = New<HCallFunction>(function, argument_count);
}
} else if (expr->IsMonomorphic()) {
if (expr->IsMonomorphic()) {
Add<HCheckValue>(function, expr->target());
Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitExpressions(expr->arguments()));
// 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);
@ -9296,15 +9259,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
return;
}
if (TryInlineApiFunctionCall(expr, receiver)) return;
if (TryHandleArrayCall(expr, function)) return;
if (TryInlineCall(expr)) return;
call = PreProcessCall(New<HInvokeFunction>(
function, expr->target(), argument_count));
PushArgumentsFromEnvironment(argument_count);
call = BuildCallConstantFunction(expr->target(), argument_count);
} else {
Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitExpressions(expr->arguments()));
PushArgumentsFromEnvironment(argument_count);
HCallFunction* call_function =
New<HCallFunction>(function, argument_count);
@ -9443,6 +9403,12 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
HValue* function = Top();
CHECK_ALIVE(VisitExpressions(expr->arguments()));
if (function->IsConstant() &&
HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
Handle<Object> constant = HConstant::cast(function)->handle(isolate());
expr->SetKnownGlobalTarget(Handle<JSFunction>::cast(constant));
}
if (FLAG_inline_construct &&
expr->IsMonomorphic() &&
IsAllocationInlineable(expr->target())) {