Commit a4bd96a6 authored by yangguo's avatar yangguo Committed by Commit bot

[builtins] move remaining builtins into separate files.

R=bmeurer@chromium.org
BUG=v8:5197

Review-Url: https://codereview.chromium.org/2178943002
Cr-Commit-Position: refs/heads/master@{#38034}
parent aa322336
......@@ -872,9 +872,11 @@ v8_source_set("v8_base") {
"src/bit-vector.h",
"src/bootstrapper.cc",
"src/bootstrapper.h",
"src/builtins/builtins-api.cc",
"src/builtins/builtins-array.cc",
"src/builtins/builtins-arraybuffer.cc",
"src/builtins/builtins-boolean.cc",
"src/builtins/builtins-call.cc",
"src/builtins/builtins-callsite.cc",
"src/builtins/builtins-conversion.cc",
"src/builtins/builtins-dataview.cc",
......@@ -882,6 +884,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-debug.cc",
"src/builtins/builtins-error.cc",
"src/builtins/builtins-function.cc",
"src/builtins/builtins-generator.cc",
"src/builtins/builtins-global.cc",
"src/builtins/builtins-handler.cc",
"src/builtins/builtins-internal.cc",
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins.h"
#include "src/api-arguments.h"
#include "src/api-natives.h"
#include "src/builtins/builtins-utils.h"
namespace v8 {
namespace internal {
namespace {
// Returns the holder JSObject if the function can legally be called with this
// receiver. Returns nullptr if the call is illegal.
// TODO(dcarney): CallOptimization duplicates this logic, merge.
JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
JSObject* receiver) {
Object* recv_type = info->signature();
// No signature, return holder.
if (!recv_type->IsFunctionTemplateInfo()) return receiver;
FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
// Check the receiver. Fast path for receivers with no hidden prototypes.
if (signature->IsTemplateFor(receiver)) return receiver;
if (!receiver->map()->has_hidden_prototype()) return nullptr;
for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
PrototypeIterator::END_AT_NON_HIDDEN);
!iter.IsAtEnd(); iter.Advance()) {
JSObject* current = iter.GetCurrent<JSObject>();
if (signature->IsTemplateFor(current)) return current;
}
return nullptr;
}
template <bool is_construct>
MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
Isolate* isolate, Handle<HeapObject> function,
Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
Handle<Object> receiver, BuiltinArguments args) {
Handle<JSObject> js_receiver;
JSObject* raw_holder;
if (is_construct) {
DCHECK(args.receiver()->IsTheHole(isolate));
if (fun_data->instance_template()->IsUndefined(isolate)) {
v8::Local<ObjectTemplate> templ =
ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
ToApiHandle<v8::FunctionTemplate>(fun_data));
fun_data->set_instance_template(*Utils::OpenHandle(*templ));
}
Handle<ObjectTemplateInfo> instance_template(
ObjectTemplateInfo::cast(fun_data->instance_template()), isolate);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, js_receiver,
ApiNatives::InstantiateObject(instance_template,
Handle<JSReceiver>::cast(new_target)),
Object);
args[0] = *js_receiver;
DCHECK_EQ(*js_receiver, *args.receiver());
raw_holder = *js_receiver;
} else {
DCHECK(receiver->IsJSReceiver());
if (!receiver->IsJSObject()) {
// This function cannot be called with the given receiver. Abort!
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
}
js_receiver = Handle<JSObject>::cast(receiver);
if (!fun_data->accept_any_receiver() &&
js_receiver->IsAccessCheckNeeded() &&
!isolate->MayAccess(handle(isolate->context()), js_receiver)) {
isolate->ReportFailedAccessCheck(js_receiver);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
}
raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
if (raw_holder == nullptr) {
// This function cannot be called with the given receiver. Abort!
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
}
}
Object* raw_call_data = fun_data->call_code();
if (!raw_call_data->IsUndefined(isolate)) {
DCHECK(raw_call_data->IsCallHandlerInfo());
CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
Object* callback_obj = call_data->callback();
v8::FunctionCallback callback =
v8::ToCData<v8::FunctionCallback>(callback_obj);
Object* data_obj = call_data->data();
LOG(isolate, ApiObjectAccess("call", JSObject::cast(*js_receiver)));
FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
*new_target, &args[0] - 1,
args.length() - 1);
Handle<Object> result = custom.Call(callback);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
if (result.is_null()) {
if (is_construct) return js_receiver;
return isolate->factory()->undefined_value();
}
// Rebox the result.
result->VerifyApiCallResultType();
if (!is_construct || result->IsJSObject()) return handle(*result, isolate);
}
return js_receiver;
}
} // anonymous namespace
BUILTIN(HandleApiCall) {
HandleScope scope(isolate);
Handle<JSFunction> function = args.target<JSFunction>();
Handle<Object> receiver = args.receiver();
Handle<HeapObject> new_target = args.new_target();
Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
isolate);
if (new_target->IsJSReceiver()) {
RETURN_RESULT_OR_FAILURE(
isolate, HandleApiCallHelper<true>(isolate, function, new_target,
fun_data, receiver, args));
} else {
RETURN_RESULT_OR_FAILURE(
isolate, HandleApiCallHelper<false>(isolate, function, new_target,
fun_data, receiver, args));
}
}
namespace {
class RelocatableArguments : public BuiltinArguments, public Relocatable {
public:
RelocatableArguments(Isolate* isolate, int length, Object** arguments)
: BuiltinArguments(length, arguments), Relocatable(isolate) {}
virtual inline void IterateInstance(ObjectVisitor* v) {
if (length() == 0) return;
v->VisitPointers(lowest_address(), highest_address() + 1);
}
private:
DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
};
} // namespace
MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
Handle<HeapObject> function,
Handle<Object> receiver,
int argc,
Handle<Object> args[]) {
DCHECK(function->IsFunctionTemplateInfo() ||
(function->IsJSFunction() &&
JSFunction::cast(*function)->shared()->IsApiFunction()));
// Do proper receiver conversion for non-strict mode api functions.
if (!receiver->IsJSReceiver()) {
if (function->IsFunctionTemplateInfo() ||
is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
Object::ConvertReceiver(isolate, receiver),
Object);
}
}
Handle<FunctionTemplateInfo> fun_data =
function->IsFunctionTemplateInfo()
? Handle<FunctionTemplateInfo>::cast(function)
: handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
isolate);
Handle<HeapObject> new_target = isolate->factory()->undefined_value();
// Construct BuiltinArguments object:
// new target, function, arguments reversed, receiver.
const int kBufferSize = 32;
Object* small_argv[kBufferSize];
Object** argv;
const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
if (frame_argc <= kBufferSize) {
argv = small_argv;
} else {
argv = new Object*[frame_argc];
}
int cursor = frame_argc - 1;
argv[cursor--] = *receiver;
for (int i = 0; i < argc; ++i) {
argv[cursor--] = *args[i];
}
DCHECK(cursor == BuiltinArguments::kArgcOffset);
argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc);
argv[BuiltinArguments::kTargetOffset] = *function;
argv[BuiltinArguments::kNewTargetOffset] = *new_target;
MaybeHandle<Object> result;
{
RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
result = HandleApiCallHelper<false>(isolate, function, new_target, fun_data,
receiver, arguments);
}
if (argv != small_argv) delete[] argv;
return result;
}
// Helper function to handle calls to non-function objects created through the
// API. The object can be called as either a constructor (using new) or just as
// a function (without new).
MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
Handle<Object> receiver = args.receiver();
// Get the object called.
JSObject* obj = JSObject::cast(*receiver);
// Set the new target.
HeapObject* new_target;
if (is_construct_call) {
// TODO(adamk): This should be passed through in args instead of
// being patched in here. We need to set a non-undefined value
// for v8::FunctionCallbackInfo::IsConstructCall() to get the
// right answer.
new_target = obj;
} else {
new_target = isolate->heap()->undefined_value();
}
// Get the invocation callback from the function descriptor that was
// used to create the called object.
DCHECK(obj->map()->is_callable());
JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
// TODO(ishell): turn this back to a DCHECK.
CHECK(constructor->shared()->IsApiFunction());
Object* handler =
constructor->shared()->get_api_func_data()->instance_call_handler();
DCHECK(!handler->IsUndefined(isolate));
// TODO(ishell): remove this debugging code.
CHECK(handler->IsCallHandlerInfo());
CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
Object* callback_obj = call_data->callback();
v8::FunctionCallback callback =
v8::ToCData<v8::FunctionCallback>(callback_obj);
// Get the data for the call and perform the callback.
Object* result;
{
HandleScope scope(isolate);
LOG(isolate, ApiObjectAccess("call non-function", obj));
FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
obj, new_target, &args[0] - 1,
args.length() - 1);
Handle<Object> result_handle = custom.Call(callback);
if (result_handle.is_null()) {
result = isolate->heap()->undefined_value();
} else {
result = *result_handle;
}
}
// Check for exceptions and return result.
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return result;
}
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction) {
return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
}
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor) {
return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
}
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
namespace v8 {
namespace internal {
Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return CallFunction_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return CallFunction_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return CallFunction_ReceiverIsAny();
}
break;
case TailCallMode::kAllow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return TailCallFunction_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return TailCallFunction_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return TailCallFunction_ReceiverIsAny();
}
break;
}
UNREACHABLE();
return Handle<Code>::null();
}
Handle<Code> Builtins::Call(ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return Call_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return Call_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return Call_ReceiverIsAny();
}
break;
case TailCallMode::kAllow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return TailCall_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return TailCall_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return TailCall_ReceiverIsAny();
}
break;
}
UNREACHABLE();
return Handle<Code>::null();
}
Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return CallBoundFunction();
case TailCallMode::kAllow:
return TailCallBoundFunction();
}
UNREACHABLE();
return Handle<Code>::null();
}
void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kAny,
TailCallMode::kDisallow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsAny(MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow);
}
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
Generate_CallBoundFunctionImpl(masm, TailCallMode::kDisallow);
}
void Builtins::Generate_TailCallBoundFunction(MacroAssembler* masm) {
Generate_CallBoundFunctionImpl(masm, TailCallMode::kAllow);
}
void Builtins::Generate_Call_ReceiverIsNullOrUndefined(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_Call_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_Call_ReceiverIsAny(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow);
}
void Builtins::Generate_TailCall_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCall_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCall_ReceiverIsAny(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow);
}
} // namespace internal
} // namespace v8
......@@ -297,5 +297,17 @@ BUILTIN(FunctionPrototypeToString) {
"Function.prototype.toString")));
}
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V )
void Builtins::Generate_FunctionPrototypeHasInstance(
CodeStubAssembler* assembler) {
using compiler::Node;
Node* f = assembler->Parameter(0);
Node* v = assembler->Parameter(1);
Node* context = assembler->Parameter(4);
Node* result = assembler->OrdinaryHasInstance(context, f, v);
assembler->Return(result);
}
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
#include "src/code-factory.h"
namespace v8 {
namespace internal {
namespace {
void Generate_GeneratorPrototypeResume(
CodeStubAssembler* assembler, JSGeneratorObject::ResumeMode resume_mode,
char const* const method_name) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(0);
Node* value = assembler->Parameter(1);
Node* context = assembler->Parameter(4);
Node* closed =
assembler->SmiConstant(Smi::FromInt(JSGeneratorObject::kGeneratorClosed));
// Check if the {receiver} is actually a JSGeneratorObject.
Label if_receiverisincompatible(assembler, Label::kDeferred);
assembler->GotoIf(assembler->WordIsSmi(receiver), &if_receiverisincompatible);
Node* receiver_instance_type = assembler->LoadInstanceType(receiver);
assembler->GotoUnless(assembler->Word32Equal(
receiver_instance_type,
assembler->Int32Constant(JS_GENERATOR_OBJECT_TYPE)),
&if_receiverisincompatible);
// Check if the {receiver} is running or already closed.
Node* receiver_continuation = assembler->LoadObjectField(
receiver, JSGeneratorObject::kContinuationOffset);
Label if_receiverisclosed(assembler, Label::kDeferred),
if_receiverisrunning(assembler, Label::kDeferred);
assembler->GotoIf(assembler->SmiEqual(receiver_continuation, closed),
&if_receiverisclosed);
DCHECK_LT(JSGeneratorObject::kGeneratorExecuting,
JSGeneratorObject::kGeneratorClosed);
assembler->GotoIf(assembler->SmiLessThan(receiver_continuation, closed),
&if_receiverisrunning);
// Resume the {receiver} using our trampoline.
Node* result = assembler->CallStub(
CodeFactory::ResumeGenerator(assembler->isolate()), context, value,
receiver, assembler->SmiConstant(Smi::FromInt(resume_mode)));
assembler->Return(result);
assembler->Bind(&if_receiverisincompatible);
{
// The {receiver} is not a valid JSGeneratorObject.
Node* result = assembler->CallRuntime(
Runtime::kThrowIncompatibleMethodReceiver, context,
assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked(
method_name, TENURED)),
receiver);
assembler->Return(result); // Never reached.
}
assembler->Bind(&if_receiverisclosed);
{
// The {receiver} is closed already.
Node* result = nullptr;
switch (resume_mode) {
case JSGeneratorObject::kNext:
result = assembler->CallRuntime(Runtime::kCreateIterResultObject,
context, assembler->UndefinedConstant(),
assembler->BooleanConstant(true));
break;
case JSGeneratorObject::kReturn:
result =
assembler->CallRuntime(Runtime::kCreateIterResultObject, context,
value, assembler->BooleanConstant(true));
break;
case JSGeneratorObject::kThrow:
result = assembler->CallRuntime(Runtime::kThrow, context, value);
break;
}
assembler->Return(result);
}
assembler->Bind(&if_receiverisrunning);
{
Node* result =
assembler->CallRuntime(Runtime::kThrowGeneratorRunning, context);
assembler->Return(result); // Never reached.
}
}
} // anonymous namespace
// ES6 section 25.3.1.2 Generator.prototype.next ( value )
void Builtins::Generate_GeneratorPrototypeNext(CodeStubAssembler* assembler) {
Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kNext,
"[Generator].prototype.next");
}
// ES6 section 25.3.1.3 Generator.prototype.return ( value )
void Builtins::Generate_GeneratorPrototypeReturn(CodeStubAssembler* assembler) {
Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kReturn,
"[Generator].prototype.return");
}
// ES6 section 25.3.1.4 Generator.prototype.throw ( exception )
void Builtins::Generate_GeneratorPrototypeThrow(CodeStubAssembler* assembler) {
Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kThrow,
"[Generator].prototype.throw");
}
} // namespace internal
} // namespace v8
......@@ -5,6 +5,8 @@
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
#include "src/macro-assembler.h"
namespace v8 {
namespace internal {
......@@ -31,5 +33,16 @@ BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
}
// -----------------------------------------------------------------------------
// Interrupt and stack checks.
void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kInterrupt);
}
void Builtins::Generate_StackCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kStackGuard);
}
} // namespace internal
} // namespace v8
......@@ -3,14 +3,13 @@
// found in the LICENSE file.
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
#include "src/api-arguments.h"
#include "src/api-natives.h"
#include "src/code-factory.h"
#include "src/ic/handler-compiler.h"
#include "src/ic/ic.h"
#include "src/vm-state-inl.h"
#include "src/code-events.h"
#include "src/code-stub-assembler.h"
#include "src/ic/ic-state.h"
#include "src/interface-descriptors.h"
#include "src/isolate.h"
#include "src/macro-assembler.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
......@@ -19,469 +18,6 @@ namespace internal {
#define FORWARD_DECLARE(Name) \
Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
BUILTIN_LIST_C(FORWARD_DECLARE)
#undef FORWARD_DECLARE
// -----------------------------------------------------------------------------
// ES6 section 19.2 Function Objects
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V )
void Builtins::Generate_FunctionPrototypeHasInstance(
CodeStubAssembler* assembler) {
using compiler::Node;
Node* f = assembler->Parameter(0);
Node* v = assembler->Parameter(1);
Node* context = assembler->Parameter(4);
Node* result = assembler->OrdinaryHasInstance(context, f, v);
assembler->Return(result);
}
// -----------------------------------------------------------------------------
// ES6 section 25.3 Generator Objects
namespace {
void Generate_GeneratorPrototypeResume(
CodeStubAssembler* assembler, JSGeneratorObject::ResumeMode resume_mode,
char const* const method_name) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(0);
Node* value = assembler->Parameter(1);
Node* context = assembler->Parameter(4);
Node* closed =
assembler->SmiConstant(Smi::FromInt(JSGeneratorObject::kGeneratorClosed));
// Check if the {receiver} is actually a JSGeneratorObject.
Label if_receiverisincompatible(assembler, Label::kDeferred);
assembler->GotoIf(assembler->WordIsSmi(receiver), &if_receiverisincompatible);
Node* receiver_instance_type = assembler->LoadInstanceType(receiver);
assembler->GotoUnless(assembler->Word32Equal(
receiver_instance_type,
assembler->Int32Constant(JS_GENERATOR_OBJECT_TYPE)),
&if_receiverisincompatible);
// Check if the {receiver} is running or already closed.
Node* receiver_continuation = assembler->LoadObjectField(
receiver, JSGeneratorObject::kContinuationOffset);
Label if_receiverisclosed(assembler, Label::kDeferred),
if_receiverisrunning(assembler, Label::kDeferred);
assembler->GotoIf(assembler->SmiEqual(receiver_continuation, closed),
&if_receiverisclosed);
DCHECK_LT(JSGeneratorObject::kGeneratorExecuting,
JSGeneratorObject::kGeneratorClosed);
assembler->GotoIf(assembler->SmiLessThan(receiver_continuation, closed),
&if_receiverisrunning);
// Resume the {receiver} using our trampoline.
Node* result = assembler->CallStub(
CodeFactory::ResumeGenerator(assembler->isolate()), context, value,
receiver, assembler->SmiConstant(Smi::FromInt(resume_mode)));
assembler->Return(result);
assembler->Bind(&if_receiverisincompatible);
{
// The {receiver} is not a valid JSGeneratorObject.
Node* result = assembler->CallRuntime(
Runtime::kThrowIncompatibleMethodReceiver, context,
assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked(
method_name, TENURED)),
receiver);
assembler->Return(result); // Never reached.
}
assembler->Bind(&if_receiverisclosed);
{
// The {receiver} is closed already.
Node* result = nullptr;
switch (resume_mode) {
case JSGeneratorObject::kNext:
result = assembler->CallRuntime(Runtime::kCreateIterResultObject,
context, assembler->UndefinedConstant(),
assembler->BooleanConstant(true));
break;
case JSGeneratorObject::kReturn:
result =
assembler->CallRuntime(Runtime::kCreateIterResultObject, context,
value, assembler->BooleanConstant(true));
break;
case JSGeneratorObject::kThrow:
result = assembler->CallRuntime(Runtime::kThrow, context, value);
break;
}
assembler->Return(result);
}
assembler->Bind(&if_receiverisrunning);
{
Node* result =
assembler->CallRuntime(Runtime::kThrowGeneratorRunning, context);
assembler->Return(result); // Never reached.
}
}
} // namespace
// ES6 section 25.3.1.2 Generator.prototype.next ( value )
void Builtins::Generate_GeneratorPrototypeNext(CodeStubAssembler* assembler) {
Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kNext,
"[Generator].prototype.next");
}
// ES6 section 25.3.1.3 Generator.prototype.return ( value )
void Builtins::Generate_GeneratorPrototypeReturn(CodeStubAssembler* assembler) {
Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kReturn,
"[Generator].prototype.return");
}
// ES6 section 25.3.1.4 Generator.prototype.throw ( exception )
void Builtins::Generate_GeneratorPrototypeThrow(CodeStubAssembler* assembler) {
Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kThrow,
"[Generator].prototype.throw");
}
// -----------------------------------------------------------------------------
//
namespace {
// Returns the holder JSObject if the function can legally be called with this
// receiver. Returns nullptr if the call is illegal.
// TODO(dcarney): CallOptimization duplicates this logic, merge.
JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
JSObject* receiver) {
Object* recv_type = info->signature();
// No signature, return holder.
if (!recv_type->IsFunctionTemplateInfo()) return receiver;
FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
// Check the receiver. Fast path for receivers with no hidden prototypes.
if (signature->IsTemplateFor(receiver)) return receiver;
if (!receiver->map()->has_hidden_prototype()) return nullptr;
for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
PrototypeIterator::END_AT_NON_HIDDEN);
!iter.IsAtEnd(); iter.Advance()) {
JSObject* current = iter.GetCurrent<JSObject>();
if (signature->IsTemplateFor(current)) return current;
}
return nullptr;
}
template <bool is_construct>
MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
Isolate* isolate, Handle<HeapObject> function,
Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
Handle<Object> receiver, BuiltinArguments args) {
Handle<JSObject> js_receiver;
JSObject* raw_holder;
if (is_construct) {
DCHECK(args.receiver()->IsTheHole(isolate));
if (fun_data->instance_template()->IsUndefined(isolate)) {
v8::Local<ObjectTemplate> templ =
ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
ToApiHandle<v8::FunctionTemplate>(fun_data));
fun_data->set_instance_template(*Utils::OpenHandle(*templ));
}
Handle<ObjectTemplateInfo> instance_template(
ObjectTemplateInfo::cast(fun_data->instance_template()), isolate);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, js_receiver,
ApiNatives::InstantiateObject(instance_template,
Handle<JSReceiver>::cast(new_target)),
Object);
args[0] = *js_receiver;
DCHECK_EQ(*js_receiver, *args.receiver());
raw_holder = *js_receiver;
} else {
DCHECK(receiver->IsJSReceiver());
if (!receiver->IsJSObject()) {
// This function cannot be called with the given receiver. Abort!
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
}
js_receiver = Handle<JSObject>::cast(receiver);
if (!fun_data->accept_any_receiver() &&
js_receiver->IsAccessCheckNeeded() &&
!isolate->MayAccess(handle(isolate->context()), js_receiver)) {
isolate->ReportFailedAccessCheck(js_receiver);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
}
raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
if (raw_holder == nullptr) {
// This function cannot be called with the given receiver. Abort!
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
}
}
Object* raw_call_data = fun_data->call_code();
if (!raw_call_data->IsUndefined(isolate)) {
DCHECK(raw_call_data->IsCallHandlerInfo());
CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
Object* callback_obj = call_data->callback();
v8::FunctionCallback callback =
v8::ToCData<v8::FunctionCallback>(callback_obj);
Object* data_obj = call_data->data();
LOG(isolate, ApiObjectAccess("call", JSObject::cast(*js_receiver)));
FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
*new_target, &args[0] - 1,
args.length() - 1);
Handle<Object> result = custom.Call(callback);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
if (result.is_null()) {
if (is_construct) return js_receiver;
return isolate->factory()->undefined_value();
}
// Rebox the result.
result->VerifyApiCallResultType();
if (!is_construct || result->IsJSObject()) return handle(*result, isolate);
}
return js_receiver;
}
} // namespace
BUILTIN(HandleApiCall) {
HandleScope scope(isolate);
Handle<JSFunction> function = args.target<JSFunction>();
Handle<Object> receiver = args.receiver();
Handle<HeapObject> new_target = args.new_target();
Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
isolate);
if (new_target->IsJSReceiver()) {
RETURN_RESULT_OR_FAILURE(
isolate, HandleApiCallHelper<true>(isolate, function, new_target,
fun_data, receiver, args));
} else {
RETURN_RESULT_OR_FAILURE(
isolate, HandleApiCallHelper<false>(isolate, function, new_target,
fun_data, receiver, args));
}
}
Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return CallFunction_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return CallFunction_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return CallFunction_ReceiverIsAny();
}
break;
case TailCallMode::kAllow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return TailCallFunction_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return TailCallFunction_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return TailCallFunction_ReceiverIsAny();
}
break;
}
UNREACHABLE();
return Handle<Code>::null();
}
Handle<Code> Builtins::Call(ConvertReceiverMode mode,
TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return Call_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return Call_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return Call_ReceiverIsAny();
}
break;
case TailCallMode::kAllow:
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return TailCall_ReceiverIsNullOrUndefined();
case ConvertReceiverMode::kNotNullOrUndefined:
return TailCall_ReceiverIsNotNullOrUndefined();
case ConvertReceiverMode::kAny:
return TailCall_ReceiverIsAny();
}
break;
}
UNREACHABLE();
return Handle<Code>::null();
}
Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
return CallBoundFunction();
case TailCallMode::kAllow:
return TailCallBoundFunction();
}
UNREACHABLE();
return Handle<Code>::null();
}
namespace {
class RelocatableArguments : public BuiltinArguments, public Relocatable {
public:
RelocatableArguments(Isolate* isolate, int length, Object** arguments)
: BuiltinArguments(length, arguments), Relocatable(isolate) {}
virtual inline void IterateInstance(ObjectVisitor* v) {
if (length() == 0) return;
v->VisitPointers(lowest_address(), highest_address() + 1);
}
private:
DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
};
} // namespace
MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
Handle<HeapObject> function,
Handle<Object> receiver,
int argc,
Handle<Object> args[]) {
DCHECK(function->IsFunctionTemplateInfo() ||
(function->IsJSFunction() &&
JSFunction::cast(*function)->shared()->IsApiFunction()));
// Do proper receiver conversion for non-strict mode api functions.
if (!receiver->IsJSReceiver()) {
if (function->IsFunctionTemplateInfo() ||
is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
Object::ConvertReceiver(isolate, receiver),
Object);
}
}
Handle<FunctionTemplateInfo> fun_data =
function->IsFunctionTemplateInfo()
? Handle<FunctionTemplateInfo>::cast(function)
: handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
isolate);
Handle<HeapObject> new_target = isolate->factory()->undefined_value();
// Construct BuiltinArguments object:
// new target, function, arguments reversed, receiver.
const int kBufferSize = 32;
Object* small_argv[kBufferSize];
Object** argv;
const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
if (frame_argc <= kBufferSize) {
argv = small_argv;
} else {
argv = new Object*[frame_argc];
}
int cursor = frame_argc - 1;
argv[cursor--] = *receiver;
for (int i = 0; i < argc; ++i) {
argv[cursor--] = *args[i];
}
DCHECK(cursor == BuiltinArguments::kArgcOffset);
argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc);
argv[BuiltinArguments::kTargetOffset] = *function;
argv[BuiltinArguments::kNewTargetOffset] = *new_target;
MaybeHandle<Object> result;
{
RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
result = HandleApiCallHelper<false>(isolate, function, new_target, fun_data,
receiver, arguments);
}
if (argv != small_argv) delete[] argv;
return result;
}
// Helper function to handle calls to non-function objects created through the
// API. The object can be called as either a constructor (using new) or just as
// a function (without new).
MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
Handle<Object> receiver = args.receiver();
// Get the object called.
JSObject* obj = JSObject::cast(*receiver);
// Set the new target.
HeapObject* new_target;
if (is_construct_call) {
// TODO(adamk): This should be passed through in args instead of
// being patched in here. We need to set a non-undefined value
// for v8::FunctionCallbackInfo::IsConstructCall() to get the
// right answer.
new_target = obj;
} else {
new_target = isolate->heap()->undefined_value();
}
// Get the invocation callback from the function descriptor that was
// used to create the called object.
DCHECK(obj->map()->is_callable());
JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
// TODO(ishell): turn this back to a DCHECK.
CHECK(constructor->shared()->IsApiFunction());
Object* handler =
constructor->shared()->get_api_func_data()->instance_call_handler();
DCHECK(!handler->IsUndefined(isolate));
// TODO(ishell): remove this debugging code.
CHECK(handler->IsCallHandlerInfo());
CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
Object* callback_obj = call_data->callback();
v8::FunctionCallback callback =
v8::ToCData<v8::FunctionCallback>(callback_obj);
// Get the data for the call and perform the callback.
Object* result;
{
HandleScope scope(isolate);
LOG(isolate, ApiObjectAccess("call non-function", obj));
FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
obj, new_target, &args[0] - 1,
args.length() - 1);
Handle<Object> result_handle = custom.Call(callback);
if (result_handle.is_null()) {
result = isolate->heap()->undefined_value();
} else {
result = *result_handle;
}
}
// Check for exceptions and return result.
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return result;
}
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction) {
return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
}
// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor) {
return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
}
Builtins::Builtins() : initialized_(false) {
memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
......@@ -662,87 +198,6 @@ const char* Builtins::name(int index) {
return "";
}
void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kInterrupt);
}
void Builtins::Generate_StackCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kStackGuard);
}
void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kAny,
TailCallMode::kDisallow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCallFunction_ReceiverIsAny(MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow);
}
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
Generate_CallBoundFunctionImpl(masm, TailCallMode::kDisallow);
}
void Builtins::Generate_TailCallBoundFunction(MacroAssembler* masm) {
Generate_CallBoundFunctionImpl(masm, TailCallMode::kAllow);
}
void Builtins::Generate_Call_ReceiverIsNullOrUndefined(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_Call_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kDisallow);
}
void Builtins::Generate_Call_ReceiverIsAny(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow);
}
void Builtins::Generate_TailCall_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCall_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kAllow);
}
void Builtins::Generate_TailCall_ReceiverIsAny(MacroAssembler* masm) {
Generate_Call(masm, ConvertReceiverMode::kAny, TailCallMode::kAllow);
}
#define DEFINE_BUILTIN_ACCESSOR(Name, ...) \
Handle<Code> Builtins::Name() { \
Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \
......
......@@ -485,9 +485,11 @@
'bit-vector.h',
'bootstrapper.cc',
'bootstrapper.h',
'builtins/builtins-api.cc',
'builtins/builtins-arraybuffer.cc',
'builtins/builtins-array.cc',
'builtins/builtins-boolean.cc',
'builtins/builtins-call.cc',
'builtins/builtins-callsite.cc',
'builtins/builtins-conversion.cc',
'builtins/builtins-dataview.cc',
......@@ -495,6 +497,7 @@
'builtins/builtins-debug.cc',
'builtins/builtins-error.cc',
'builtins/builtins-function.cc',
'builtins/builtins-generator.cc',
'builtins/builtins-global.cc',
'builtins/builtins-handler.cc',
'builtins/builtins-internal.cc',
......
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