[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:
parent
e615c03ba1
commit
db2ba190db
@ -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};
|
||||
|
@ -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
|
||||
|
65
src/array.js
65
src/array.js
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -493,6 +493,7 @@ class FullCodeGenerator: public AstVisitor {
|
||||
F(IsRegExp) \
|
||||
F(IsJSProxy) \
|
||||
F(IsConstructCall) \
|
||||
F(Call) \
|
||||
F(CallFunction) \
|
||||
F(DefaultConstructorCallSuper) \
|
||||
F(ArgumentsLength) \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -2209,6 +2209,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
F(IsRegExp) \
|
||||
F(IsJSProxy) \
|
||||
F(IsConstructCall) \
|
||||
F(Call) \
|
||||
F(CallFunction) \
|
||||
F(ArgumentsLength) \
|
||||
F(Arguments) \
|
||||
|
@ -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};
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -601,7 +601,7 @@ function NativeObjectNotifierPerformChange(objectInfo, changeType, changeFn) {
|
||||
|
||||
var changeRecord;
|
||||
try {
|
||||
changeRecord = %_CallFunction(UNDEFINED, changeFn);
|
||||
changeRecord = changeFn();
|
||||
} finally {
|
||||
ObjectInfoRemovePerformingType(objectInfo, changeType);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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++) {
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -87,7 +87,7 @@ function WrapInCatcher(f, holder) {
|
||||
|
||||
function WrapInNativeCall(f) {
|
||||
return function() {
|
||||
return %Call(undefined, f);
|
||||
return %Call(f, undefined);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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) },
|
||||
|
@ -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})`,
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user