blob: 47eda0be3c05f984684079c60c0fffe22e9adc5d [file] [log] [blame]
// Copyright 2012 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.h"
#include "src/assembler-inl.h"
#include "src/builtins/builtins-descriptors.h"
#include "src/callable.h"
#include "src/isolate.h"
#include "src/macro-assembler.h"
#include "src/objects-inl.h"
#include "src/visitors.h"
namespace v8 {
namespace internal {
// Forward declarations for C++ builtins.
#define FORWARD_DECLARE(Name) \
Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
BUILTIN_LIST_C(FORWARD_DECLARE)
Builtins::Builtins() : initialized_(false) {
memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
}
Builtins::~Builtins() {}
void Builtins::TearDown() { initialized_ = false; }
void Builtins::IterateBuiltins(RootVisitor* v) {
v->VisitRootPointers(Root::kBuiltins, &builtins_[0],
&builtins_[0] + builtin_count);
}
const char* Builtins::Lookup(byte* pc) {
// may be called during initialization (disassembler!)
if (initialized_) {
for (int i = 0; i < builtin_count; i++) {
Code* entry = Code::cast(builtins_[i]);
if (entry->contains(pc)) return name(i);
}
}
return NULL;
}
Handle<Code> Builtins::NewFunctionContext(ScopeType scope_type) {
switch (scope_type) {
case ScopeType::EVAL_SCOPE:
return FastNewFunctionContextEval();
case ScopeType::FUNCTION_SCOPE:
return FastNewFunctionContextFunction();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
Handle<Code> Builtins::NewCloneShallowArray(
AllocationSiteMode allocation_mode) {
switch (allocation_mode) {
case TRACK_ALLOCATION_SITE:
return FastCloneShallowArrayTrack();
case DONT_TRACK_ALLOCATION_SITE:
return FastCloneShallowArrayDontTrack();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
Handle<Code> Builtins::NewCloneShallowObject(int length) {
switch (length) {
case 0:
return FastCloneShallowObject0();
case 1:
return FastCloneShallowObject1();
case 2:
return FastCloneShallowObject2();
case 3:
return FastCloneShallowObject3();
case 4:
return FastCloneShallowObject4();
case 5:
return FastCloneShallowObject5();
case 6:
return FastCloneShallowObject6();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
switch (hint) {
case ToPrimitiveHint::kDefault:
return NonPrimitiveToPrimitive_Default();
case ToPrimitiveHint::kNumber:
return NonPrimitiveToPrimitive_Number();
case ToPrimitiveHint::kString:
return NonPrimitiveToPrimitive_String();
}
UNREACHABLE();
return Handle<Code>::null();
}
Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
switch (hint) {
case OrdinaryToPrimitiveHint::kNumber:
return OrdinaryToPrimitive_Number();
case OrdinaryToPrimitiveHint::kString:
return OrdinaryToPrimitive_String();
}
UNREACHABLE();
return Handle<Code>::null();
}
// static
int Builtins::GetBuiltinParameterCount(Name name) {
switch (name) {
#define TFJ_CASE(Name, ParamCount, ...) \
case k##Name: { \
return ParamCount; \
}
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, TFJ_CASE, IGNORE_BUILTIN,
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
#undef TFJ_CASE
default:
UNREACHABLE();
return 0;
}
}
// static
Callable Builtins::CallableFor(Isolate* isolate, Name name) {
switch (name) {
#define CASE(Name, ...) \
case k##Name: { \
Handle<Code> code = isolate->builtins()->Name(); \
auto descriptor = Builtin_##Name##_InterfaceDescriptor(isolate); \
return Callable(code, descriptor); \
}
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, CASE, CASE,
CASE, IGNORE_BUILTIN, IGNORE_BUILTIN)
#undef CASE
case kConsoleAssert: {
Handle<Code> code = isolate->builtins()->ConsoleAssert();
return Callable(code, BuiltinDescriptor(isolate));
}
default:
UNREACHABLE();
return Callable(Handle<Code>::null(), VoidDescriptor(isolate));
}
}
// static
const char* Builtins::name(int index) {
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return #Name;
BUILTIN_LIST_ALL(CASE)
#undef CASE
default:
UNREACHABLE();
break;
}
return "";
}
// static
Address Builtins::CppEntryOf(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return FUNCTION_ADDR(Builtin_##Name);
BUILTIN_LIST_C(CASE)
#undef CASE
default:
return nullptr;
}
UNREACHABLE();
}
// static
bool Builtins::IsCpp(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return true;
#define BUILTIN_LIST_CPP(V) \
BUILTIN_LIST(V, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
BUILTIN_LIST_CPP(CASE)
#undef BUILTIN_LIST_CPP
#undef CASE
default:
return false;
}
UNREACHABLE();
}
// static
bool Builtins::IsApi(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return true;
#define BUILTIN_LIST_API(V) \
BUILTIN_LIST(IGNORE_BUILTIN, V, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
BUILTIN_LIST_API(CASE);
#undef BUILTIN_LIST_API
#undef CASE
default:
return false;
}
UNREACHABLE();
}
// static
bool Builtins::HasCppImplementation(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return true;
BUILTIN_LIST_C(CASE)
#undef CASE
default:
return false;
}
UNREACHABLE();
}
#define DEFINE_BUILTIN_ACCESSOR(Name, ...) \
Handle<Code> Builtins::Name() { \
Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \
return Handle<Code>(code_address); \
}
BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR)
#undef DEFINE_BUILTIN_ACCESSOR
// static
bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
Handle<JSObject> target_global_proxy) {
if (FLAG_allow_unsafe_function_constructor) return true;
HandleScopeImplementer* impl = isolate->handle_scope_implementer();
Handle<Context> responsible_context =
impl->MicrotaskContextIsLastEnteredContext() ? impl->MicrotaskContext()
: impl->LastEnteredContext();
// TODO(jochen): Remove this.
if (responsible_context.is_null()) {
return true;
}
if (*responsible_context == target->context()) return true;
return isolate->MayAccess(responsible_context, target_global_proxy);
}
} // namespace internal
} // namespace v8