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:
parent
37f1645023
commit
23868b419c
177
src/hydrogen.cc
177
src/hydrogen.cc
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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) \
|
||||
|
154
test/mjsunit/compiler/deopt-inlined-from-call.js
Normal file
154
test/mjsunit/compiler/deopt-inlined-from-call.js
Normal 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);
|
||||
})();
|
43
test/mjsunit/compiler/inlined-call-mapcheck.js
Normal file
43
test/mjsunit/compiler/inlined-call-mapcheck.js
Normal 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);
|
||||
})();
|
190
test/mjsunit/compiler/inlined-call.js
Normal file
190
test/mjsunit/compiler/inlined-call.js
Normal 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);
|
70
test/mjsunit/regress/regress-385565.js
Normal file
70
test/mjsunit/regress/regress-385565.js
Normal 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);
|
Loading…
Reference in New Issue
Block a user