Commit 634d1d86 authored by bmeurer's avatar bmeurer Committed by Commit bot

[builtin] Refactor Invoke to deal with any kind of callable.

Now both Execution::Call and Execution::New can deal with any
kind of target and will raise a proper exception if the target is not
callable (which is not yet spec compliant for New, as we would
have to check IsConstructor instead, which we don't have yet).

Now we no longer need to do any of these weird call/construct
delegate gymnastics in C++, and we finally have a single true
bottleneck for Call/Construct abstract operations in the code
base, with only a few special handlings left in the compilers to
optimize the JSFunction case.

R=jarin@chromium.org
BUG=v8:4430, v8:4413
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#30874}
parent c281c15d
......@@ -4244,18 +4244,9 @@ MaybeLocal<Value> Object::CallAsFunction(Local<Context> context,
auto recv_obj = Utils::OpenHandle(*recv);
STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**));
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
i::Handle<i::JSFunction> fun;
if (self->IsJSFunction()) {
fun = i::Handle<i::JSFunction>::cast(self);
} else {
has_pending_exception =
!i::Execution::GetFunctionDelegate(isolate, self).ToHandle(&fun);
RETURN_ON_FAILED_EXECUTION(Value);
recv_obj = self;
}
Local<Value> result;
has_pending_exception = !ToLocal<Value>(
i::Execution::Call(isolate, fun, recv_obj, argc, args), &result);
i::Execution::Call(isolate, self, recv_obj, argc, args), &result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
......@@ -4278,21 +4269,9 @@ MaybeLocal<Value> Object::CallAsConstructor(Local<Context> context, int argc,
auto self = Utils::OpenHandle(this);
STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Object**));
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
if (self->IsJSFunction()) {
auto fun = i::Handle<i::JSFunction>::cast(self);
Local<Value> result;
has_pending_exception =
!ToLocal<Value>(i::Execution::New(fun, argc, args), &result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
i::Handle<i::JSFunction> fun;
has_pending_exception =
!i::Execution::GetConstructorDelegate(isolate, self).ToHandle(&fun);
RETURN_ON_FAILED_EXECUTION(Value);
Local<Value> result;
has_pending_exception = !ToLocal<Value>(
i::Execution::Call(isolate, fun, self, argc, args), &result);
i::Execution::New(isolate, self, self, argc, args), &result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
......
......@@ -1585,13 +1585,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// -- r1 : the target to call (can be any Object).
// -----------------------------------
Label non_smi, non_function;
__ JumpIfSmi(r1, &non_function);
Label non_callable, non_function, non_smi;
__ JumpIfSmi(r1, &non_callable);
__ bind(&non_smi);
__ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
eq);
__ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
__ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
__ b(ne, &non_function);
// 1. Call to function proxy.
......@@ -1603,27 +1603,23 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
__ bind(&non_function);
// TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
// be awesome instead; i.e. a trivial improvement would be to call into the
// runtime and just deal with the API function there instead of returning a
// delegate from a runtime call that just jumps back to the runtime once
// called. Or, bonus points, call directly into the C API function here, as
// we do in some Crankshaft fast cases.
// Overwrite the original receiver with the (original) target.
// Check if target has a [[Call]] internal method.
__ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
__ tst(r4, Operand(1 << Map::kIsCallable));
__ b(eq, &non_callable);
// Overwrite the original receiver the (original) target.
__ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(r0);
__ Push(r0, r1);
__ CallRuntime(Runtime::kGetFunctionDelegate, 1);
__ mov(r1, r0);
__ Pop(r0);
__ SmiUntag(r0);
__ Push(r1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(r1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......@@ -1658,32 +1654,40 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -----------------------------------
Label slow;
__ JumpIfSmi(r1, &slow);
__ CompareObjectType(r1, r5, r5, JS_FUNCTION_TYPE);
Label non_callable, non_function;
__ JumpIfSmi(r1, &non_callable);
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq);
__ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
__ b(ne, &slow);
__ b(ne, &non_function);
// 1. Construct of function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
__ ldr(r1, FieldMemOperand(r1, JSFunctionProxy::kConstructTrapOffset));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
__ bind(&slow);
// 2. Construct of something that else, which might have a [[Construct]]
// internal method (if not we raise an exception).
__ bind(&non_function);
// Check if target has a [[Call]] internal method.
// TODO(bmeurer): This shoud use IsConstructor once available.
__ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
__ tst(r4, Operand(1 << Map::kIsCallable));
__ b(eq, &non_callable);
// Overwrite the original receiver the (original) target.
__ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Construct of something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(r0);
__ Push(r0, r1);
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
__ mov(r1, r0);
__ Pop(r0);
__ SmiUntag(r0);
__ Push(r1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(r1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......
......@@ -1647,14 +1647,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// -- x1 : the target to call (can be any Object).
// -----------------------------------
Label non_smi, non_jsfunction, non_function;
__ JumpIfSmi(x1, &non_function);
Label non_callable, non_function, non_smi;
__ JumpIfSmi(x1, &non_callable);
__ Bind(&non_smi);
__ CompareObjectType(x1, x2, x2, JS_FUNCTION_TYPE);
__ B(ne, &non_jsfunction);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
__ Bind(&non_jsfunction);
__ Cmp(x2, JS_FUNCTION_PROXY_TYPE);
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
eq);
__ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
__ B(ne, &non_function);
// 1. Call to function proxy.
......@@ -1666,27 +1665,22 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
__ Bind(&non_function);
// TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
// be awesome instead; i.e. a trivial improvement would be to call into the
// runtime and just deal with the API function there instead of returning a
// delegate from a runtime call that just jumps back to the runtime once
// called. Or, bonus points, call directly into the C API function here, as
// we do in some Crankshaft fast cases.
// Check if target has a [[Call]] internal method.
__ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x4, 1 << Map::kIsCallable, &non_callable);
// Overwrite the original receiver with the (original) target.
__ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, x1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(x0);
__ Push(x0, x1);
__ CallRuntime(Runtime::kGetFunctionDelegate, 1);
__ Mov(x1, x0);
__ Pop(x0);
__ SmiUntag(x0);
__ Push(x1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(x1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......@@ -1722,32 +1716,39 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -----------------------------------
Label slow;
__ JumpIfSmi(x1, &slow);
__ CompareObjectType(x1, x5, x5, JS_FUNCTION_TYPE);
Label non_callable, non_function;
__ JumpIfSmi(x1, &non_callable);
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq);
__ Cmp(x5, Operand(JS_FUNCTION_PROXY_TYPE));
__ B(ne, &slow);
__ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
__ B(ne, &non_function);
// 1. Construct of function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
__ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kConstructTrapOffset));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
__ Bind(&slow);
// 2. Construct of something that else, which might have a [[Construct]]
// internal method (if not we raise an exception).
__ Bind(&non_function);
// Check if target has a [[Call]] internal method.
// TODO(bmeurer): This shoud use IsConstructor once available.
__ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x4, 1 << Map::kIsCallable, &non_callable);
// Overwrite the original receiver with the (original) target.
__ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Construct of something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(x0);
__ Push(x0, x1);
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
__ Mov(x1, x0);
__ Pop(x0);
__ SmiUntag(x0);
__ Push(x1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(x1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......
......@@ -178,13 +178,13 @@ double Simulator::CallDouble(byte* entry, CallArgument* args) {
int64_t Simulator::CallJS(byte* entry,
Object* new_target,
JSFunction* func,
Object* target,
Object* revc,
int64_t argc,
Object*** argv) {
CallArgument args[] = {
CallArgument(new_target),
CallArgument(func),
CallArgument(target),
CallArgument(revc),
CallArgument(argc),
CallArgument(argv),
......@@ -193,6 +193,7 @@ int64_t Simulator::CallJS(byte* entry,
return CallInt64(entry, args);
}
int64_t Simulator::CallRegExp(byte* entry,
String* input,
int64_t start_offset,
......
......@@ -188,7 +188,7 @@ class Simulator : public DecoderVisitor {
// which set up the simulator state and grab the result on return.
int64_t CallJS(byte* entry,
Object* new_target,
JSFunction* func,
Object* target,
Object* revc,
int64_t argc,
Object*** argv);
......
......@@ -9,8 +9,6 @@
#include "src/deoptimizer.h"
#include "src/isolate-inl.h"
#include "src/messages.h"
#include "src/parser.h"
#include "src/prettyprinter.h"
#include "src/vm-state-inl.h"
namespace v8 {
......@@ -55,47 +53,12 @@ static void PrintDeserializedCodeInfo(Handle<JSFunction> function) {
namespace {
MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
Handle<JSFunction> function,
MUST_USE_RESULT MaybeHandle<Object> Invoke(Isolate* isolate, bool is_construct,
Handle<Object> target,
Handle<Object> receiver, int argc,
Handle<Object> args[],
Handle<Object> new_target) {
Isolate* const isolate = function->GetIsolate();
// Convert calls on global objects to be calls on the global
// receiver instead to avoid having a 'this' pointer which refers
// directly to a global object.
if (receiver->IsGlobalObject()) {
receiver =
handle(Handle<GlobalObject>::cast(receiver)->global_proxy(), isolate);
}
// api callbacks can be called directly.
if (!is_construct && function->shared()->IsApiFunction()) {
SaveContext save(isolate);
isolate->set_context(function->context());
// Do proper receiver conversion for non-strict mode api functions.
if (!receiver->IsJSReceiver() &&
is_sloppy(function->shared()->language_mode())) {
if (receiver->IsUndefined() || receiver->IsNull()) {
receiver = handle(function->global_proxy(), isolate);
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, receiver, Execution::ToObject(isolate, receiver), Object);
}
}
DCHECK(function->context()->global_object()->IsGlobalObject());
auto value = Builtins::InvokeApiFunction(function, receiver, argc, args);
bool has_exception = value.is_null();
DCHECK(has_exception == isolate->has_pending_exception());
if (has_exception) {
isolate->ReportPendingMessages();
return MaybeHandle<Object>();
} else {
isolate->clear_pending_message();
}
return value;
}
DCHECK(!receiver->IsGlobalObject());
// Entering JavaScript.
VMState<JS> state(isolate);
......@@ -109,7 +72,7 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
// Placeholder for return value.
Object* value = NULL;
typedef Object* (*JSEntryFunction)(Object* new_target, Object* function,
typedef Object* (*JSEntryFunction)(Object* new_target, Object* target,
Object* receiver, int argc,
Object*** args);
......@@ -117,10 +80,6 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
? isolate->factory()->js_construct_entry_code()
: isolate->factory()->js_entry_code();
// Make sure that the global object of the context we're about to
// make the current one is indeed a global object.
DCHECK(function->context()->global_object()->IsGlobalObject());
{
// Save and restore context around invocation and block the
// allocation of handles without explicit handle scopes.
......@@ -130,10 +89,12 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
// Call the function through the right JS entry stub.
Object* orig_func = *new_target;
JSFunction* func = *function;
Object* func = *target;
Object* recv = *receiver;
Object*** argv = reinterpret_cast<Object***>(args);
if (FLAG_profile_deserialization) PrintDeserializedCodeInfo(function);
if (FLAG_profile_deserialization && target->IsJSFunction()) {
PrintDeserializedCodeInfo(Handle<JSFunction>::cast(target));
}
value = CALL_GENERATED_CODE(stub_entry, orig_func, func, recv, argc, argv);
}
......@@ -163,30 +124,64 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
} // namespace
// static
MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
Handle<Object> receiver, int argc,
Handle<Object> argv[]) {
if (!callable->IsJSFunction()) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, callable,
GetFunctionDelegate(isolate, callable), Object);
// Convert calls on global objects to be calls on the global
// receiver instead to avoid having a 'this' pointer which refers
// directly to a global object.
if (receiver->IsGlobalObject()) {
receiver =
handle(Handle<GlobalObject>::cast(receiver)->global_proxy(), isolate);
}
// api callbacks can be called directly.
if (callable->IsJSFunction() &&
Handle<JSFunction>::cast(callable)->shared()->IsApiFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
SaveContext save(isolate);
isolate->set_context(function->context());
// Do proper receiver conversion for non-strict mode api functions.
if (!receiver->IsJSReceiver() &&
is_sloppy(function->shared()->language_mode())) {
if (receiver->IsUndefined() || receiver->IsNull()) {
receiver = handle(function->global_proxy(), isolate);
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, receiver, Execution::ToObject(isolate, receiver), Object);
}
}
Handle<JSFunction> func = Handle<JSFunction>::cast(callable);
return Invoke(false, func, receiver, argc, argv,
DCHECK(function->context()->global_object()->IsGlobalObject());
auto value = Builtins::InvokeApiFunction(function, receiver, argc, argv);
bool has_exception = value.is_null();
DCHECK(has_exception == isolate->has_pending_exception());
if (has_exception) {
isolate->ReportPendingMessages();
return MaybeHandle<Object>();
} else {
isolate->clear_pending_message();
}
return value;
}
return Invoke(isolate, false, callable, receiver, argc, argv,
isolate->factory()->undefined_value());
}
// static
MaybeHandle<Object> Execution::New(Handle<JSFunction> constructor, int argc,
Handle<Object> argv[]) {
return New(constructor, constructor, argc, argv);
return New(constructor->GetIsolate(), constructor, constructor, argc, argv);
}
MaybeHandle<Object> Execution::New(Handle<JSFunction> constructor,
Handle<JSFunction> new_target, int argc,
// static
MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
Handle<Object> new_target, int argc,
Handle<Object> argv[]) {
return Invoke(true, constructor, handle(constructor->global_proxy()), argc,
argv, new_target);
return Invoke(isolate, true, constructor,
isolate->factory()->undefined_value(), argc, argv, new_target);
}
......@@ -234,98 +229,6 @@ MaybeHandle<Object> Execution::TryCall(Handle<JSFunction> func,
}
// static
MaybeHandle<JSFunction> Execution::GetFunctionDelegate(Isolate* isolate,
Handle<Object> object) {
DCHECK(!object->IsJSFunction());
if (object->IsHeapObject()) {
DisallowHeapAllocation no_gc;
// If object is a function proxy, get its handler. Iterate if necessary.
Object* fun = *object;
while (fun->IsJSFunctionProxy()) {
fun = JSFunctionProxy::cast(fun)->call_trap();
}
if (fun->IsJSFunction()) {
return handle(JSFunction::cast(fun), isolate);
}
// We can also have exotic objects with [[Call]] internal methods.
if (fun->IsCallable()) {
return handle(isolate->native_context()->call_as_function_delegate(),
isolate);
}
}
// If the Object doesn't have an instance-call handler we should
// throw a non-callable exception.
Handle<String> callsite = RenderCallSite(isolate, object);
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kCalledNonCallable, callsite),
JSFunction);
}
// static
MaybeHandle<JSFunction> Execution::GetConstructorDelegate(
Isolate* isolate, Handle<Object> object) {
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a constructor.
DCHECK(!object->IsJSFunction());
if (object->IsHeapObject()) {
DisallowHeapAllocation no_gc;
// If object is a function proxies, get its handler. Iterate if necessary.
Object* fun = *object;
while (fun->IsJSFunctionProxy()) {
// TODO(bmeurer): This should work based on [[Construct]]; our proxies
// are screwed.
fun = JSFunctionProxy::cast(fun)->call_trap();
}
if (fun->IsJSFunction()) {
return handle(JSFunction::cast(fun), isolate);
}
// We can also have exotic objects with [[Construct]] internal methods.
// TODO(bmeurer): This should use IsConstructor() as dictacted by the spec.
if (fun->IsCallable()) {
return handle(isolate->native_context()->call_as_constructor_delegate(),
isolate);
}
}
// If the Object doesn't have an instance-call handler we should
// throw a non-callable exception.
Handle<String> callsite = RenderCallSite(isolate, object);
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kCalledNonCallable, callsite),
JSFunction);
}
// static
Handle<String> Execution::RenderCallSite(Isolate* isolate,
Handle<Object> object) {
MessageLocation location;
if (isolate->ComputeLocation(&location)) {
Zone zone;
base::SmartPointer<ParseInfo> info(
location.function()->shared()->is_function()
? new ParseInfo(&zone, location.function())
: new ParseInfo(&zone, location.script()));
if (Parser::ParseStatic(info.get())) {
CallPrinter printer(isolate, &zone);
const char* string = printer.Print(info->literal(), location.start_pos());
return isolate->factory()->NewStringFromAsciiChecked(string);
} else {
isolate->clear_pending_exception();
}
}
return Object::TypeOf(isolate, object);
}
void StackGuard::SetStackLimit(uintptr_t limit) {
ExecutionAccess access(isolate_);
// If the current limits are special (e.g. due to a pending interrupt) then
......
......@@ -35,8 +35,9 @@ class Execution final : public AllStatic {
MUST_USE_RESULT static MaybeHandle<Object> New(Handle<JSFunction> constructor,
int argc,
Handle<Object> argv[]);
MUST_USE_RESULT static MaybeHandle<Object> New(Handle<JSFunction> constructor,
Handle<JSFunction> new_target,
MUST_USE_RESULT static MaybeHandle<Object> New(Isolate* isolate,
Handle<Object> constructor,
Handle<Object> new_target,
int argc,
Handle<Object> argv[]);
......@@ -88,20 +89,6 @@ class Execution final : public AllStatic {
Handle<JSFunction> fun,
Handle<Object> pos,
Handle<Object> is_global);
// Get a function delegate for the given non-function object.
// Used for support calling objects as functions.
MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionDelegate(
Isolate* isolate, Handle<Object> object);
// Get a function delegate (or undefined) for the given non-function
// object. Used for support calling objects as constructors.
MUST_USE_RESULT static MaybeHandle<JSFunction> GetConstructorDelegate(
Isolate* isolate, Handle<Object> object);
private:
MUST_USE_RESULT static Handle<String> RenderCallSite(Isolate* isolate,
Handle<Object> object);
};
......
......@@ -1516,13 +1516,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// -- edi : the target to call (can be any Object).
// -----------------------------------
Label non_smi, non_function;
__ JumpIfSmi(edi, &non_function);
Label non_callable, non_function, non_smi;
__ JumpIfSmi(edi, &non_callable);
__ bind(&non_smi);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, edx);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &non_function);
// 1. Call to function proxy.
......@@ -1534,28 +1534,22 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
__ bind(&non_function);
// TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
// be awesome instead; i.e. a trivial improvement would be to call into the
// runtime and just deal with the API function there instead of returning a
// delegate from a runtime call that just jumps back to the runtime once
// called. Or, bonus points, call directly into the C API function here, as
// we do in some Crankshaft fast cases.
// Check if target has a [[Call]] internal method.
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
__ j(zero, &non_callable, Label::kNear);
// Overwrite the original receiver with the (original) target.
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(eax);
__ Push(eax);
__ Push(edi);
__ CallRuntime(Runtime::kGetFunctionDelegate, 1);
__ mov(edi, eax);
__ Pop(eax);
__ SmiUntag(eax);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(edi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......@@ -1591,33 +1585,39 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -- edi : the constructor to call (can be any Object)
// -----------------------------------
Label slow;
__ JumpIfSmi(edi, &slow, Label::kNear);
Label non_callable, non_function;
__ JumpIfSmi(edi, &non_callable);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &slow, Label::kNear);
__ j(not_equal, &non_function, Label::kNear);
// 1. Construct of function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
__ mov(edi, FieldOperand(edi, JSFunctionProxy::kConstructTrapOffset));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
__ bind(&slow);
// 2. Construct of something else, which might have a [[Construct]] internal
// method (if not we raise an exception).
__ bind(&non_function);
// Check if target has a [[Call]] internal method.
// TODO(bmeurer): This shoud use IsConstructor once available.
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
__ j(zero, &non_callable, Label::kNear);
// Overwrite the original receiver with the (original) target.
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Construct of something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(eax);
__ Push(eax);
__ Push(edi);
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
__ mov(edi, eax);
__ Pop(eax);
__ SmiUntag(eax);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(edi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......
......@@ -1596,14 +1596,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// -- a1 : the target to call (can be any Object).
// -----------------------------------
Label non_smi, non_function;
__ JumpIfSmi(a1, &non_function);
Label non_callable, non_function, non_smi;
__ JumpIfSmi(a1, &non_callable);
__ bind(&non_smi);
__ GetObjectType(a1, a2, a2);
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
eq, a2, Operand(JS_FUNCTION_TYPE));
__ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
eq, t2, Operand(JS_FUNCTION_TYPE));
__ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
// 1. Call to function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
......@@ -1614,29 +1613,25 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
__ bind(&non_function);
// TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
// be awesome instead; i.e. a trivial improvement would be to call into the
// runtime and just deal with the API function there instead of returning a
// delegate from a runtime call that just jumps back to the runtime once
// called. Or, bonus points, call directly into the C API function here, as
// we do in some Crankshaft fast cases.
// Check if target has a [[Call]] internal method.
__ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t1, t1, Operand(1 << Map::kIsCallable));
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
// Overwrite the original receiver with the (original) target.
__ sll(at, a0, kPointerSizeLog2);
__ addu(at, sp, at);
__ sw(a1, MemOperand(at));
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ sll(a0, a0, kSmiTagSize); // Smi tagged.
__ Push(a0, a1);
__ CallRuntime(Runtime::kGetFunctionDelegate, 1);
__ mov(a1, v0);
__ Pop(a0);
__ sra(a0, a0, kSmiTagSize); // Un-tag.
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......@@ -1672,31 +1667,41 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -----------------------------------
Label slow;
__ JumpIfSmi(a1, &slow);
__ GetObjectType(a1, t1, t1);
Label non_callable, non_function;
__ JumpIfSmi(a1, &non_callable);
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, t1, Operand(JS_FUNCTION_TYPE));
__ Branch(&slow, ne, t1, Operand(JS_FUNCTION_PROXY_TYPE));
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
// 1. Construct of function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
__ lw(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
__ bind(&slow);
// 2. Construct of something that else, which might have a [[Construct]]
// internal method (if not we raise an exception).
__ bind(&non_function);
// Check if target has a [[Call]] internal method.
// TODO(bmeurer): This shoud use IsConstructor once available.
__ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t1, t1, Operand(1 << Map::kIsCallable));
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
// Overwrite the original receiver with the (original) target.
__ sll(at, a0, kPointerSizeLog2);
__ addu(at, sp, at);
__ sw(a1, MemOperand(at));
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Construct of something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(a0);
__ Push(a0, a1);
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
__ mov(a1, v0);
__ Pop(a0);
__ SmiUntag(a0);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......
......@@ -1593,13 +1593,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// -- a1 : the target to call (can be any Object).
// -----------------------------------
Label non_smi, non_function;
__ JumpIfSmi(a1, &non_function);
Label non_callable, non_function, non_smi;
__ JumpIfSmi(a1, &non_callable);
__ bind(&non_smi);
__ GetObjectType(a1, a2, a2);
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET,
eq, a2, Operand(JS_FUNCTION_TYPE));
__ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
eq, t2, Operand(JS_FUNCTION_TYPE));
__ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
// 1. Call to function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies.
......@@ -1610,29 +1610,25 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
__ bind(&non_function);
// TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
// be awesome instead; i.e. a trivial improvement would be to call into the
// runtime and just deal with the API function there instead of returning a
// delegate from a runtime call that just jumps back to the runtime once
// called. Or, bonus points, call directly into the C API function here, as
// we do in some Crankshaft fast cases.
// Check if target has a [[Call]] internal method.
__ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t1, t1, Operand(1 << Map::kIsCallable));
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
// Overwrite the original receiver with the (original) target.
__ dsll(at, a0, kPointerSizeLog2);
__ daddu(at, sp, at);
__ sd(a1, MemOperand(at));
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(a0);
__ Push(a0, a1);
__ CallRuntime(Runtime::kGetFunctionDelegate, 1);
__ mov(a1, v0);
__ Pop(a0);
__ SmiUntag(a0);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......@@ -1667,31 +1663,41 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -----------------------------------
Label slow;
__ JumpIfSmi(a1, &slow);
__ GetObjectType(a1, a5, a5);
Label non_callable, non_function;
__ JumpIfSmi(a1, &non_callable);
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, a5, Operand(JS_FUNCTION_TYPE));
__ Branch(&slow, ne, a5, Operand(JS_FUNCTION_PROXY_TYPE));
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
// 1. Construct of function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
__ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
__ bind(&slow);
// 2. Construct of something that else, which might have a [[Construct]]
// internal method (if not we raise an exception).
__ bind(&non_function);
// Check if target has a [[Call]] internal method.
// TODO(bmeurer): This shoud use IsConstructor once available.
__ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t1, t1, Operand(1 << Map::kIsCallable));
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
// Overwrite the original receiver with the (original) target.
__ dsll(at, a0, kPointerSizeLog2);
__ daddu(at, sp, at);
__ sd(a1, MemOperand(at));
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Construct of something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(a0);
__ Push(a0, a1);
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
__ mov(a1, v0);
__ Pop(a0);
__ SmiUntag(a0);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(a1);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......
......@@ -520,7 +520,8 @@ RUNTIME_FUNCTION(Runtime_DefaultConstructorCallSuper) {
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, Execution::New(super_constructor, original_constructor,
isolate, result,
Execution::New(isolate, super_constructor, original_constructor,
argument_count, arguments.get()));
return *result;
......
......@@ -494,16 +494,9 @@ RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
bound_args->get(JSFunction::kBoundArgumentsStartIndex + i), isolate);
}
if (!bound_function->IsJSFunction()) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, bound_function,
Execution::GetConstructorDelegate(isolate, bound_function));
}
DCHECK(bound_function->IsJSFunction());
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, Execution::New(Handle<JSFunction>::cast(bound_function),
isolate, result, Execution::New(isolate, bound_function, bound_function,
total_argc, param_data.get()));
return *result;
}
......@@ -564,30 +557,6 @@ RUNTIME_FUNCTION(Runtime_Apply) {
}
RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
RUNTIME_ASSERT(!object->IsJSFunction());
Handle<JSFunction> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, Execution::GetFunctionDelegate(isolate, object));
return *result;
}
RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
RUNTIME_ASSERT(!object->IsJSFunction());
Handle<JSFunction> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, Execution::GetConstructorDelegate(isolate, object));
return *result;
}
RUNTIME_FUNCTION(Runtime_GetOriginalConstructor) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
......
......@@ -11,6 +11,8 @@
#include "src/frames-inl.h"
#include "src/isolate-inl.h"
#include "src/messages.h"
#include "src/parser.h"
#include "src/prettyprinter.h"
namespace v8 {
namespace internal {
......@@ -409,5 +411,39 @@ RUNTIME_FUNCTION(Runtime_GetCodeStubExportsObject) {
return isolate->heap()->code_stub_exports_object();
}
namespace {
Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object) {
MessageLocation location;
if (isolate->ComputeLocation(&location)) {
Zone zone;
base::SmartPointer<ParseInfo> info(
location.function()->shared()->is_function()
? new ParseInfo(&zone, location.function())
: new ParseInfo(&zone, location.script()));
if (Parser::ParseStatic(info.get())) {
CallPrinter printer(isolate, &zone);
const char* string = printer.Print(info->literal(), location.start_pos());
return isolate->factory()->NewStringFromAsciiChecked(string);
} else {
isolate->clear_pending_exception();
}
}
return Object::TypeOf(isolate, object);
}
} // namespace
RUNTIME_FUNCTION(Runtime_ThrowCalledNonCallable) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
Handle<String> callsite = RenderCallSite(isolate, object);
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCalledNonCallable, callsite));
}
} // namespace internal
} // namespace v8
......@@ -244,8 +244,6 @@ namespace internal {
F(NewObjectFromBound, 1, 1) \
F(Call, -1 /* >= 2 */, 1) \
F(Apply, 5, 1) \
F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \
F(GetOriginalConstructor, 0, 1) \
F(CallFunction, -1 /* receiver + n args + function */, 1) \
F(IsConstructCall, 0, 1) \
......@@ -341,7 +339,8 @@ namespace internal {
F(HarmonyToString, 0, 1) \
F(GetTypeFeedbackVector, 1, 1) \
F(GetCallerJSFunction, 0, 1) \
F(GetCodeStubExportsObject, 0, 1)
F(GetCodeStubExportsObject, 0, 1) \
F(ThrowCalledNonCallable, 1, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \
......
......@@ -1717,14 +1717,15 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the target to call (can be any Object)
// -----------------------------------
StackArgumentsAccessor args(rsp, rax);
Label non_smi, non_function;
__ JumpIfSmi(rdi, &non_function);
Label non_callable, non_function, non_smi;
__ JumpIfSmi(rdi, &non_callable);
__ bind(&non_smi);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(equal, masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &non_function);
// 1. Call to function proxy.
......@@ -1736,29 +1737,23 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
__ bind(&non_function);
// TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
// be awesome instead; i.e. a trivial improvement would be to call into the
// runtime and just deal with the API function there instead of returning a
// delegate from a runtime call that just jumps back to the runtime once
// called. Or, bonus points, call directly into the C API function here, as
// we do in some Crankshaft fast cases.
StackArgumentsAccessor args(rsp, rax);
// Check if target has a [[Call]] internal method.
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsCallable));
__ j(zero, &non_callable, Label::kNear);
// Overwrite the original receiver with the (original) target.
__ movp(args.GetReceiverOperand(), rdi);
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, rdi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ Integer32ToSmi(rax, rax);
__ Push(rax);
__ Push(rdi);
__ CallRuntime(Runtime::kGetFunctionDelegate, 1);
__ movp(rdi, rax);
__ Pop(rax);
__ SmiToInteger32(rax, rax);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(rdi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......@@ -1793,34 +1788,42 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -- rdi : the constructor to call (can be any Object)
// -----------------------------------
StackArgumentsAccessor args(rsp, rax);
Label slow;
__ JumpIfSmi(rdi, &slow, Label::kNear);
Label non_callable, non_function;
__ JumpIfSmi(rdi, &non_callable);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &slow, Label::kNear);
__ j(not_equal, &non_function, Label::kNear);
// 1. Construct of function proxy.
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
__ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
__ bind(&slow);
// 2. Construct of something else, which might have a [[Construct]] internal
// method (if not we raise an exception).
__ bind(&non_function);
// Check if target has a [[Call]] internal method.
// TODO(bmeurer): This shoud use IsConstructor once available.
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsCallable));
__ j(zero, &non_callable, Label::kNear);
// Overwrite the original receiver with the (original) target.
__ movp(args.GetReceiverOperand(), rdi);
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, rdi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Construct of something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ Integer32ToSmi(rax, rax);
__ Push(rax);
__ Push(rdi);
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
__ movp(rdi, rax);
__ Pop(rax);
__ SmiToInteger32(rax, rax);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(rdi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......
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