blob: e71b26163e885382f3e3d4d624f1432f0d447ca8 [file] [log] [blame]
// Copyright 2018 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.
#ifndef V8_OBJECTS_TEMPLATES_INL_H_
#define V8_OBJECTS_TEMPLATES_INL_H_
#include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/oddball.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/templates.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
#include "torque-generated/src/objects/templates-tq-inl.inc"
TQ_OBJECT_CONSTRUCTORS_IMPL(TemplateInfo)
TQ_OBJECT_CONSTRUCTORS_IMPL(FunctionTemplateInfo)
TQ_OBJECT_CONSTRUCTORS_IMPL(ObjectTemplateInfo)
TQ_OBJECT_CONSTRUCTORS_IMPL(FunctionTemplateRareData)
TQ_OBJECT_CONSTRUCTORS_IMPL(DictionaryTemplateInfo)
NEVER_READ_ONLY_SPACE_IMPL(DictionaryTemplateInfo)
NEVER_READ_ONLY_SPACE_IMPL(ObjectTemplateInfo)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag,
is_object_template_call_handler,
IsObjectTemplateCallHandlerBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, has_side_effects,
HasSideEffectsBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, undetectable,
UndetectableBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, needs_access_check,
NeedsAccessCheckBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, read_only_prototype,
ReadOnlyPrototypeBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, remove_prototype,
RemovePrototypeBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, accept_any_receiver,
AcceptAnyReceiverBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, published,
PublishedBit::kShift)
BIT_FIELD_ACCESSORS(
FunctionTemplateInfo, relaxed_flag,
allowed_receiver_instance_type_range_start,
FunctionTemplateInfo::AllowedReceiverInstanceTypeRangeStartBits)
BIT_FIELD_ACCESSORS(
FunctionTemplateInfo, relaxed_flag,
allowed_receiver_instance_type_range_end,
FunctionTemplateInfo::AllowedReceiverInstanceTypeRangeEndBits)
RELAXED_UINT32_ACCESSORS(FunctionTemplateInfo, flag,
FunctionTemplateInfo::kFlagOffset)
int32_t FunctionTemplateInfo::relaxed_flag() const {
return flag(kRelaxedLoad);
}
void FunctionTemplateInfo::set_relaxed_flag(int32_t flags) {
return set_flag(flags, kRelaxedStore);
}
Address FunctionTemplateInfo::callback(i::IsolateForSandbox isolate) const {
Address result = maybe_redirected_callback(isolate);
if (!USE_SIMULATOR_BOOL) return result;
if (result == kNullAddress) return kNullAddress;
return ExternalReference::UnwrapRedirection(result);
}
void FunctionTemplateInfo::init_callback(i::IsolateForSandbox isolate,
Address initial_value) {
init_maybe_redirected_callback(isolate, initial_value);
if (USE_SIMULATOR_BOOL) {
init_callback_redirection(isolate);
}
}
void FunctionTemplateInfo::set_callback(i::IsolateForSandbox isolate,
Address value) {
set_maybe_redirected_callback(isolate, value);
if (USE_SIMULATOR_BOOL) {
init_callback_redirection(isolate);
}
}
void FunctionTemplateInfo::init_callback_redirection(
i::IsolateForSandbox isolate) {
CHECK(USE_SIMULATOR_BOOL);
Address value = maybe_redirected_callback(isolate);
if (value == kNullAddress) return;
value =
ExternalReference::Redirect(value, ExternalReference::DIRECT_API_CALL);
set_maybe_redirected_callback(isolate, value);
}
void FunctionTemplateInfo::remove_callback_redirection(
i::IsolateForSandbox isolate) {
CHECK(USE_SIMULATOR_BOOL);
Address value = callback(isolate);
set_maybe_redirected_callback(isolate, value);
}
EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(
FunctionTemplateInfo, maybe_redirected_callback, Address,
kMaybeRedirectedCallbackOffset, kFunctionTemplateInfoCallbackTag)
template <class IsolateT>
bool FunctionTemplateInfo::has_callback(IsolateT* isolate) const {
return !IsTheHole(callback_data(kAcquireLoad), isolate);
}
// static
Tagged<FunctionTemplateRareData>
FunctionTemplateInfo::EnsureFunctionTemplateRareData(
Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
Tagged<HeapObject> extra =
function_template_info->rare_data(isolate, kAcquireLoad);
if (IsUndefined(extra, isolate)) {
return AllocateFunctionTemplateRareData(isolate, function_template_info);
} else {
return FunctionTemplateRareData::cast(extra);
}
}
#define RARE_ACCESSORS(Name, CamelName, Type, Default) \
DEF_GETTER(FunctionTemplateInfo, Get##CamelName, Tagged<Type>) { \
Tagged<HeapObject> extra = rare_data(cage_base, kAcquireLoad); \
Tagged<Undefined> undefined = \
GetReadOnlyRoots(cage_base).undefined_value(); \
return extra == undefined ? Default \
: FunctionTemplateRareData::cast(extra)->Name(); \
} \
inline void FunctionTemplateInfo::Set##CamelName( \
Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info, \
Handle<Type> Name) { \
Tagged<FunctionTemplateRareData> rare_data = \
EnsureFunctionTemplateRareData(isolate, function_template_info); \
rare_data->set_##Name(*Name); \
}
RARE_ACCESSORS(prototype_template, PrototypeTemplate, HeapObject, undefined)
RARE_ACCESSORS(prototype_provider_template, PrototypeProviderTemplate,
HeapObject, undefined)
RARE_ACCESSORS(parent_template, ParentTemplate, HeapObject, undefined)
RARE_ACCESSORS(named_property_handler, NamedPropertyHandler, HeapObject,
undefined)
RARE_ACCESSORS(indexed_property_handler, IndexedPropertyHandler, HeapObject,
undefined)
RARE_ACCESSORS(instance_template, InstanceTemplate, HeapObject, undefined)
RARE_ACCESSORS(instance_call_handler, InstanceCallHandler, HeapObject,
undefined)
RARE_ACCESSORS(access_check_info, AccessCheckInfo, HeapObject, undefined)
RARE_ACCESSORS(c_function_overloads, CFunctionOverloads, FixedArray,
GetReadOnlyRoots(cage_base).empty_fixed_array())
#undef RARE_ACCESSORS
InstanceType FunctionTemplateInfo::GetInstanceType() const {
int type = instance_type();
DCHECK(base::IsInRange(type, Internals::kFirstJSApiObjectType,
Internals::kLastJSApiObjectType));
return static_cast<InstanceType>(type);
}
void FunctionTemplateInfo::SetInstanceType(int api_instance_type) {
// Translate |api_instance_type| value from range
// [Internals::kFirstEmbedderJSApiObjectType,
// Internals::kLastEmbedderJSApiObjectType] to range
// [Internals::kFirstJSApiObjectType, Internals::kLastJSApiObjectType].
DCHECK_LE(Internals::kFirstEmbedderJSApiObjectType, api_instance_type);
DCHECK_LE(api_instance_type, Internals::kLastEmbedderJSApiObjectType);
// kNoJSApiObjectType must correspond to JS_API_OBJECT_TYPE.
static_assert(kNoJSApiObjectType == 0);
static_assert(JS_API_OBJECT_TYPE == Internals::kFirstJSApiObjectType);
set_instance_type(static_cast<InstanceType>(
api_instance_type + Internals::kFirstJSApiObjectType));
}
void FunctionTemplateInfo::SetAllowedReceiverInstanceTypeRange(
int api_instance_type_start, int api_instance_type_end) {
// Translate |api_instance_type_start| and |api_instance_type_end| values
// from range [Internals::kFirstEmbedderJSApiObjectType,
// Internals::kLastEmbedderJSApiObjectType] to range
// [Internals::kFirstJSApiObjectType, Internals::kLastJSApiObjectType].
DCHECK_LE(Internals::kFirstEmbedderJSApiObjectType, api_instance_type_start);
DCHECK_LE(api_instance_type_start, api_instance_type_end);
DCHECK_LE(api_instance_type_end, Internals::kLastEmbedderJSApiObjectType);
// kNoJSApiObjectType must correspond to JS_API_OBJECT_TYPE.
static_assert(kNoJSApiObjectType == 0);
static_assert(JS_API_OBJECT_TYPE == Internals::kFirstJSApiObjectType);
set_allowed_receiver_instance_type_range_start(static_cast<InstanceType>(
api_instance_type_start + Internals::kFirstJSApiObjectType));
set_allowed_receiver_instance_type_range_end(static_cast<InstanceType>(
api_instance_type_end + Internals::kFirstJSApiObjectType));
}
// Ensure that instance type fields in FunctionTemplateInfo are big enough
// to fit the whole JSApiObject type range.
static_assert(
FunctionTemplateInfo::AllowedReceiverInstanceTypeRangeStartBits::is_valid(
LAST_JS_API_OBJECT_TYPE));
static_assert(
FunctionTemplateInfo::AllowedReceiverInstanceTypeRangeEndBits::is_valid(
LAST_JS_API_OBJECT_TYPE));
bool TemplateInfo::should_cache() const {
return serial_number() != kDoNotCache;
}
bool TemplateInfo::is_cached() const { return serial_number() > kUncached; }
bool FunctionTemplateInfo::instantiated() {
return IsSharedFunctionInfo(shared_function_info());
}
inline bool FunctionTemplateInfo::BreakAtEntry(Isolate* isolate) {
Tagged<Object> maybe_shared = shared_function_info();
if (IsSharedFunctionInfo(maybe_shared)) {
Tagged<SharedFunctionInfo> shared = SharedFunctionInfo::cast(maybe_shared);
return shared->BreakAtEntry(isolate);
}
return false;
}
Tagged<FunctionTemplateInfo> FunctionTemplateInfo::GetParent(Isolate* isolate) {
Tagged<Object> parent = GetParentTemplate();
return IsUndefined(parent, isolate) ? Tagged<FunctionTemplateInfo>{}
: FunctionTemplateInfo::cast(parent);
}
Tagged<ObjectTemplateInfo> ObjectTemplateInfo::GetParent(Isolate* isolate) {
Tagged<Object> maybe_ctor = constructor();
if (IsUndefined(maybe_ctor, isolate)) return ObjectTemplateInfo();
Tagged<FunctionTemplateInfo> constructor =
FunctionTemplateInfo::cast(maybe_ctor);
while (true) {
constructor = constructor->GetParent(isolate);
if (constructor.is_null()) return ObjectTemplateInfo();
Tagged<Object> maybe_obj = constructor->GetInstanceTemplate();
if (!IsUndefined(maybe_obj, isolate)) {
return ObjectTemplateInfo::cast(maybe_obj);
}
}
return Tagged<ObjectTemplateInfo>();
}
int ObjectTemplateInfo::embedder_field_count() const {
return EmbedderFieldCountBits::decode(data());
}
void ObjectTemplateInfo::set_embedder_field_count(int count) {
DCHECK_LE(count, JSObject::kMaxEmbedderFields);
return set_data(EmbedderFieldCountBits::update(data(), count));
}
bool ObjectTemplateInfo::immutable_proto() const {
return IsImmutablePrototypeBit::decode(data());
}
void ObjectTemplateInfo::set_immutable_proto(bool immutable) {
return set_data(IsImmutablePrototypeBit::update(data(), immutable));
}
bool ObjectTemplateInfo::code_like() const {
return IsCodeKindBit::decode(data());
}
void ObjectTemplateInfo::set_code_like(bool is_code_like) {
return set_data(IsCodeKindBit::update(data(), is_code_like));
}
bool FunctionTemplateInfo::IsTemplateFor(Tagged<JSObject> object) const {
return IsTemplateFor(object->map());
}
bool TemplateInfo::TryGetIsolate(Isolate** isolate) const {
if (GetIsolateFromHeapObject(*this, isolate)) return true;
Isolate* isolate_value = Isolate::TryGetCurrent();
if (isolate_value != nullptr) {
*isolate = isolate_value;
return true;
}
return false;
}
Isolate* TemplateInfo::GetIsolateChecked() const {
Isolate* isolate;
CHECK(TryGetIsolate(&isolate));
return isolate;
}
// static
template <typename ReturnType>
MaybeHandle<ReturnType> TemplateInfo::ProbeInstantiationsCache(
Isolate* isolate, DirectHandle<NativeContext> native_context,
int serial_number, CachingMode caching_mode) {
DCHECK_NE(serial_number, TemplateInfo::kDoNotCache);
if (serial_number == TemplateInfo::kUncached) {
return {};
}
if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) {
Tagged<FixedArray> fast_cache =
native_context->fast_template_instantiations_cache();
Handle<Object> object{fast_cache->get(serial_number), isolate};
if (IsTheHole(*object, isolate)) {
return {};
}
return Handle<ReturnType>::cast(object);
}
if (caching_mode == CachingMode::kUnlimited ||
(serial_number < TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
Tagged<SimpleNumberDictionary> slow_cache =
native_context->slow_template_instantiations_cache();
InternalIndex entry = slow_cache->FindEntry(isolate, serial_number);
if (entry.is_found()) {
return handle(ReturnType::cast(slow_cache->ValueAt(entry)), isolate);
}
}
return {};
}
// static
template <typename InstantiationType, typename TemplateInfoType>
void TemplateInfo::CacheTemplateInstantiation(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<TemplateInfoType> data, CachingMode caching_mode,
Handle<InstantiationType> object) {
DCHECK_NE(TemplateInfo::kDoNotCache, data->serial_number());
int serial_number = data->serial_number();
if (serial_number == TemplateInfo::kUncached) {
serial_number = isolate->heap()->GetNextTemplateSerialNumber();
}
if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) {
Handle<FixedArray> fast_cache =
handle(native_context->fast_template_instantiations_cache(), isolate);
Handle<FixedArray> new_cache =
FixedArray::SetAndGrow(isolate, fast_cache, serial_number, object);
if (*new_cache != *fast_cache) {
native_context->set_fast_template_instantiations_cache(*new_cache);
}
data->set_serial_number(serial_number);
} else if (caching_mode == CachingMode::kUnlimited ||
(serial_number <
TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
Handle<SimpleNumberDictionary> cache =
handle(native_context->slow_template_instantiations_cache(), isolate);
auto new_cache =
SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
if (*new_cache != *cache) {
native_context->set_slow_template_instantiations_cache(*new_cache);
}
data->set_serial_number(serial_number);
} else {
// we've overflowed the cache limit, no more caching
data->set_serial_number(TemplateInfo::kDoNotCache);
}
}
// static
template <typename TemplateInfoType>
void TemplateInfo::UncacheTemplateInstantiation(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<TemplateInfoType> data, CachingMode caching_mode) {
int serial_number = data->serial_number();
if (serial_number < 0) return;
if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) {
Tagged<FixedArray> fast_cache =
native_context->fast_template_instantiations_cache();
DCHECK(!IsUndefined(fast_cache->get(serial_number), isolate));
fast_cache->set(serial_number, ReadOnlyRoots{isolate}.the_hole_value(),
SKIP_WRITE_BARRIER);
data->set_serial_number(TemplateInfo::kUncached);
} else if (caching_mode == CachingMode::kUnlimited ||
(serial_number <
TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
Handle<SimpleNumberDictionary> cache =
handle(native_context->slow_template_instantiations_cache(), isolate);
InternalIndex entry = cache->FindEntry(isolate, serial_number);
DCHECK(entry.is_found());
cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
native_context->set_slow_template_instantiations_cache(*cache);
data->set_serial_number(TemplateInfo::kUncached);
}
}
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_TEMPLATES_INL_H_