Optimize Function.prototype.call

BUG=
R=verwaest@chromium.org, jarin@chromium.org, jkummerow@chromium.org

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

Patch from Petka Antonov <p.antonov@partner.samsung.com>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24631 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2014-10-15 12:22:15 +00:00
parent 37f1645023
commit 23868b419c
7 changed files with 604 additions and 52 deletions

View File

@ -8108,9 +8108,9 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
}
bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function,
Call* expr,
int arguments_count) {
bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
Call* expr,
int arguments_count) {
return TryInline(function,
arguments_count,
NULL,
@ -8162,13 +8162,22 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
Call* expr,
HValue* receiver,
Handle<Map> receiver_map) {
Call* expr, Handle<JSFunction> function, Handle<Map> receiver_map,
int args_count_no_receiver) {
if (!function->shared()->HasBuiltinFunctionId()) return false;
BuiltinFunctionId id = function->shared()->builtin_function_id();
int argument_count = args_count_no_receiver + 1; // Plus receiver.
if (receiver_map.is_null()) {
HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
if (receiver->IsConstant() &&
HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
receiver_map =
handle(Handle<HeapObject>::cast(
HConstant::cast(receiver)->handle(isolate()))->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();
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
switch (id) {
case kStringCharCodeAt:
case kStringCharAt:
@ -8277,7 +8286,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
if (receiver_map->is_observed()) return false;
if (!receiver_map->is_extensible()) return false;
Drop(expr->arguments()->length());
Drop(args_count_no_receiver);
HValue* result;
HValue* reduced_length;
HValue* receiver = Pop();
@ -8353,7 +8362,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
const int argc = expr->arguments()->length();
const int argc = args_count_no_receiver;
if (argc != 1) return false;
HValue* value_to_push = Pop();
@ -8410,7 +8419,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
// Threshold for fast inlined Array.shift().
HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
Drop(expr->arguments()->length());
Drop(args_count_no_receiver);
HValue* receiver = Pop();
HValue* function = Pop();
HValue* result;
@ -8716,7 +8725,47 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
}
bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
int arguments_count) {
Handle<JSFunction> known_function;
int args_count_no_receiver = arguments_count - 1;
if (function->IsConstant() &&
HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
Handle<Map> receiver_map;
if (receiver->IsConstant() &&
HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
receiver_map =
handle(Handle<HeapObject>::cast(
HConstant::cast(receiver)->handle(isolate()))->map());
}
known_function =
Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate()));
if (TryInlineBuiltinMethodCall(expr, known_function, receiver_map,
args_count_no_receiver)) {
if (FLAG_trace_inlining) {
PrintF("Inlining builtin ");
known_function->ShortPrint();
PrintF("\n");
}
return;
}
if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
return;
}
}
PushArgumentsFromEnvironment(arguments_count);
HInvokeFunction* call =
New<HInvokeFunction>(function, known_function, arguments_count);
Drop(1); // Function
ast_context()->ReturnInstruction(call, expr->id());
}
bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
DCHECK(expr->expression()->IsProperty());
if (!expr->IsMonomorphic()) {
@ -8724,27 +8773,45 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
}
Handle<Map> function_map = expr->GetReceiverTypes()->first();
if (function_map->instance_type() != JS_FUNCTION_TYPE ||
!expr->target()->shared()->HasBuiltinFunctionId() ||
expr->target()->shared()->builtin_function_id() != kFunctionApply) {
!expr->target()->shared()->HasBuiltinFunctionId()) {
return false;
}
if (current_info()->scope()->arguments() == NULL) return false;
switch (expr->target()->shared()->builtin_function_id()) {
case kFunctionCall: {
if (expr->arguments()->length() == 0) return false;
BuildFunctionCall(expr);
return true;
}
case kFunctionApply: {
// For .apply, only the pattern f.apply(receiver, arguments)
// is supported.
if (current_info()->scope()->arguments() == NULL) return false;
ZoneList<Expression*>* args = expr->arguments();
if (args->length() != 2) return false;
VariableProxy* arg_two = args->at(1)->AsVariableProxy();
if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
BuildFunctionApply(expr);
return true;
}
default: { return false; }
}
UNREACHABLE();
}
void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
ZoneList<Expression*>* args = expr->arguments();
if (args->length() != 2) return false;
VariableProxy* arg_two = args->at(1)->AsVariableProxy();
if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
// Found pattern f.apply(receiver, arguments).
CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
CHECK_ALIVE(VisitForValue(args->at(0)));
HValue* receiver = Pop(); // receiver
HValue* function = Pop(); // f
Drop(1); // apply
Handle<Map> function_map = expr->GetReceiverTypes()->first();
HValue* checked_function = AddCheckMap(function, function_map);
if (function_state()->outer() == NULL) {
@ -8756,7 +8823,6 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
length,
elements);
ast_context()->ReturnInstruction(result, expr->id());
return true;
} else {
// We are inside inlined function and we know exactly what is inside
// arguments object. But we need to be able to materialize at deopt.
@ -8770,26 +8836,36 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
for (int i = 1; i < arguments_count; i++) {
Push(arguments_values->at(i));
}
Handle<JSFunction> known_function;
if (function->IsConstant() &&
HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
known_function = Handle<JSFunction>::cast(
HConstant::cast(function)->handle(isolate()));
int args_count = arguments_count - 1; // Excluding receiver.
if (TryInlineApply(known_function, expr, args_count)) return true;
}
PushArgumentsFromEnvironment(arguments_count);
HInvokeFunction* call = New<HInvokeFunction>(
function, known_function, arguments_count);
Drop(1); // Function.
ast_context()->ReturnInstruction(call, expr->id());
return true;
HandleIndirectCall(expr, function, arguments_count);
}
}
// f.call(...)
void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
HValue* function = Top(); // f
Handle<Map> function_map = expr->GetReceiverTypes()->first();
HValue* checked_function = AddCheckMap(function, function_map);
// f and call are on the stack in the unoptimized code
// during evaluation of the arguments.
CHECK_ALIVE(VisitExpressions(expr->arguments()));
int args_length = expr->arguments()->length();
int receiver_index = args_length - 1;
// Patch the receiver.
HValue* receiver = BuildWrapReceiver(
environment()->ExpressionStackAt(receiver_index), checked_function);
environment()->SetExpressionStackAt(receiver_index, receiver);
// Call must not be on the stack from now on.
int call_index = args_length + 1;
environment()->RemoveExpressionStackAt(call_index);
HandleIndirectCall(expr, function, args_length);
}
HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
Handle<JSFunction> target) {
SharedFunctionInfo* shared = target->shared();
@ -9052,11 +9128,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
HConstant::cast(function)->handle(isolate()));
expr->set_target(known_function);
if (TryCallApply(expr)) return;
if (TryIndirectCall(expr)) return;
CHECK_ALIVE(VisitExpressions(expr->arguments()));
Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
if (TryInlineBuiltinMethodCall(expr, receiver, map)) {
if (TryInlineBuiltinMethodCall(expr, known_function, map,
expr->arguments()->length())) {
if (FLAG_trace_inlining) {
PrintF("Inlining builtin ");
known_function->ShortPrint();
@ -12092,6 +12169,18 @@ void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
}
HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) {
int count = index_from_top + 1;
int index = values_.length() - count;
DCHECK(HasExpressionAt(index));
// Simulate popping 'count' elements and then
// pushing 'count - 1' elements back.
pop_count_ += Max(count - push_count_, 0);
push_count_ = Max(push_count_ - count, 0) + (count - 1);
return values_.Remove(index);
}
void HEnvironment::Drop(int count) {
for (int i = 0; i < count; ++i) {
Pop();

View File

@ -642,6 +642,7 @@ class HEnvironment FINAL : public ZoneObject {
}
void SetExpressionStackAt(int index_from_top, HValue* value);
HValue* RemoveExpressionStackAt(int index_from_top);
HEnvironment* Copy() const;
HEnvironment* CopyWithoutHistory() const;
@ -2311,8 +2312,13 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
void EnsureArgumentsArePushedForAccess();
bool TryArgumentsAccess(Property* expr);
// Try to optimize fun.apply(receiver, arguments) pattern.
bool TryCallApply(Call* expr);
// Shared code for .call and .apply optimizations.
void HandleIndirectCall(Call* expr, HValue* function, int arguments_count);
// Try to optimize indirect calls such as fun.apply(receiver, arguments)
// or fun.call(...).
bool TryIndirectCall(Call* expr);
void BuildFunctionApply(Call* expr);
void BuildFunctionCall(Call* expr);
bool TryHandleArrayCall(Call* expr, HValue* function);
bool TryHandleArrayCallNew(CallNew* expr, HValue* function);
@ -2348,12 +2354,11 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
BailoutId id,
BailoutId assignment_id,
HValue* implicit_return_value);
bool TryInlineApply(Handle<JSFunction> function,
Call* expr,
int arguments_count);
bool TryInlineBuiltinMethodCall(Call* expr,
HValue* receiver,
Handle<Map> receiver_map);
bool TryInlineIndirectCall(Handle<JSFunction> function, Call* expr,
int arguments_count);
bool TryInlineBuiltinMethodCall(Call* expr, Handle<JSFunction> function,
Handle<Map> receiver_map,
int args_count_no_receiver);
bool TryInlineBuiltinFunctionCall(Call* expr);
enum ApiCallType {
kCallApiFunction,

View File

@ -6560,6 +6560,7 @@ class Script: public Struct {
V(Array.prototype, pop, ArrayPop) \
V(Array.prototype, shift, ArrayShift) \
V(Function.prototype, apply, FunctionApply) \
V(Function.prototype, call, FunctionCall) \
V(String.prototype, charCodeAt, StringCharCodeAt) \
V(String.prototype, charAt, StringCharAt) \
V(String, fromCharCode, StringFromCharCode) \

View File

@ -0,0 +1,154 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --noalways-opt
var global = this;
Array.prototype.f = function() {
return 0;
};
(function() {
var called = 0;
function g(x, y, called) {
return called + 1;
}
function f(deopt, called) {
return g([].f.call({}), deopt + 1, called);
}
called = f(0, called);
called = f(0, called);
%OptimizeFunctionOnNextCall(f);
called = f(0, called);
assertOptimized(f);
called = f({}, called);
assertUnoptimized(f);
assertEquals(4, called);
})();
(function() {
// The array built-ins are only inlined if the receiver is a
// HConstant, this seems to require a *unique* global identifier
// each time.
global.a1 = [1,2,3,4];
var obj = {value: 3};
function f(b) {
return [].pop.call(a1) + b.value;
}
assertEquals(7, f(obj));
assertEquals(6, f(obj));
%OptimizeFunctionOnNextCall(f);
assertEquals(5, f(obj));
assertOptimized(f);
assertEquals(4, f({d: 0, value: 3}));
assertUnoptimized(f);
assertEquals(0, a1.length);
})();
(function() {
global.a2 = [1,2,3,4];
var obj = {value: 3};
function f(b) {
return [].shift.call(a2) + b.value;
}
assertEquals(4, f(obj));
assertEquals(5, f(obj));
%OptimizeFunctionOnNextCall(f);
assertEquals(6, f(obj));
assertOptimized(f);
assertEquals(7, f({d: 0, value: 3}));
assertUnoptimized(f);
assertEquals(0, a2.length);
})();
(function() {
global.a3 = [1,2,3,4];
var obj = {value: 3};
function f(b) {
return [].push.call(a3, b.value);
}
assertEquals(5, f(obj));
assertEquals(6, f(obj));
%OptimizeFunctionOnNextCall(f);
assertEquals(7, f(obj));
assertOptimized(f);
assertEquals(8, f({d: 0, value: 3}));
assertUnoptimized(f);
assertEquals(8, a3.length);
assertEquals(3, a3[7]);
})();
(function() {
global.a4 = [1,2,3,4];
var obj = {value: 3};
function f(b) {
return [].indexOf.call(a4, b.value);
}
f(obj);
f(obj);
%OptimizeFunctionOnNextCall(f);
var index1 = f(obj);
assertOptimized(f);
var index2 = f({d: 0, value: 3});
assertUnoptimized(f);
assertEquals(2, index1);
assertEquals(index1, index2);
})();
(function() {
global.a5 = [1,2,3,4];
var obj = {value: 3};
function f(b) {
return [].lastIndexOf.call(a5, b.value);
}
f(obj);
f(obj);
%OptimizeFunctionOnNextCall(f);
var index1 = f(obj);
assertOptimized(f);
var index2 = f({d: 0, value: 3});
assertUnoptimized(f);
assertEquals(2, index1);
assertEquals(index1, index2);
})();

View File

@ -0,0 +1,43 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --noalways-opt
(function() {
function f(x) {
for (i = 0; i < 1; i++) {
x.call(this);
}
}
function g() {}
f(g);
f(g);
%OptimizeFunctionOnNextCall(f);
assertThrows(function() { f('whatever') }, TypeError);
})();

View File

@ -0,0 +1,190 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --noalways-opt
var global = this;
// For the HConstant
Array.prototype.fun = function() {
funRecv = this;
called++;
assertEquals(0, arguments.length);
};
Array.prototype.funStrict = function() {
"use strict";
funStrictRecv = this;
called++;
assertEquals(0, arguments.length);
};
Array.prototype.manyArgs = function() {
"use strict";
assertEquals(5, arguments.length);
assertEquals(0, this);
assertEquals(5, arguments[4]);
called++;
}
Array.prototype.manyArgsSloppy = function() {
assertEquals(global, this);
assertEquals(5, arguments.length);
assertEquals(5, arguments[4]);
called++;
}
var array = [];
for (var i = 0; i < 100; ++i) {
array[i] = i;
}
var copy = array.slice();
function unshiftsArray(num) {
[].unshift.call(array, num);
}
unshiftsArray(50);
unshiftsArray(60);
%OptimizeFunctionOnNextCall(unshiftsArray);
unshiftsArray(80);
unshiftsArray(50);
unshiftsArray(60);
copy.unshift(50);
copy.unshift(60);
copy.unshift(80);
copy.unshift(50);
copy.unshift(60);
assertOptimized(unshiftsArray);
assertArrayEquals(array, copy);
var called = 0;
var funRecv;
function callNoArgs() {
[].fun.call();
}
callNoArgs();
callNoArgs();
assertEquals(this, funRecv);
%OptimizeFunctionOnNextCall(callNoArgs);
callNoArgs();
assertEquals(this, funRecv);
assertEquals(3, called);
assertOptimized(callNoArgs);
var funStrictRecv;
called = 0;
function callStrictNoArgs() {
[].funStrict.call();
}
callStrictNoArgs();
callStrictNoArgs();
assertEquals(undefined, funStrictRecv);
%OptimizeFunctionOnNextCall(callStrictNoArgs);
callStrictNoArgs();
assertEquals(undefined, funStrictRecv);
assertEquals(3, called);
assertOptimized(callStrictNoArgs);
called = 0;
function callManyArgs() {
[].manyArgs.call(0, 1, 2, 3, 4, 5);
}
callManyArgs();
callManyArgs();
%OptimizeFunctionOnNextCall(callManyArgs);
callManyArgs();
assertOptimized(callManyArgs);
assertEquals(called, 3);
called = 0;
function callManyArgsSloppy() {
[].manyArgsSloppy.call(null, 1, 2, 3, 4, 5);
}
callManyArgsSloppy();
callManyArgsSloppy();
%OptimizeFunctionOnNextCall(callManyArgsSloppy);
callManyArgsSloppy();
assertOptimized(callManyArgsSloppy);
assertEquals(called, 3);
var str = "hello";
var code = str.charCodeAt(3);
called = 0;
function callBuiltinIndirectly() {
called++;
return "".charCodeAt.call(str, 3);
}
callBuiltinIndirectly();
callBuiltinIndirectly();
%OptimizeFunctionOnNextCall(callBuiltinIndirectly);
assertEquals(code, callBuiltinIndirectly());
assertOptimized(callBuiltinIndirectly);
assertEquals(3, called);
this.array = [1,2,3,4,5,6,7,8,9];
var copy = this.array.slice();
called = 0;
function callInlineableBuiltinIndirectlyWhileInlined() {
called++;
return [].push.apply(array, arguments);
}
function callInlined(num) {
return callInlineableBuiltinIndirectlyWhileInlined(num);
}
callInlineableBuiltinIndirectlyWhileInlined(1);
callInlineableBuiltinIndirectlyWhileInlined(2);
%OptimizeFunctionOnNextCall(callInlineableBuiltinIndirectlyWhileInlined);
callInlineableBuiltinIndirectlyWhileInlined(3);
assertOptimized(callInlineableBuiltinIndirectlyWhileInlined);
callInlined(1);
callInlined(2);
%OptimizeFunctionOnNextCall(callInlined);
callInlined(3);
copy.push(1, 2, 3, 1, 2, 3);
assertOptimized(callInlined);
assertArrayEquals(copy, this.array);
assertEquals(6, called);

View File

@ -0,0 +1,70 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --noalways-opt
var calls = 0;
function callsFReceiver(o) {
return [].f.call(new Number(o.m), 1, 2, 3);
}
// For the HConstant
Array.prototype.f = function() {
calls++;
return +this;
};
var o1 = {m: 1};
var o2 = {a: 0, m:1};
var r1 = callsFReceiver(o1);
callsFReceiver(o1);
%OptimizeFunctionOnNextCall(callsFReceiver);
var r2 = callsFReceiver(o1);
assertOptimized(callsFReceiver);
callsFReceiver(o2);
assertUnoptimized(callsFReceiver);
var r3 = callsFReceiver(o1);
assertEquals(1, r1);
assertTrue(r1 === r2);
assertTrue(r2 === r3);
r1 = callsFReceiver(o1);
callsFReceiver(o1);
%OptimizeFunctionOnNextCall(callsFReceiver);
r2 = callsFReceiver(o1);
callsFReceiver(o2);
r3 = callsFReceiver(o1);
assertEquals(1, r1);
assertTrue(r1 === r2);
assertTrue(r2 === r3);
assertEquals(10, calls);