[runtime] Replace many buggy uses of %_CallFunction with %_Call.

The semantics of the %_CallFunction intrinsic seem to be very unclear,
which resulted in a lot of bugs. Especially the combination with
%IsSloppyModeFunction is always a bug, because the receiver would be
wrapped in the wrong context. So the %IsSloppyModeFunction helper is
gone now, and many of the buggy uses of %_CallFunction are also
eliminated.

If you ever need to call something with a different receiver, then
%_Call is your friend now. It does what you want and implements the
call sequence fully (and correct).

BUG=v8:4413
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#30634}
This commit is contained in:
bmeurer 2015-09-08 06:35:20 -07:00 committed by Commit bot
parent e615c03ba1
commit db2ba190db
35 changed files with 316 additions and 182 deletions

View File

@ -192,6 +192,15 @@ void CallConstructDescriptor::InitializePlatformSpecific(
}
void CallTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r0 : number of arguments
// r1 : the target to call
Register registers[] = {r1, r0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {r2, r1, r0};

View File

@ -207,6 +207,15 @@ void CallConstructDescriptor::InitializePlatformSpecific(
}
void CallTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// x1: target
// x0: number of arguments
Register registers[] = {x1, x0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// x2: length

View File

@ -390,7 +390,7 @@ function ArrayToString() {
if (!IS_CALLABLE(func)) {
return %_CallFunction(array, ObjectToString);
}
return %_CallFunction(array, func);
return %_Call(func, array);
}
@ -903,7 +903,7 @@ function InnerArraySort(array, length, comparefn) {
var element = a[i];
for (var j = i - 1; j >= from; j--) {
var tmp = a[j];
var order = %_CallFunction(UNDEFINED, tmp, element, comparefn);
var order = comparefn(tmp, element);
if (order > 0) {
a[j + 1] = tmp;
} else {
@ -922,7 +922,7 @@ function InnerArraySort(array, length, comparefn) {
t_array[j] = [i, a[i]];
}
%_CallFunction(t_array, function(a, b) {
return %_CallFunction(UNDEFINED, a[1], b[1], comparefn);
return comparefn(a[1], b[1]);
}, ArraySort);
var third_index = t_array[t_array.length >> 1][0];
return third_index;
@ -945,14 +945,14 @@ function InnerArraySort(array, length, comparefn) {
var v0 = a[from];
var v1 = a[to - 1];
var v2 = a[third_index];
var c01 = %_CallFunction(UNDEFINED, v0, v1, comparefn);
var c01 = comparefn(v0, v1);
if (c01 > 0) {
// v1 < v0, so swap them.
var tmp = v0;
v0 = v1;
v1 = tmp;
} // v0 <= v1.
var c02 = %_CallFunction(UNDEFINED, v0, v2, comparefn);
var c02 = comparefn(v0, v2);
if (c02 >= 0) {
// v2 <= v0 <= v1.
var tmp = v0;
@ -961,7 +961,7 @@ function InnerArraySort(array, length, comparefn) {
v1 = tmp;
} else {
// v0 <= v1 && v0 < v2
var c12 = %_CallFunction(UNDEFINED, v1, v2, comparefn);
var c12 = comparefn(v1, v2);
if (c12 > 0) {
// v0 <= v2 < v1
var tmp = v1;
@ -982,7 +982,7 @@ function InnerArraySort(array, length, comparefn) {
// From i to high_start are elements that haven't been compared yet.
partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i];
var order = %_CallFunction(UNDEFINED, element, pivot, comparefn);
var order = comparefn(element, pivot);
if (order < 0) {
a[i] = a[low_end];
a[low_end] = element;
@ -992,7 +992,7 @@ function InnerArraySort(array, length, comparefn) {
high_start--;
if (high_start == i) break partition;
var top_elem = a[high_start];
order = %_CallFunction(UNDEFINED, top_elem, pivot, comparefn);
order = comparefn(top_elem, pivot);
} while (order > 0);
a[i] = a[high_start];
a[high_start] = element;
@ -1179,12 +1179,6 @@ function ArraySort(comparefn) {
// or delete elements from the array.
function InnerArrayFilter(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(f)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var accumulator = new InternalArray();
var accumulator_length = 0;
@ -1195,8 +1189,7 @@ function InnerArrayFilter(f, receiver, array, length) {
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
if (%_CallFunction(new_receiver, element, i, array, f)) {
if (%_Call(f, receiver, element, i, array)) {
accumulator[accumulator_length++] = element;
}
}
@ -1219,12 +1212,6 @@ function ArrayFilter(f, receiver) {
function InnerArrayForEach(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(f)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
@ -1233,8 +1220,7 @@ function InnerArrayForEach(f, receiver, array, length) {
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
%_CallFunction(new_receiver, element, i, array, f);
%_Call(f, receiver, element, i, array);
}
}
}
@ -1252,12 +1238,6 @@ function ArrayForEach(f, receiver) {
function InnerArraySome(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(f)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
@ -1266,8 +1246,7 @@ function InnerArraySome(f, receiver, array, length) {
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
if (%_CallFunction(new_receiver, element, i, array, f)) return true;
if (%_Call(f, receiver, element, i, array)) return true;
}
}
return false;
@ -1289,12 +1268,6 @@ function ArraySome(f, receiver) {
function InnerArrayEvery(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(f)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
@ -1303,8 +1276,7 @@ function InnerArrayEvery(f, receiver, array, length) {
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
if (!%_CallFunction(new_receiver, element, i, array, f)) return false;
if (!%_Call(f, receiver, element, i, array)) return false;
}
}
return true;
@ -1323,12 +1295,6 @@ function ArrayEvery(f, receiver) {
function InnerArrayMap(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(f)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var accumulator = new InternalArray(length);
var is_array = IS_ARRAY(array);
@ -1338,8 +1304,7 @@ function InnerArrayMap(f, receiver, array, length) {
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
accumulator[i] = %_CallFunction(new_receiver, element, i, array, f);
accumulator[i] = %_Call(f, receiver, element, i, array);
}
}
return accumulator;
@ -1508,7 +1473,7 @@ function InnerArrayReduce(callback, current, array, length, argumentsLength) {
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(callback);
current = %_CallFunction(UNDEFINED, current, element, i, array, callback);
current = callback(current, element, i, array);
}
}
return current;
@ -1551,7 +1516,7 @@ function InnerArrayReduceRight(callback, current, array, length,
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(callback);
current = %_CallFunction(UNDEFINED, current, element, i, array, callback);
current = callback(current, element, i, array);
}
}
return current;

View File

@ -139,7 +139,7 @@ function SetConstructor(iterable) {
}
for (var value of iterable) {
%_CallFunction(this, value, adder);
%_Call(adder, this, value);
}
}
}
@ -246,12 +246,6 @@ function SetForEach(f, receiver) {
}
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(f)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var iterator = new SetIterator(this, ITERATOR_KIND_VALUES);
var key;
@ -260,8 +254,7 @@ function SetForEach(f, receiver) {
while (%SetIteratorNext(iterator, value_array)) {
if (stepping) %DebugPrepareStepInIfStepping(f);
key = value_array[0];
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
%_CallFunction(new_receiver, key, key, this, f);
%_Call(f, receiver, key, key, this);
}
}
@ -307,7 +300,7 @@ function MapConstructor(iterable) {
if (!IS_SPEC_OBJECT(nextItem)) {
throw MakeTypeError(kIteratorValueNotAnObject, nextItem);
}
%_CallFunction(this, nextItem[0], nextItem[1], adder);
%_Call(adder, this, nextItem[0], nextItem[1]);
}
}
}
@ -437,20 +430,13 @@ function MapForEach(f, receiver) {
}
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
if (%IsSloppyModeFunction(f)) receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var iterator = new MapIterator(this, ITERATOR_KIND_ENTRIES);
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var value_array = [UNDEFINED, UNDEFINED];
while (%MapIteratorNext(iterator, value_array)) {
if (stepping) %DebugPrepareStepInIfStepping(f);
var new_receiver = needs_wrapper ? TO_OBJECT(receiver) : receiver;
%_CallFunction(new_receiver, value_array[1], value_array[0], this, f);
%_Call(f, receiver, value_array[1], value_array[0], this);
}
}
@ -486,7 +472,7 @@ function MapFromArray(array) {
for (var i = 0; i < length; i += 2) {
var key = array[i];
var value = array[i + 1];
%_CallFunction(map, key, value, MapSet);
%_Call(MapSet, map, key, value);
}
return map;
};
@ -495,7 +481,7 @@ function SetFromArray(array) {
var set = new GlobalSet;
var length = array.length;
for (var i = 0; i < length; ++i) {
%_CallFunction(set, array[i], SetAdd);
%_Call(SetAdd, set, array[i]);
}
return set;
};

View File

@ -238,6 +238,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kTraceExit:
return 0;
case Runtime::kInlineArguments:
case Runtime::kInlineCall:
case Runtime::kInlineCallFunction:
case Runtime::kInlineDefaultConstructorCallSuper:
case Runtime::kInlineGetCallerJSFunction:

View File

@ -4056,6 +4056,26 @@ void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
}
void FullCodeGenerator::EmitCall(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_LE(2, args->length());
// Push target, receiver and arguments onto the stack.
for (Expression* const arg : *args) {
VisitForStackValue(arg);
}
// Move target to r1.
int const argc = args->length() - 2;
__ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize));
// Call the target.
__ mov(r0, Operand(argc));
__ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
context()->DropAndPlug(1, r0);
}
void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() >= 2);
@ -4081,7 +4101,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
__ bind(&runtime);
__ push(r0);
__ CallRuntime(Runtime::kCall, args->length());
__ CallRuntime(Runtime::kCallFunction, args->length());
__ bind(&done);
context()->Plug(r0);

View File

@ -3785,6 +3785,27 @@ void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
}
void FullCodeGenerator::EmitCall(CallRuntime* expr) {
ASM_LOCATION("FullCodeGenerator::EmitCallFunction");
ZoneList<Expression*>* args = expr->arguments();
DCHECK_LE(2, args->length());
// Push target, receiver and arguments onto the stack.
for (Expression* const arg : *args) {
VisitForStackValue(arg);
}
// Move target to x1.
int const argc = args->length() - 2;
__ Peek(x1, (argc + 1) * kXRegSize);
// Call the target.
__ Mov(x0, argc);
__ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
// Restore context register.
__ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
context()->DropAndPlug(1, x0);
}
void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
ASM_LOCATION("FullCodeGenerator::EmitCallFunction");
ZoneList<Expression*>* args = expr->arguments();
@ -3810,7 +3831,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
__ Bind(&runtime);
__ Push(x0);
__ CallRuntime(Runtime::kCall, args->length());
__ CallRuntime(Runtime::kCallFunction, args->length());
__ Bind(&done);
context()->Plug(x0);

View File

@ -493,6 +493,7 @@ class FullCodeGenerator: public AstVisitor {
F(IsRegExp) \
F(IsJSProxy) \
F(IsConstructCall) \
F(Call) \
F(CallFunction) \
F(DefaultConstructorCallSuper) \
F(ArgumentsLength) \

View File

@ -3965,6 +3965,26 @@ void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
}
void FullCodeGenerator::EmitCall(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_LE(2, args->length());
// Push target, receiver and arguments onto the stack.
for (Expression* const arg : *args) {
VisitForStackValue(arg);
}
// Move target to edi.
int const argc = args->length() - 2;
__ mov(edi, Operand(esp, (argc + 1) * kPointerSize));
// Call the target.
__ mov(eax, Immediate(argc));
__ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
context()->DropAndPlug(1, eax);
}
void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() >= 2);
@ -3990,7 +4010,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
__ bind(&runtime);
__ push(eax);
__ CallRuntime(Runtime::kCall, args->length());
__ CallRuntime(Runtime::kCallFunction, args->length());
__ bind(&done);
context()->Plug(eax);

View File

@ -4078,6 +4078,26 @@ void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
}
void FullCodeGenerator::EmitCall(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_LE(2, args->length());
// Push target, receiver and arguments onto the stack.
for (Expression* const arg : *args) {
VisitForStackValue(arg);
}
// Move target to a1.
int const argc = args->length() - 2;
__ lw(a1, MemOperand(sp, (argc + 1) * kPointerSize));
// Call the target.
__ li(a0, Operand(argc));
__ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
context()->DropAndPlug(1, v0);
}
void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() >= 2);
@ -4103,7 +4123,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
__ bind(&runtime);
__ push(v0);
__ CallRuntime(Runtime::kCall, args->length());
__ CallRuntime(Runtime::kCallFunction, args->length());
__ bind(&done);
context()->Plug(v0);

View File

@ -4082,6 +4082,26 @@ void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
}
void FullCodeGenerator::EmitCall(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_LE(2, args->length());
// Push target, receiver and arguments onto the stack.
for (Expression* const arg : *args) {
VisitForStackValue(arg);
}
// Move target to a1.
int const argc = args->length() - 2;
__ ld(a1, MemOperand(sp, (argc + 1) * kPointerSize));
// Call the target.
__ li(a0, Operand(argc));
__ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
// Restore context register.
__ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
context()->DropAndPlug(1, v0);
}
void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() >= 2);
@ -4107,7 +4127,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
__ bind(&runtime);
__ push(v0);
__ CallRuntime(Runtime::kCall, args->length());
__ CallRuntime(Runtime::kCallFunction, args->length());
__ bind(&done);
context()->Plug(v0);

View File

@ -3952,6 +3952,26 @@ void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
}
void FullCodeGenerator::EmitCall(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK_LE(2, args->length());
// Push target, receiver and arguments onto the stack.
for (Expression* const arg : *args) {
VisitForStackValue(arg);
}
// Move target to rdi.
int const argc = args->length() - 2;
__ movp(rdi, Operand(rsp, (argc + 1) * kPointerSize));
// Call the target.
__ Set(rax, argc);
__ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
// Restore context register.
__ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
context()->DropAndPlug(1, rax);
}
void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() >= 2);
@ -3977,7 +3997,7 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
__ bind(&runtime);
__ Push(rax);
__ CallRuntime(Runtime::kCall, args->length());
__ CallRuntime(Runtime::kCallFunction, args->length());
__ bind(&done);
context()->Plug(rax);

View File

@ -95,17 +95,9 @@ function InnerArrayFind(predicate, thisArg, array, length) {
throw MakeTypeError(kCalledNonCallable, predicate);
}
var needs_wrapper = false;
if (IS_NULL(thisArg)) {
if (%IsSloppyModeFunction(predicate)) thisArg = UNDEFINED;
} else if (!IS_UNDEFINED(thisArg)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
}
for (var i = 0; i < length; i++) {
var element = array[i];
var newThisArg = needs_wrapper ? TO_OBJECT(thisArg) : thisArg;
if (%_CallFunction(newThisArg, element, i, array, predicate)) {
if (%_Call(predicate, thisArg, element, i, array)) {
return element;
}
}
@ -128,17 +120,9 @@ function InnerArrayFindIndex(predicate, thisArg, array, length) {
throw MakeTypeError(kCalledNonCallable, predicate);
}
var needs_wrapper = false;
if (IS_NULL(thisArg)) {
if (%IsSloppyModeFunction(predicate)) thisArg = UNDEFINED;
} else if (!IS_UNDEFINED(thisArg)) {
needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
}
for (var i = 0; i < length; i++) {
var element = array[i];
var newThisArg = needs_wrapper ? TO_OBJECT(thisArg) : thisArg;
if (%_CallFunction(newThisArg, element, i, array, predicate)) {
if (%_Call(predicate, thisArg, element, i, array)) {
return i;
}
}
@ -212,12 +196,6 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
if (mapping) {
if (!IS_CALLABLE(mapfn)) {
throw MakeTypeError(kCalledNonCallable, mapfn);
} else if (%IsSloppyModeFunction(mapfn)) {
if (IS_NULL(receiver)) {
receiver = UNDEFINED;
} else if (!IS_UNDEFINED(receiver)) {
receiver = TO_OBJECT(receiver);
}
}
}
@ -247,7 +225,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
nextValue = next.value;
if (mapping) {
mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
mappedValue = %_Call(mapfn, receiver, nextValue, k);
} else {
mappedValue = nextValue;
}
@ -261,7 +239,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
for (k = 0; k < len; ++k) {
nextValue = items[k];
if (mapping) {
mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
mappedValue = %_Call(mapfn, receiver, nextValue, k);
} else {
mappedValue = nextValue;
}

View File

@ -277,7 +277,7 @@ function TypedArrayToLocaleString() {
// ES6 section 22.2.3.28
function TypedArrayToString() {
return %_CallFunction(this, ArrayToString);
return %_Call(ArrayToString, this);
}
@ -372,7 +372,7 @@ function TypedArrayOf() {
function TypedArrayFrom(source, mapfn, thisArg) {
// TODO(littledan): Investigate if there is a receiver which could be
// faster to accumulate on than Array, e.g., a TypedVector.
var array = %_CallFunction(GlobalArray, source, mapfn, thisArg, ArrayFrom);
var array = %_Call(ArrayFrom, GlobalArray, source, mapfn, thisArg);
return ConstructTypedArray(this, array);
}
%FunctionSetLength(TypedArrayFrom, 1);

View File

@ -12477,6 +12477,23 @@ void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
}
// Fast support for calls.
void HOptimizedGraphBuilder::GenerateCall(CallRuntime* call) {
DCHECK_LE(2, call->arguments()->length());
CHECK_ALIVE(VisitExpressions(call->arguments()));
CallTrampolineDescriptor descriptor(isolate());
PushArgumentsFromEnvironment(call->arguments()->length() - 1);
HValue* trampoline = Add<HConstant>(isolate()->builtins()->Call());
HValue* target = Pop();
HValue* values[] = {context(), target,
Add<HConstant>(call->arguments()->length() - 2)};
HInstruction* result = New<HCallWithDescriptor>(
trampoline, call->arguments()->length() - 1, descriptor,
Vector<HValue*>(values, arraysize(values)));
return ast_context()->ReturnInstruction(result, call->id());
}
// Fast call for custom callbacks.
void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
// 1 ~ The function to call is not itself an argument to the call.

View File

@ -2209,6 +2209,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
F(IsRegExp) \
F(IsJSProxy) \
F(IsConstructCall) \
F(Call) \
F(CallFunction) \
F(ArgumentsLength) \
F(Arguments) \

View File

@ -198,6 +198,15 @@ void CallConstructDescriptor::InitializePlatformSpecific(
}
void CallTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// eax : number of arguments
// edi : the target to call
Register registers[] = {edi, eax};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {ecx, ebx, eax};

View File

@ -354,6 +354,19 @@ CreateWeakCellDescriptor::BuildCallInterfaceDescriptorFunctionType(
}
Type::FunctionType*
CallTrampolineDescriptor::BuildCallInterfaceDescriptorFunctionType(
Isolate* isolate, int paramater_count) {
Zone* zone = isolate->interface_descriptor_zone();
Type::FunctionType* function =
Type::FunctionType::New(AnyTagged(zone), Type::Undefined(), 2, zone);
function->InitParameter(0, AnyTagged(zone)); // target
function->InitParameter(
1, UntaggedSigned32(zone)); // actual number of arguments
return function;
}
Type::FunctionType*
CallFunctionWithFeedbackDescriptor::BuildCallInterfaceDescriptorFunctionType(
Isolate* isolate, int paramater_count) {

View File

@ -37,6 +37,7 @@ class PlatformInterfaceDescriptor;
V(CallFunctionWithFeedback) \
V(CallFunctionWithFeedbackAndVector) \
V(CallConstruct) \
V(CallTrampoline) \
V(RegExpConstructResult) \
V(TransitionElementsKind) \
V(AllocateHeapNumber) \
@ -430,6 +431,13 @@ class CreateWeakCellDescriptor : public CallInterfaceDescriptor {
};
class CallTrampolineDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(CallTrampolineDescriptor,
CallInterfaceDescriptor)
};
class CallFunctionDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(CallFunctionDescriptor, CallInterfaceDescriptor)

View File

@ -52,7 +52,7 @@ function Revive(holder, name, reviver) {
}
}
}
return %_CallFunction(holder, name, val, reviver);
return %_Call(reviver, holder, name, val);
}
@ -147,11 +147,11 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) {
if (IS_SPEC_OBJECT(value)) {
var toJSON = value.toJSON;
if (IS_CALLABLE(toJSON)) {
value = %_CallFunction(value, key, toJSON);
value = %_Call(toJSON, value, key);
}
}
if (IS_CALLABLE(replacer)) {
value = %_CallFunction(holder, key, value, replacer);
value = %_Call(replacer, holder, key, value);
}
if (IS_STRING(value)) {
return %QuoteJSONString(value);

View File

@ -156,7 +156,6 @@ macro TO_PRIMITIVE_STRING(arg) = (%_ToPrimitive_String(arg));
macro TO_NAME(arg) = (%_ToName(arg));
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
macro HAS_OWN_PROPERTY(arg, index) = (%_CallFunction(arg, index, ObjectHasOwnProperty));
macro SHOULD_CREATE_WRAPPER(functionName, receiver) = (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(functionName));
macro HAS_INDEX(array, index, is_array) = ((is_array && %_HasFastPackedElements(%IS_VAR(array))) ? (index < array.length) : (index in array));
# Private names.

View File

@ -190,6 +190,15 @@ void CallConstructDescriptor::InitializePlatformSpecific(
}
void CallTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: target
// a0: number of arguments
Register registers[] = {a1, a0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {a2, a1, a0};

View File

@ -190,6 +190,15 @@ void CallConstructDescriptor::InitializePlatformSpecific(
}
void CallTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: target
// a0: number of arguments
Register registers[] = {a1, a0};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {a2, a1, a0};

View File

@ -601,7 +601,7 @@ function NativeObjectNotifierPerformChange(objectInfo, changeType, changeFn) {
var changeRecord;
try {
changeRecord = %_CallFunction(UNDEFINED, changeFn);
changeRecord = changeFn();
} finally {
ObjectInfoRemovePerformingType(objectInfo, changeType);
}

View File

@ -88,7 +88,7 @@ function PromiseCoerce(constructor, x) {
if (IS_CALLABLE(then)) {
var deferred = %_CallFunction(constructor, PromiseDeferred);
try {
%_CallFunction(x, deferred.resolve, deferred.reject, then);
%_Call(then, x, deferred.resolve, deferred.reject);
} catch(r) {
deferred.reject(r);
}

View File

@ -717,14 +717,14 @@ function IsConcatSpreadable(O) {
function DefaultNumber(x) {
var valueOf = x.valueOf;
if (IS_CALLABLE(valueOf)) {
var v = %_CallFunction(x, valueOf);
var v = %_Call(valueOf, x);
if (IS_SYMBOL(v)) throw MakeTypeError(kSymbolToNumber);
if (IS_SIMD_VALUE(x)) throw MakeTypeError(kSimdToNumber);
if (IsPrimitive(v)) return v;
}
var toString = x.toString;
if (IS_CALLABLE(toString)) {
var s = %_CallFunction(x, toString);
var s = %_Call(toString, x);
if (IsPrimitive(s)) return s;
}
throw MakeTypeError(kCannotConvertToPrimitive);
@ -736,13 +736,13 @@ function DefaultString(x) {
if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToString);
var toString = x.toString;
if (IS_CALLABLE(toString)) {
var s = %_CallFunction(x, toString);
var s = %_Call(toString, x);
if (IsPrimitive(s)) return s;
}
var valueOf = x.valueOf;
if (IS_CALLABLE(valueOf)) {
var v = %_CallFunction(x, valueOf);
var v = %_Call(valueOf, x);
if (IsPrimitive(v)) return v;
}
}

View File

@ -16,27 +16,6 @@
namespace v8 {
namespace internal {
// TODO(bmeurer): This is an awful hack resulting from our inability to decide
// who's responsible for doing the receiver patching. By any means, we really
// need to kill this runtime function and just do things right instead!!
RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
if (!callable->IsJSFunction()) {
HandleScope scope(isolate);
Handle<JSFunction> delegate;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, delegate,
Execution::GetFunctionDelegate(isolate, Handle<JSReceiver>(callable)));
callable = JSFunction::cast(*delegate);
}
JSFunction* function = JSFunction::cast(callable);
SharedFunctionInfo* shared = function->shared();
return isolate->heap()->ToBoolean(is_sloppy(shared->language_mode()));
}
RUNTIME_FUNCTION(Runtime_FunctionGetName) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
@ -532,32 +511,18 @@ RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
RUNTIME_FUNCTION(Runtime_Call) {
HandleScope scope(isolate);
DCHECK(args.length() >= 2);
int argc = args.length() - 2;
CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
Object* receiver = args[0];
// 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);
}
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] = Handle<Object>(args[1 + i], isolate);
argv[i] = args.at<Object>(2 + i);
}
Handle<JSReceiver> hfun(fun);
Handle<Object> hreceiver(receiver, isolate);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
Execution::Call(isolate, hfun, hreceiver, argc, argv, true));
Execution::Call(isolate, target, receiver, argc, argv.start(), true));
return *result;
}
@ -634,9 +599,37 @@ RUNTIME_FUNCTION(Runtime_GetOriginalConstructor) {
}
// TODO(bmeurer): Kill %_CallFunction ASAP as it is almost never used
// correctly because of the weird semantics underneath.
RUNTIME_FUNCTION(Runtime_CallFunction) {
SealHandleScope shs(isolate);
return __RT_impl_Runtime_Call(args, isolate);
HandleScope scope(isolate);
DCHECK(args.length() >= 2);
int argc = args.length() - 2;
CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
Object* receiver = args[0];
// 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) {
argv[i] = Handle<Object>(args[1 + i], isolate);
}
Handle<JSReceiver> hfun(fun);
Handle<Object> hreceiver(receiver, isolate);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
Execution::Call(isolate, hfun, hreceiver, argc, argv, true));
return *result;
}

View File

@ -218,7 +218,6 @@ namespace internal {
#define FOR_EACH_INTRINSIC_FUNCTION(F) \
F(IsSloppyModeFunction, 1, 1) \
F(FunctionGetName, 1, 1) \
F(FunctionSetName, 2, 1) \
F(FunctionNameShouldPrintAsAnonymous, 1, 1) \

View File

@ -314,8 +314,7 @@ function StringReplace(search, replace) {
// Compute the string to replace with.
if (IS_CALLABLE(replace)) {
var receiver = UNDEFINED;
result += %_CallFunction(receiver, search, start, subject, replace);
result += replace(search, start, subject);
} else {
reusableMatchInfo[CAPTURE0] = start;
reusableMatchInfo[CAPTURE1] = end;
@ -478,8 +477,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
override[0] = elem;
override[1] = match_start;
$regexpLastMatchInfoOverride = override;
var func_result =
%_CallFunction(UNDEFINED, elem, match_start, subject, replace);
var func_result = replace(elem, match_start, subject);
// Overwrite the i'th element in the results with the string we got
// back from the callback function.
res[i] = TO_STRING_INLINE(func_result);
@ -525,7 +523,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
// No captures, only the match, which is always valid.
var s = %_SubString(subject, index, endOfMatch);
// Don't call directly to avoid exposing the built-in global object.
replacement = %_CallFunction(UNDEFINED, s, index, subject, replace);
replacement = replace(s, index, subject);
} else {
var parameters = new InternalArray(m + 2);
for (var j = 0; j < m; j++) {

View File

@ -143,7 +143,7 @@ function NAMEConstructByIterable(obj, iterable, iteratorFn) {
// was already looked up, and wrap it in another iterable. The
// __proto__ of the new iterable is set to null to avoid any chance
// of modifications to Object.prototype being observable here.
var iterator = %_CallFunction(iterable, iteratorFn);
var iterator = %_Call(iteratorFn, iterable);
var newIterable = {
__proto__: null
};

View File

@ -32,7 +32,7 @@ function WeakMapConstructor(iterable) {
if (!IS_SPEC_OBJECT(nextItem)) {
throw MakeTypeError(kIteratorValueNotAnObject, nextItem);
}
%_CallFunction(this, nextItem[0], nextItem[1], adder);
%_Call(adder, this, nextItem[0], nextItem[1]);
}
}
}
@ -118,7 +118,7 @@ function WeakSetConstructor(iterable) {
throw MakeTypeError(kPropertyNotFunction, 'add', this);
}
for (var value of iterable) {
%_CallFunction(this, value, adder);
%_Call(adder, this, value);
}
}
}

View File

@ -191,6 +191,15 @@ void CallConstructDescriptor::InitializePlatformSpecific(
}
void CallTrampolineDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// rax : number of arguments
// rdi : the target to call
Register registers[] = {rdi, rax};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void RegExpConstructResultDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {rcx, rbx, rax};

View File

@ -87,7 +87,7 @@ function WrapInCatcher(f, holder) {
function WrapInNativeCall(f) {
return function() {
return %Call(undefined, f);
return %Call(f, undefined);
};
}

View File

@ -106,10 +106,10 @@ function TestCall(isStrict, callTrap) {
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
assertSame(o, receiver)
receiver = 333
assertEquals(42, %Call(o, 11, 31, f))
assertEquals(42, %Call(f, o, 11, 31));
assertSame(o, receiver)
receiver = 333
assertEquals(42, %Call(null, 11, 31, f))
assertEquals(42, %Call(f, null, 11, 31));
assertSame(isStrict ? null : global_object, receiver)
receiver = 333
assertEquals(42, %Apply(f, o, [11, 31], 0, 2))
@ -136,10 +136,10 @@ function TestCall(isStrict, callTrap) {
assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
assertSame(o, receiver)
receiver = 333
assertEquals(23, %Call({}, 11, ff))
assertEquals(23, %Call(ff, {}, 11));
assertSame(o, receiver)
receiver = 333
assertEquals(23, %Call({}, 11, 3, ff))
assertEquals(23, %Call(ff, {}, 11, 3));
assertSame(o, receiver)
receiver = 333
assertEquals(24, %Apply(ff, {}, [12, 13], 0, 1))
@ -166,10 +166,10 @@ function TestCall(isStrict, callTrap) {
assertEquals(42, Function.prototype.apply.call(fff, {}))
assertSame(o, receiver)
receiver = 333
assertEquals(42, %Call({}, fff))
assertEquals(42, %Call(fff, {}));
assertSame(o, receiver)
receiver = 333
assertEquals(42, %Call({}, 11, 3, fff))
assertEquals(42, %Call(fff, {}, 11, 3))
assertSame(o, receiver)
receiver = 333
assertEquals(42, %Apply(fff, {}, [], 0, 0))
@ -211,7 +211,7 @@ function TestCall(isStrict, callTrap) {
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
assertSame(o, receiver)
receiver = 333
assertEquals(23, %Call(o, 11, 12, f))
assertEquals(23, %Call(f, o, 11, 12))
assertSame(o, receiver)
receiver = 333
assertEquals(27, %Apply(f, o, [12, 13, 14], 1, 2))
@ -280,8 +280,8 @@ function TestCallThrow(callTrap) {
assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
assertThrows(function(){ %Call({}, f) }, "myexn")
assertThrows(function(){ %Call({}, 1, 2, f) }, "myexn")
assertThrows(function(){ %Call(f, {}) }, "myexn")
assertThrows(function(){ %Call(f, {}, 1, 2) }, "myexn")
assertThrows(function(){ %Apply({}, f, [], 3, 0) }, "myexn")
assertThrows(function(){ %Apply({}, f, [3, 4], 0, 1) }, "myexn")
assertThrows(function(){ %_CallFunction({}, f) }, "myexn")
@ -293,8 +293,8 @@ function TestCallThrow(callTrap) {
assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
assertThrows(function(){ %Call({}, f) }, "myexn")
assertThrows(function(){ %Call({}, 1, 2, f) }, "myexn")
assertThrows(function(){ %Call(f, {}) }, "myexn")
assertThrows(function(){ %Call(f, {}, 1, 2) }, "myexn")
assertThrows(function(){ %Apply({}, f, [], 3, 0) }, "myexn")
assertThrows(function(){ %Apply({}, f, [3, 4], 0, 1) }, "myexn")
assertThrows(function(){ %_CallFunction({}, f) }, "myexn")
@ -698,7 +698,7 @@ function TestCalls() {
function(f, x, y, o) { return Function.prototype.call.call(f, o, x, y) },
function(f, x, y, o) { return Function.prototype.apply.call(f, o, [x, y]) },
function(f, x, y, o) { return %_CallFunction(o, x, y, f) },
function(f, x, y, o) { return %Call(o, x, y, f) },
function(f, x, y, o) { return %Call(f, o, x, y) },
function(f, x, y, o) { return %Apply(f, o, [null, x, y, null], 1, 2) },
function(f, x, y, o) { return %Apply(f, o, arguments, 2, 2) },
function(f, x, y, o) { if (typeof o == "object") return o.f(x, y) },

View File

@ -72,7 +72,7 @@ function generateSpread(n) {
`f.bind(undefined)(${generateArguments(argumentCount)})`,
`%_CallFunction(${generateArguments(argumentCount, 'undefined')},
f)`,
`%Call(${generateArguments(argumentCount, 'undefined')}, f)`,
`%Call(f, ${generateArguments(argumentCount, 'undefined')})`,
`%Apply(f, undefined, [${generateArguments(argumentCount)}], 0,
${argumentCount})`,
];
@ -135,7 +135,7 @@ function generateSpread(n) {
`o.m.apply(o, [${generateArguments(argumentCount)}])`,
`o.m.bind(o)(${generateArguments(argumentCount)})`,
`%_CallFunction(${generateArguments(argumentCount, 'o')}, o.m)`,
`%Call(${generateArguments(argumentCount, 'o')}, o.m)`,
`%Call(o.m, ${generateArguments(argumentCount, 'o')})`,
`%Apply(o.m, o, [${generateArguments(argumentCount)}], 0,
${argumentCount})`,
];