Commit 7f11fba7 authored by bmeurer's avatar bmeurer Committed by Commit bot

[runtime] Remove obsolete %Apply and %TailCall runtime entries.

The %TailCall runtime entry and the %_TailCall intrinsic is not used,
and will never be used (because %TailCall doesn't actually do a tail
call). We will soon have proper ES6 tail calls, which are correct and
properly tested.

The %Apply runtime entry is basically a super-slow, less correct version
of Reflect.apply, so we can as well just use Reflect.apply, which is
exposed to builtins via %reflect_apply.

R=ishell@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#34317}
parent 45876462
......@@ -95,8 +95,6 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
return ReduceToString(node);
case Runtime::kInlineCall:
return ReduceCall(node);
case Runtime::kInlineTailCall:
return ReduceTailCall(node);
case Runtime::kInlineGetSuperConstructor:
return ReduceGetSuperConstructor(node);
default:
......@@ -507,16 +505,6 @@ Reduction JSIntrinsicLowering::ReduceCall(Node* node) {
}
Reduction JSIntrinsicLowering::ReduceTailCall(Node* node) {
size_t const arity = CallRuntimeParametersOf(node->op()).arity();
NodeProperties::ChangeOp(node,
javascript()->CallFunction(arity, VectorSlotPair(),
ConvertReceiverMode::kAny,
TailCallMode::kAllow));
return Changed(node);
}
Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) {
Node* active_function = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
......
......@@ -66,7 +66,6 @@ class JSIntrinsicLowering final : public AdvancedReducer {
Reduction ReduceToPrimitive(Node* node);
Reduction ReduceToString(Node* node);
Reduction ReduceCall(Node* node);
Reduction ReduceTailCall(Node* node);
Reduction ReduceGetSuperConstructor(Node* node);
Reduction Change(Node* node, const Operator* op);
......
......@@ -180,7 +180,6 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kInlineToString:
return 1;
case Runtime::kInlineCall:
case Runtime::kInlineTailCall:
case Runtime::kInlineDeoptimizeNow:
case Runtime::kInlineThrowNotDateError:
return 2;
......
......@@ -323,14 +323,14 @@ extrasUtils.createPrivateSymbol = function createPrivateSymbol(name) {
// indirection and slowness given how un-optimized bind is.
extrasUtils.simpleBind = function simpleBind(func, thisArg) {
return function() {
return %Apply(func, thisArg, arguments, 0, arguments.length);
return function(...args) {
return %reflect_apply(func, thisArg, args);
};
};
extrasUtils.uncurryThis = function uncurryThis(func) {
return function(thisArg) {
return %Apply(func, thisArg, arguments, 1, arguments.length - 1);
return function(thisArg, ...args) {
return %reflect_apply(func, thisArg, args);
};
};
......
......@@ -458,7 +458,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
if (!%_IsSmi(elem)) {
// elem must be an Array.
// Use the apply argument as backing for global RegExp properties.
var func_result = %Apply(replace, UNDEFINED, elem, 0, elem.length);
var func_result = %reflect_apply(replace, UNDEFINED, elem);
// Overwrite the i'th element in the results with the string we got
// back from the callback function.
res[i] = TO_STRING(func_result);
......@@ -512,7 +512,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
parameters[j] = index;
parameters[j + 1] = subject;
replacement = %Apply(replace, UNDEFINED, parameters, 0, j + 2);
replacement = %reflect_apply(replace, UNDEFINED, parameters);
}
result += replacement; // The add method converts to string if necessary.
......
......@@ -267,61 +267,6 @@ RUNTIME_FUNCTION(Runtime_Call) {
}
RUNTIME_FUNCTION(Runtime_TailCall) {
HandleScope scope(isolate);
DCHECK_LE(2, args.length());
int const argc = args.length() - 2;
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, target, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
ScopedVector<Handle<Object>> argv(argc);
for (int i = 0; i < argc; ++i) {
argv[i] = args.at<Object>(2 + i);
}
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
Execution::Call(isolate, target, receiver, argc, argv.start()));
return *result;
}
RUNTIME_FUNCTION(Runtime_Apply) {
HandleScope scope(isolate);
DCHECK(args.length() == 5);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
CONVERT_INT32_ARG_CHECKED(offset, 3);
CONVERT_INT32_ARG_CHECKED(argc, 4);
RUNTIME_ASSERT(offset >= 0);
// Loose upper bound to allow fuzzing. We'll most likely run out of
// stack space before hitting this limit.
static int kMaxArgc = 1000000;
RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc);
// If there are too many arguments, allocate argv via malloc.
const int argv_small_size = 10;
Handle<Object> argv_small_buffer[argv_small_size];
base::SmartArrayPointer<Handle<Object> > argv_large_buffer;
Handle<Object>* argv = argv_small_buffer;
if (argc > argv_small_size) {
argv = new Handle<Object>[argc];
if (argv == NULL) return isolate->StackOverflow();
argv_large_buffer = base::SmartArrayPointer<Handle<Object> >(argv);
}
for (int i = 0; i < argc; ++i) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, argv[i], Object::GetElement(isolate, arguments, offset + i));
}
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, Execution::Call(isolate, fun, receiver, argc, argv));
return *result;
}
// ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee.
RUNTIME_FUNCTION(Runtime_ConvertReceiver) {
HandleScope scope(isolate);
......
......@@ -236,8 +236,6 @@ namespace internal {
F(IsConstructor, 1, 1) \
F(SetForceInlineFlag, 1, 1) \
F(Call, -1 /* >= 2 */, 1) \
F(TailCall, -1 /* >= 2 */, 1) \
F(Apply, 5, 1) \
F(ConvertReceiver, 1, 1) \
F(IsFunction, 1, 1) \
F(FunctionToString, 1, 1)
......
......@@ -72,8 +72,7 @@ function generateSpread(n) {
`f.bind(undefined)(${generateArguments(argumentCount)})`,
`%_Call(f, ${generateArguments(argumentCount, 'undefined')})`,
`%Call(f, ${generateArguments(argumentCount, 'undefined')})`,
`%Apply(f, undefined, [${generateArguments(argumentCount)}], 0,
${argumentCount})`,
`Reflect.apply(f, undefined, [${generateArguments(argumentCount)}])`,
];
for (let call of calls) {
......@@ -135,8 +134,7 @@ function generateSpread(n) {
`o.m.bind(o)(${generateArguments(argumentCount)})`,
`%_Call(o.m, ${generateArguments(argumentCount, 'o')})`,
`%Call(o.m, ${generateArguments(argumentCount, 'o')})`,
`%Apply(o.m, o, [${generateArguments(argumentCount)}], 0,
${argumentCount})`,
`Reflect.apply(o.m, o, [${generateArguments(argumentCount)}])`,
];
for (let call of calls) {
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --nostress-opt --turbo
// Flags: --nonative-context-specialization
var p0 = new Object();
var p1 = new Object();
var p2 = new Object();
// Ensure 1 parameter passed straight-through is handled correctly
var count1 = 100000;
tailee1 = function() {
"use strict";
if (count1-- == 0) {
return this;
}
return %_TailCall(tailee1, this);
};
%OptimizeFunctionOnNextCall(tailee1);
assertEquals(p0, tailee1.call(p0));
// Ensure 2 parameters passed straight-through trigger a tail call are handled
// correctly and don't cause a stack overflow.
var count2 = 100000;
tailee2 = function(px) {
"use strict";
assertEquals(p2, px);
assertEquals(p1, this);
count2 = ((count2 | 0) - 1) | 0;
if ((count2 | 0) === 0) {
return this;
}
return %_TailCall(tailee2, this, px);
};
%OptimizeFunctionOnNextCall(tailee2);
assertEquals(p1, tailee2.call(p1, p2));
// Ensure swapped 2 parameters trigger a tail call and do the appropriate
// parameters swapping
var count3 = 999999;
tailee3 = function(px) {
"use strict";
if (count3-- == 0) {
return this;
}
return %_TailCall(tailee3, px, this);
};
%OptimizeFunctionOnNextCall(tailee3);
assertEquals(p2, tailee3.call(p1, p2));
// Ensure too many parameters defeats the tail call optimization (currently
// unsupported).
var count4 = 1000000;
tailee4 = function(px) {
"use strict";
if (count4-- == 0) {
return this;
}
return %_TailCall(tailee4, this, px, undefined);
};
%OptimizeFunctionOnNextCall(tailee4);
assertThrows(function() { tailee4.call(p1, p2); });
// Ensure that calling the arguments adapter defeats the tail call optimization.
var count5 = 1000000;
tailee5 = function(px) {
"use strict";
if (count5-- == 0) {
return this;
}
return %_TailCall(tailee5, this);
};
%OptimizeFunctionOnNextCall(tailee5);
assertThrows(function() { tailee5.call(p1, p2); });
// Ensure tail calls with fewer stack parameters properly re-arranges the stack.
tailee6 = function(px) {
return px;
}
tailee7 = function(px, py, pz, pa, pb, pc) {
"use strict";
return %_TailCall(tailee6, this, pc);
};
%OptimizeFunctionOnNextCall(tailee6);
%OptimizeFunctionOnNextCall(tailee7);
assertEquals(110, tailee7.call(null, 15, 16, 17, 18, 0, 110));
tailee8 = function(px, py, pz, pa, pb) {
return pb + pz + px;
}
tailee9 = function(px, py, pz, pa, pb, pc) {
"use strict";
return %_TailCall(tailee8, this, pb, py, px, pa, pz);
};
%OptimizeFunctionOnNextCall(tailee8);
%OptimizeFunctionOnNextCall(tailee9);
assertEquals(32, tailee9.call(null, 15, 16, 17, 18, 0, 110));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment