blob: 3f98d4fb13a84056767f66bd161370e42d49a22a [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() {}
BailoutId Builtins::GetContinuationBailoutId(Name name) {
switch (name) {
#define BAILOUT_ID(NAME, ...) \
case k##NAME: \
return BailoutId(BailoutId::kFirstBuiltinContinuationId + name);
BUILTIN_LIST_TFJ(BAILOUT_ID);
BUILTIN_LIST_TFC(BAILOUT_ID);
#undef BAILOUT_ID
default:
UNREACHABLE();
}
}
Builtins::Name Builtins::GetBuiltinFromBailoutId(BailoutId id) {
switch (id.ToInt()) {
#define BAILOUT_ID(NAME, ...) \
case BailoutId::kFirstBuiltinContinuationId + k##NAME: \
return k##NAME;
BUILTIN_LIST_TFJ(BAILOUT_ID)
BUILTIN_LIST_TFC(BAILOUT_ID)
#undef BAILOUT_ID
default:
UNREACHABLE();
}
}
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::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
switch (hint) {
case ToPrimitiveHint::kDefault:
return NonPrimitiveToPrimitive_Default();
case ToPrimitiveHint::kNumber:
return NonPrimitiveToPrimitive_Number();
case ToPrimitiveHint::kString:
return NonPrimitiveToPrimitive_String();
}
UNREACHABLE();
}
Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
switch (hint) {
case OrdinaryToPrimitiveHint::kNumber:
return OrdinaryToPrimitive_Number();
case OrdinaryToPrimitiveHint::kString:
return OrdinaryToPrimitive_String();
}
UNREACHABLE();
}
Handle<Code> Builtins::builtin_handle(Name name) {
return Handle<Code>(reinterpret_cast<Code**>(builtin_address(name)));
}
// 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();
}
}
// static
Callable Builtins::CallableFor(Isolate* isolate, Name name) {
Handle<Code> code(
reinterpret_cast<Code**>(isolate->builtins()->builtin_address(name)));
CallDescriptors::Key key;
switch (name) {
// This macro is deliberately crafted so as to emit very little code,
// in order to keep binary size of this function under control.
#define CASE_OTHER(Name, ...) \
case k##Name: { \
key = Builtin_##Name##_InterfaceDescriptor::key(); \
break; \
}
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, CASE_OTHER,
CASE_OTHER, CASE_OTHER, IGNORE_BUILTIN, IGNORE_BUILTIN)
#undef CASE_OTHER
case kConsoleAssert: {
return Callable(code, BuiltinDescriptor(isolate));
}
case kArrayForEach: {
Handle<Code> code = isolate->builtins()->ArrayForEach();
return Callable(code, BuiltinDescriptor(isolate));
}
case kArrayForEachLoopEagerDeoptContinuation: {
Handle<Code> code =
isolate->builtins()->ArrayForEachLoopEagerDeoptContinuation();
return Callable(code, BuiltinDescriptor(isolate));
}
case kArrayForEachLoopLazyDeoptContinuation: {
Handle<Code> code =
isolate->builtins()->ArrayForEachLoopLazyDeoptContinuation();
return Callable(code, BuiltinDescriptor(isolate));
}
case kArrayMapLoopEagerDeoptContinuation: {
Handle<Code> code =
isolate->builtins()->ArrayMapLoopEagerDeoptContinuation();
return Callable(code, BuiltinDescriptor(isolate));
}
case kArrayMapLoopLazyDeoptContinuation: {
Handle<Code> code =
isolate->builtins()->ArrayMapLoopLazyDeoptContinuation();
return Callable(code, BuiltinDescriptor(isolate));
}
default:
UNREACHABLE();
}
CallInterfaceDescriptor descriptor(isolate, key);
return Callable(code, descriptor);
}
// static
int Builtins::GetStackParameterCount(Isolate* isolate, Name name) {
switch (name) {
#define CASE(Name, Count, ...) \
case k##Name: { \
return Count; \
}
BUILTIN_LIST_TFJ(CASE)
#undef CASE
default:
UNREACHABLE();
return 0;
}
}
// 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
Handle<Code> Builtins::JSConstructStubGeneric() {
return FLAG_harmony_restrict_constructor_return
? JSConstructStubGenericRestrictedReturn()
: JSConstructStubGenericUnrestrictedReturn();
}
// 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