Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

14
deps/v8/src/api/DIR_METADATA vendored Normal file
View File

@ -0,0 +1,14 @@
# Metadata information for this directory.
#
# For more information on DIR_METADATA files, see:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
#
# For the schema of this file, see Metadata message:
# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
monorail {
component: "Blink>JavaScript>API"
}
buganizer_public: {
component_id: 1456124
}

10
deps/v8/src/api/OWNERS vendored Normal file
View File

@ -0,0 +1,10 @@
file:../../include/OWNERS
clemensb@chromium.org
ishell@chromium.org
jkummerow@chromium.org
leszeks@chromium.org
mlippautz@chromium.org
verwaest@chromium.org
# For v8-debug.h implementations.
per-file api.cc=file:../debug/OWNERS

489
deps/v8/src/api/api-arguments-inl.h vendored Normal file
View File

@ -0,0 +1,489 @@
// 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.
#ifndef V8_API_API_ARGUMENTS_INL_H_
#define V8_API_API_ARGUMENTS_INL_H_
#include "src/api/api-arguments.h"
// Include the non-inl header before the rest of the headers.
#include "src/api/api-inl.h"
#include "src/debug/debug.h"
#include "src/execution/vm-state-inl.h"
#include "src/logging/runtime-call-stats-scope.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/instance-type.h"
#include "src/objects/slots-inl.h"
namespace v8 {
namespace internal {
CustomArgumentsBase::CustomArgumentsBase(Isolate* isolate)
: Relocatable(isolate) {}
template <typename T>
CustomArguments<T>::~CustomArguments() {
slot_at(kReturnValueIndex).store(Tagged<Object>(kHandleZapValue));
}
template <typename T>
template <typename V>
Handle<V> CustomArguments<T>::GetReturnValue(Isolate* isolate) const {
// Check the ReturnValue.
FullObjectSlot slot = slot_at(kReturnValueIndex);
DCHECK(Is<JSAny>(*slot));
return Cast<V>(Handle<Object>(slot.location()));
}
inline Tagged<JSObject> PropertyCallbackArguments::holder() const {
return Cast<JSObject>(*slot_at(T::kHolderIndex));
}
inline Tagged<Object> PropertyCallbackArguments::receiver() const {
return *slot_at(T::kThisIndex);
}
#define DCHECK_NAME_COMPATIBLE(interceptor, name) \
DCHECK(interceptor->is_named()); \
DCHECK(!name->IsPrivate()); \
DCHECK_IMPLIES(IsSymbol(*name), interceptor->can_intercept_symbols());
#define PREPARE_CALLBACK_INFO_ACCESSOR(ISOLATE, F, API_RETURN_TYPE, \
ACCESSOR_INFO, RECEIVER, ACCESSOR_KIND, \
EXCEPTION_CONTEXT) \
if (ISOLATE->should_check_side_effects() && \
!ISOLATE->debug()->PerformSideEffectCheckForAccessor( \
ACCESSOR_INFO, RECEIVER, ACCESSOR_KIND)) { \
return {}; \
} \
const PropertyCallbackInfo<API_RETURN_TYPE>& callback_info = \
GetPropertyCallbackInfo<API_RETURN_TYPE>(); \
ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F), \
EXCEPTION_CONTEXT, &callback_info);
#define PREPARE_CALLBACK_INFO_INTERCEPTOR(ISOLATE, F, API_RETURN_TYPE, \
INTERCEPTOR_INFO, EXCEPTION_CONTEXT) \
if (ISOLATE->should_check_side_effects() && \
!ISOLATE->debug()->PerformSideEffectCheckForInterceptor( \
INTERCEPTOR_INFO)) { \
return {}; \
} \
const PropertyCallbackInfo<API_RETURN_TYPE>& callback_info = \
GetPropertyCallbackInfo<API_RETURN_TYPE>(); \
ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F), \
EXCEPTION_CONTEXT, &callback_info);
DirectHandle<Object> FunctionCallbackArguments::CallOrConstruct(
Tagged<FunctionTemplateInfo> function, bool is_construct) {
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionCallback);
v8::FunctionCallback f =
reinterpret_cast<v8::FunctionCallback>(function->callback(isolate));
if (isolate->should_check_side_effects() &&
!isolate->debug()->PerformSideEffectCheckForCallback(
handle(function, isolate))) {
return {};
}
FunctionCallbackInfo<v8::Value> info(values_, argv_, argc_);
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f),
is_construct ? ExceptionContext::kConstructor
: ExceptionContext::kOperation,
&info);
f(info);
return GetReturnValue<Object>(isolate);
}
PropertyCallbackArguments::~PropertyCallbackArguments(){
#ifdef DEBUG
// TODO(chromium:1310062): enable this check.
// if (javascript_execution_counter_) {
// CHECK_WITH_MSG(javascript_execution_counter_ ==
// isolate()->javascript_execution_counter(),
// "Unexpected side effect detected");
// }
#endif // DEBUG
}
Maybe<InterceptorResult> PropertyCallbackArguments::GetBooleanReturnValue(
v8::Intercepted intercepted, const char* callback_kind_for_error_message,
bool ignore_return_value) {
Isolate* isolate = this->isolate();
if (isolate->has_exception()) {
// TODO(ishell, 328490288): fix Node.js which has Setter/Definer
// interceptor callbacks not returning v8::Intercepted::kYes on exceptions.
if ((false) && DEBUG_BOOL && (intercepted == v8::Intercepted::kNo)) {
FATAL(
"Check failed: %s interceptor callback has thrown an "
"exception but hasn't returned v8::Intercepted::kYes.",
callback_kind_for_error_message);
}
return Nothing<InterceptorResult>();
}
if (intercepted == v8::Intercepted::kNo) {
// Not intercepted, there must be no side effects including exceptions.
DCHECK(!isolate->has_exception());
return Just(InterceptorResult::kNotIntercepted);
}
DCHECK_EQ(intercepted, v8::Intercepted::kYes);
AcceptSideEffects();
if (ignore_return_value) return Just(InterceptorResult::kTrue);
bool result = IsTrue(*GetReturnValue<Boolean>(isolate), isolate);
// TODO(ishell, 348688196): ensure callbacks comply with this and
// enable the check.
if ((false) && DEBUG_BOOL && !result && ShouldThrowOnError()) {
FATAL(
"Check failed: %s interceptor callback hasn't thrown an "
"exception on failure as requested.",
callback_kind_for_error_message);
}
return Just(result ? InterceptorResult::kTrue : InterceptorResult::kFalse);
}
// -------------------------------------------------------------------------
// Named Interceptor callbacks.
DirectHandle<JSObjectOrUndefined>
PropertyCallbackArguments::CallNamedEnumerator(
DirectHandle<InterceptorInfo> interceptor) {
DCHECK(interceptor->is_named());
RCS_SCOPE(isolate(), RuntimeCallCounterId::kNamedEnumeratorCallback);
return CallPropertyEnumerator(interceptor);
}
// TODO(ishell): return std::optional<PropertyAttributes>.
DirectHandle<Object> PropertyCallbackArguments::CallNamedQuery(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name) {
DCHECK_NAME_COMPATIBLE(interceptor, name);
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedQueryCallback);
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(Smi::FromInt(v8::None));
NamedPropertyQueryCallback f =
ToCData<NamedPropertyQueryCallback, kApiNamedPropertyQueryCallbackTag>(
isolate, interceptor->query());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Integer, interceptor,
ExceptionContext::kNamedQuery);
v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
if (intercepted == v8::Intercepted::kNo) return {};
return GetReturnValue<Object>(isolate);
}
DirectHandle<JSAny> PropertyCallbackArguments::CallNamedGetter(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name) {
DCHECK_NAME_COMPATIBLE(interceptor, name);
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedGetterCallback);
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
NamedPropertyGetterCallback f =
ToCData<NamedPropertyGetterCallback, kApiNamedPropertyGetterCallbackTag>(
isolate, interceptor->getter());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
ExceptionContext::kNamedGetter);
v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
if (intercepted == v8::Intercepted::kNo) return {};
return GetReturnValue<JSAny>(isolate);
}
Handle<JSAny> PropertyCallbackArguments::CallNamedDescriptor(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name) {
DCHECK_NAME_COMPATIBLE(interceptor, name);
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedDescriptorCallback);
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
NamedPropertyDescriptorCallback f =
ToCData<NamedPropertyDescriptorCallback,
kApiNamedPropertyDescriptorCallbackTag>(
isolate, interceptor->descriptor());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
ExceptionContext::kNamedDescriptor);
v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
if (intercepted == v8::Intercepted::kNo) return {};
return GetReturnValue<JSAny>(isolate);
}
v8::Intercepted PropertyCallbackArguments::CallNamedSetter(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name,
DirectHandle<Object> value) {
DCHECK_NAME_COMPATIBLE(interceptor, name);
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedSetterCallback);
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
NamedPropertySetterCallback f =
ToCData<NamedPropertySetterCallback, kApiNamedPropertySetterCallbackTag>(
isolate, interceptor->setter());
DirectHandle<InterceptorInfo> has_side_effects;
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, void, has_side_effects,
ExceptionContext::kNamedSetter);
v8::Intercepted intercepted =
f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
return intercepted;
}
v8::Intercepted PropertyCallbackArguments::CallNamedDefiner(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name,
const v8::PropertyDescriptor& desc) {
DCHECK_NAME_COMPATIBLE(interceptor, name);
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedDefinerCallback);
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
NamedPropertyDefinerCallback f = ToCData<NamedPropertyDefinerCallback,
kApiNamedPropertyDefinerCallbackTag>(
isolate, interceptor->definer());
DirectHandle<InterceptorInfo> has_side_effects;
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, void, has_side_effects,
ExceptionContext::kNamedDefiner);
v8::Intercepted intercepted =
f(v8::Utils::ToLocal(name), desc, callback_info);
return intercepted;
}
v8::Intercepted PropertyCallbackArguments::CallNamedDeleter(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name) {
DCHECK_NAME_COMPATIBLE(interceptor, name);
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedDeleterCallback);
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
NamedPropertyDeleterCallback f = ToCData<NamedPropertyDeleterCallback,
kApiNamedPropertyDeleterCallbackTag>(
isolate, interceptor->deleter());
DirectHandle<InterceptorInfo> has_side_effects;
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, has_side_effects,
ExceptionContext::kNamedDeleter);
v8::Intercepted intercepted = f(v8::Utils::ToLocal(name), callback_info);
return intercepted;
}
// -------------------------------------------------------------------------
// Indexed Interceptor callbacks.
DirectHandle<JSObjectOrUndefined>
PropertyCallbackArguments::CallIndexedEnumerator(
DirectHandle<InterceptorInfo> interceptor) {
DCHECK(!interceptor->is_named());
RCS_SCOPE(isolate(), RuntimeCallCounterId::kIndexedEnumeratorCallback);
return CallPropertyEnumerator(interceptor);
}
// TODO(ishell): return std::optional<PropertyAttributes>.
DirectHandle<Object> PropertyCallbackArguments::CallIndexedQuery(
DirectHandle<InterceptorInfo> interceptor, uint32_t index) {
DCHECK(!interceptor->is_named());
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedQueryCallback);
index_ = index;
slot_at(kPropertyKeyIndex).store(Smi::zero()); // indexed callback marker
slot_at(kReturnValueIndex).store(Smi::FromInt(v8::None));
IndexedPropertyQueryCallbackV2 f =
ToCData<IndexedPropertyQueryCallbackV2,
kApiIndexedPropertyQueryCallbackTag>(isolate,
interceptor->query());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Integer, interceptor,
ExceptionContext::kIndexedQuery);
v8::Intercepted intercepted = f(index, callback_info);
if (intercepted == v8::Intercepted::kNo) return {};
return GetReturnValue<Object>(isolate);
}
DirectHandle<JSAny> PropertyCallbackArguments::CallIndexedGetter(
DirectHandle<InterceptorInfo> interceptor, uint32_t index) {
DCHECK(!interceptor->is_named());
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kNamedGetterCallback);
index_ = index;
slot_at(kPropertyKeyIndex).store(Smi::zero()); // indexed callback marker
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
IndexedPropertyGetterCallbackV2 f =
ToCData<IndexedPropertyGetterCallbackV2,
kApiIndexedPropertyGetterCallbackTag>(isolate,
interceptor->getter());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
ExceptionContext::kIndexedGetter);
v8::Intercepted intercepted = f(index, callback_info);
if (intercepted == v8::Intercepted::kNo) return {};
return GetReturnValue<JSAny>(isolate);
}
Handle<JSAny> PropertyCallbackArguments::CallIndexedDescriptor(
DirectHandle<InterceptorInfo> interceptor, uint32_t index) {
DCHECK(!interceptor->is_named());
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedDescriptorCallback);
index_ = index;
slot_at(kPropertyKeyIndex).store(Smi::zero()); // indexed callback marker
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
IndexedPropertyDescriptorCallbackV2 f =
ToCData<IndexedPropertyDescriptorCallbackV2,
kApiIndexedPropertyDescriptorCallbackTag>(
isolate, interceptor->descriptor());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Value, interceptor,
ExceptionContext::kIndexedDescriptor);
v8::Intercepted intercepted = f(index, callback_info);
if (intercepted == v8::Intercepted::kNo) return {};
return GetReturnValue<JSAny>(isolate);
}
v8::Intercepted PropertyCallbackArguments::CallIndexedSetter(
DirectHandle<InterceptorInfo> interceptor, uint32_t index,
DirectHandle<Object> value) {
DCHECK(!interceptor->is_named());
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedSetterCallback);
index_ = index;
slot_at(kPropertyKeyIndex).store(Smi::zero()); // indexed callback marker
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
IndexedPropertySetterCallbackV2 f =
ToCData<IndexedPropertySetterCallbackV2,
kApiIndexedPropertySetterCallbackTag>(isolate,
interceptor->setter());
DirectHandle<InterceptorInfo> has_side_effects;
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, void, has_side_effects,
ExceptionContext::kIndexedSetter);
v8::Intercepted intercepted =
f(index, v8::Utils::ToLocal(value), callback_info);
return intercepted;
}
v8::Intercepted PropertyCallbackArguments::CallIndexedDefiner(
DirectHandle<InterceptorInfo> interceptor, uint32_t index,
const v8::PropertyDescriptor& desc) {
DCHECK(!interceptor->is_named());
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedDefinerCallback);
index_ = index;
slot_at(kPropertyKeyIndex).store(Smi::zero()); // indexed callback marker
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
IndexedPropertyDefinerCallbackV2 f =
ToCData<IndexedPropertyDefinerCallbackV2,
kApiIndexedPropertyDefinerCallbackTag>(isolate,
interceptor->definer());
DirectHandle<InterceptorInfo> has_side_effects;
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, void, has_side_effects,
ExceptionContext::kIndexedDefiner);
v8::Intercepted intercepted = f(index, desc, callback_info);
return intercepted;
}
v8::Intercepted PropertyCallbackArguments::CallIndexedDeleter(
DirectHandle<InterceptorInfo> interceptor, uint32_t index) {
DCHECK(!interceptor->is_named());
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kIndexedDeleterCallback);
index_ = index;
slot_at(kPropertyKeyIndex).store(Smi::zero()); // indexed callback marker
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
IndexedPropertyDeleterCallbackV2 f =
ToCData<IndexedPropertyDeleterCallbackV2,
kApiIndexedPropertyDeleterCallbackTag>(isolate,
interceptor->deleter());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Boolean, interceptor,
ExceptionContext::kIndexedDeleter);
v8::Intercepted intercepted = f(index, callback_info);
return intercepted;
}
DirectHandle<JSObjectOrUndefined>
PropertyCallbackArguments::CallPropertyEnumerator(
DirectHandle<InterceptorInfo> interceptor) {
// Named and indexed enumerator callbacks have same signatures.
static_assert(std::is_same<NamedPropertyEnumeratorCallback,
IndexedPropertyEnumeratorCallback>::value);
Isolate* isolate = this->isolate();
slot_at(kPropertyKeyIndex).store(Smi::zero()); // not relevant
// Enumerator callback's return value is initialized with undefined even
// though it's supposed to return v8::Array.
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
// TODO(ishell): consider making it return v8::Intercepted to indicate
// whether the result was set or not.
IndexedPropertyEnumeratorCallback f =
v8::ToCData<IndexedPropertyEnumeratorCallback,
kApiIndexedPropertyEnumeratorCallbackTag>(
isolate, interceptor->enumerator());
PREPARE_CALLBACK_INFO_INTERCEPTOR(isolate, f, v8::Array, interceptor,
ExceptionContext::kNamedEnumerator);
f(callback_info);
DirectHandle<JSAny> result = GetReturnValue<JSAny>(isolate);
DCHECK(IsUndefined(*result) || IsJSObject(*result));
return Cast<JSObjectOrUndefined>(result);
}
// -------------------------------------------------------------------------
// Accessors
DirectHandle<JSAny> PropertyCallbackArguments::CallAccessorGetter(
DirectHandle<AccessorInfo> info, DirectHandle<Name> name) {
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kAccessorGetterCallback);
// Unlike interceptor callbacks we know that the property exists, so
// the callback is allowed to have side effects.
AcceptSideEffects();
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
AccessorNameGetterCallback f =
reinterpret_cast<AccessorNameGetterCallback>(info->getter(isolate));
PREPARE_CALLBACK_INFO_ACCESSOR(
isolate, f, v8::Value, info, direct_handle(receiver(), isolate),
ACCESSOR_GETTER, ExceptionContext::kAttributeGet);
f(v8::Utils::ToLocal(name), callback_info);
return GetReturnValue<JSAny>(isolate);
}
bool PropertyCallbackArguments::CallAccessorSetter(
DirectHandle<AccessorInfo> accessor_info, DirectHandle<Name> name,
DirectHandle<Object> value) {
Isolate* isolate = this->isolate();
RCS_SCOPE(isolate, RuntimeCallCounterId::kAccessorSetterCallback);
// Unlike interceptor callbacks we know that the property exists, so
// the callback is allowed to have side effects.
AcceptSideEffects();
slot_at(kPropertyKeyIndex).store(*name);
slot_at(kReturnValueIndex).store(ReadOnlyRoots(isolate).true_value());
// The actual type of setter callback is either
// v8::AccessorNameSetterCallback or
// i::Accessors::AccessorNameBooleanSetterCallback, depending on whether the
// AccessorInfo was created by the API or internally (see accessors.cc).
// Here we handle both cases using the AccessorNameSetterCallback signature
// and checking whether the returned result is set to default value
// (the undefined value).
// TODO(ishell, 348660658): update V8 Api to allow setter callbacks provide
// the result of [[Set]] operation according to JavaScript semantics.
AccessorNameSetterCallback f = reinterpret_cast<AccessorNameSetterCallback>(
accessor_info->setter(isolate));
PREPARE_CALLBACK_INFO_ACCESSOR(
isolate, f, void, accessor_info, direct_handle(receiver(), isolate),
ACCESSOR_SETTER, ExceptionContext::kAttributeSet);
f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
// Historically, in case of v8::AccessorNameSetterCallback it wasn't allowed
// to set the result and not setting the result was treated as successful
// execution.
// During interceptors Api refactoring it was temporarily allowed to call
// v8::ReturnValue<void>::Set[NonEmpty](Local<S>) and the result was just
// converted to v8::Boolean which was then treated as a result of [[Set]].
// In case of AccessorNameBooleanSetterCallback, the result is always
// set to v8::Boolean or an exception is be thrown (in which case the
// result is ignored anyway). So, regardless of whether the signature was
// v8::AccessorNameSetterCallback or AccessorNameBooleanSetterCallback
// the result is guaranteed to be v8::Boolean value indicating success or
// failure.
DirectHandle<Boolean> result = GetReturnValue<Boolean>(isolate);
return IsTrue(*result, isolate);
}
#undef PREPARE_CALLBACK_INFO_ACCESSOR
#undef PREPARE_CALLBACK_INFO_INTERCEPTOR
} // namespace internal
} // namespace v8
#endif // V8_API_API_ARGUMENTS_INL_H_

58
deps/v8/src/api/api-arguments.cc vendored Normal file
View File

@ -0,0 +1,58 @@
// 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.
#include "src/api/api-arguments.h"
#include "src/api/api-arguments-inl.h"
namespace v8 {
namespace internal {
PropertyCallbackArguments::PropertyCallbackArguments(
Isolate* isolate, Tagged<Object> data, Tagged<Object> self,
Tagged<JSObject> holder, Maybe<ShouldThrow> should_throw)
: Super(isolate)
#ifdef DEBUG
,
javascript_execution_counter_(isolate->javascript_execution_counter())
#endif // DEBUG
{
if (DEBUG_BOOL) {
// Zap these fields to ensure that they are initialized by a subsequent
// CallXXX(..).
Tagged<Object> zap_value(kZapValue);
slot_at(T::kPropertyKeyIndex).store(zap_value);
slot_at(T::kReturnValueIndex).store(zap_value);
}
slot_at(T::kThisIndex).store(self);
slot_at(T::kHolderIndex).store(holder);
slot_at(T::kDataIndex).store(data);
slot_at(T::kIsolateIndex)
.store(Tagged<Object>(reinterpret_cast<Address>(isolate)));
int value = Internals::kInferShouldThrowMode;
if (should_throw.IsJust()) {
value = should_throw.FromJust();
}
slot_at(T::kShouldThrowOnErrorIndex).store(Smi::FromInt(value));
slot_at(T::kHolderV2Index).store(Smi::zero());
DCHECK(IsHeapObject(*slot_at(T::kHolderIndex)));
DCHECK(IsSmi(*slot_at(T::kIsolateIndex)));
}
FunctionCallbackArguments::FunctionCallbackArguments(
Isolate* isolate, Tagged<FunctionTemplateInfo> target,
Tagged<HeapObject> new_target, Address* argv, int argc)
: Super(isolate), argv_(argv), argc_(argc) {
slot_at(T::kTargetIndex).store(target);
slot_at(T::kUnusedIndex).store(ReadOnlyRoots(isolate).undefined_value());
slot_at(T::kNewTargetIndex).store(new_target);
slot_at(T::kIsolateIndex)
.store(Tagged<Object>(reinterpret_cast<Address>(isolate)));
slot_at(T::kReturnValueIndex).store(ReadOnlyRoots(isolate).undefined_value());
slot_at(T::kContextIndex).store(isolate->context());
DCHECK(IsSmi(*slot_at(T::kIsolateIndex)));
}
} // namespace internal
} // namespace v8

317
deps/v8/src/api/api-arguments.h vendored Normal file
View File

@ -0,0 +1,317 @@
// 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.
#ifndef V8_API_API_ARGUMENTS_H_
#define V8_API_API_ARGUMENTS_H_
#include "include/v8-template.h"
#include "src/builtins/builtins-utils.h"
#include "src/execution/isolate.h"
#include "src/objects/slots.h"
#include "src/objects/visitors.h"
namespace v8 {
namespace internal {
// Custom arguments replicate a small segment of stack that can be
// accessed through an Arguments object the same way the actual stack
// can.
class CustomArgumentsBase : public Relocatable {
protected:
explicit inline CustomArgumentsBase(Isolate* isolate);
};
template <typename T>
class CustomArguments : public CustomArgumentsBase {
public:
static constexpr int kReturnValueIndex = T::kReturnValueIndex;
static_assert(T::kSize == sizeof(T));
~CustomArguments() override;
inline void IterateInstance(RootVisitor* v) override {
v->VisitRootPointers(Root::kRelocatable, nullptr, slot_at(0),
slot_at(T::kArgsLength));
}
protected:
explicit inline CustomArguments(Isolate* isolate)
: CustomArgumentsBase(isolate) {}
template <typename V>
Handle<V> GetReturnValue(Isolate* isolate) const;
inline Isolate* isolate() const {
return reinterpret_cast<Isolate*>((*slot_at(T::kIsolateIndex)).ptr());
}
inline FullObjectSlot slot_at(int index) const {
// This allows index == T::kArgsLength so "one past the end" slots
// can be retrieved for iterating purposes.
DCHECK_LE(static_cast<unsigned>(index),
static_cast<unsigned>(T::kArgsLength));
return FullObjectSlot(values_ + index);
}
Address values_[T::kArgsLength];
};
// Note: Calling args.Call() sets the return value on args. For multiple
// Call()'s, a new args should be used every time.
// This class also serves as a side effects detection scope (JavaScript code
// execution). It is used for ensuring correctness of the interceptor callback
// implementations. The idea is that the interceptor callback that does not
// intercept an operation must not produce side effects. If the callback
// signals that it has handled the operation (by either returning a respective
// result or by throwing an exception) then the AcceptSideEffects() method
// must be called to "accept" the side effects that have happened during the
// lifetime of the PropertyCallbackArguments object.
class PropertyCallbackArguments final
: public CustomArguments<PropertyCallbackInfo<Value> > {
public:
using T = PropertyCallbackInfo<Value>;
using Super = CustomArguments<T>;
static constexpr int kArgsLength = T::kArgsLength;
static constexpr int kThisIndex = T::kThisIndex;
static constexpr int kDataIndex = T::kDataIndex;
static constexpr int kHolderV2Index = T::kHolderV2Index;
static constexpr int kHolderIndex = T::kHolderIndex;
static constexpr int kIsolateIndex = T::kIsolateIndex;
static constexpr int kShouldThrowOnErrorIndex = T::kShouldThrowOnErrorIndex;
static constexpr int kPropertyKeyIndex = T::kPropertyKeyIndex;
// This constructor leaves kPropertyKeyIndex and kReturnValueIndex slots
// uninitialized in order to let them be initialized by the subsequent
// CallXXX(..) and avoid double initialization. As a consequence, there
// must be no GC call between this constructor and CallXXX(..).
// In debug mode these slots are zapped, so GC should be able to detect
// the misuse of this object.
PropertyCallbackArguments(Isolate* isolate, Tagged<Object> data,
Tagged<Object> self, Tagged<JSObject> holder,
Maybe<ShouldThrow> should_throw);
inline ~PropertyCallbackArguments();
// Don't copy PropertyCallbackArguments, because they would both have the
// same prev_ pointer.
PropertyCallbackArguments(const PropertyCallbackArguments&) = delete;
PropertyCallbackArguments& operator=(const PropertyCallbackArguments&) =
delete;
// -------------------------------------------------------------------------
// Accessor Callbacks
// Returns the result of [[Get]] operation or throws an exception.
// In case of exception empty handle is returned.
// TODO(ishell, 328490288): stop returning empty handles.
inline DirectHandle<JSAny> CallAccessorGetter(DirectHandle<AccessorInfo> info,
DirectHandle<Name> name);
// Returns the result of [[Set]] operation or throws an exception.
V8_WARN_UNUSED_RESULT
inline bool CallAccessorSetter(DirectHandle<AccessorInfo> info,
DirectHandle<Name> name,
DirectHandle<Object> value);
// -------------------------------------------------------------------------
// Named Interceptor Callbacks
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline DirectHandle<Object> CallNamedQuery(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name);
inline DirectHandle<JSAny> CallNamedGetter(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name);
// Calls Setter/Definer/Deleter callback and returns whether the request
// was intercepted.
// Pending exception handling and interpretation of the result should be
// done by the caller using GetBooleanReturnValue(..).
inline v8::Intercepted CallNamedSetter(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name,
DirectHandle<Object> value);
inline v8::Intercepted CallNamedDefiner(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name,
const v8::PropertyDescriptor& desc);
inline v8::Intercepted CallNamedDeleter(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name);
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline Handle<JSAny> CallNamedDescriptor(
DirectHandle<InterceptorInfo> interceptor, DirectHandle<Name> name);
// Returns JSArray-like object with property names or undefined.
inline DirectHandle<JSObjectOrUndefined> CallNamedEnumerator(
DirectHandle<InterceptorInfo> interceptor);
// -------------------------------------------------------------------------
// Indexed Interceptor Callbacks
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline DirectHandle<Object> CallIndexedQuery(
DirectHandle<InterceptorInfo> interceptor, uint32_t index);
inline DirectHandle<JSAny> CallIndexedGetter(
DirectHandle<InterceptorInfo> interceptor, uint32_t index);
// Calls Setter/Definer/Deleter callback and returns whether the request
// was intercepted.
// Pending exception handling and interpretation of the result should be
// done by the caller using GetBooleanReturnValue(..).
inline v8::Intercepted CallIndexedSetter(
DirectHandle<InterceptorInfo> interceptor, uint32_t index,
DirectHandle<Object> value);
inline v8::Intercepted CallIndexedDefiner(
DirectHandle<InterceptorInfo> interceptor, uint32_t index,
const v8::PropertyDescriptor& desc);
inline v8::Intercepted CallIndexedDeleter(
DirectHandle<InterceptorInfo> interceptor, uint32_t index);
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline Handle<JSAny> CallIndexedDescriptor(
DirectHandle<InterceptorInfo> interceptor, uint32_t index);
// Returns JSArray-like object with property names or undefined.
inline DirectHandle<JSObjectOrUndefined> CallIndexedEnumerator(
DirectHandle<InterceptorInfo> interceptor);
// Accept potential JavaScript side effects that might occur during life
// time of this object.
inline void AcceptSideEffects() {
#ifdef DEBUG
javascript_execution_counter_ = 0;
#endif // DEBUG
}
// Converts the result of Setter/Definer/Deleter interceptor callback to
// Maybe<InterceptorResult>.
// Currently, in certain scenarios the actual boolean result returned by
// the Setter/Definer operation is ignored and thus we don't need to process
// the actual return value.
inline Maybe<InterceptorResult> GetBooleanReturnValue(
v8::Intercepted intercepted, const char* callback_kind_for_error_message,
bool ignore_return_value = false);
// TODO(ishell): cleanup this hack by embedding the PropertyCallbackInfo
// into PropertyCallbackArguments object.
template <typename T>
const v8::PropertyCallbackInfo<T>& GetPropertyCallbackInfo() {
return *(reinterpret_cast<PropertyCallbackInfo<T>*>(&values_[0]));
}
// Forwards ShouldThrowOnError() request to the underlying
// v8::PropertyCallbackInfo<> object.
bool ShouldThrowOnError() {
return GetPropertyCallbackInfo<Value>().ShouldThrowOnError();
}
// Unofficial way of getting property key from v8::PropertyCallbackInfo<T>.
template <typename T>
static Tagged<Object> GetPropertyKey(const PropertyCallbackInfo<T>& info) {
return Tagged<Object>(info.args_[kPropertyKeyIndex]);
}
template <typename T>
static Handle<Object> GetPropertyKeyHandle(
const PropertyCallbackInfo<T>& info) {
return Handle<Object>(&info.args_[kPropertyKeyIndex]);
}
// Returns index value passed to CallIndexedXXX(). This works as long as
// all the calls to indexed interceptor callbacks are done via
// PropertyCallbackArguments.
template <typename T>
static uint32_t GetPropertyIndex(const PropertyCallbackInfo<T>& info) {
// Currently all indexed interceptor callbacks are called via
// PropertyCallbackArguments, so it's guaranteed that
// v8::PropertyCallbackInfo<T>::args_ array IS the
// PropertyCallbackArguments::values_ array. As a result we can restore
// pointer to PropertyCallbackArguments object from the former.
Address ptr = reinterpret_cast<Address>(&info.args_) -
offsetof(PropertyCallbackArguments, values_);
auto pca = reinterpret_cast<const PropertyCallbackArguments*>(ptr);
return pca->index_;
}
private:
// Returns JSArray-like object with property names or undefined.
inline DirectHandle<JSObjectOrUndefined> CallPropertyEnumerator(
DirectHandle<InterceptorInfo> interceptor);
inline Tagged<JSObject> holder() const;
inline Tagged<Object> receiver() const;
// This field is used for propagating index value from CallIndexedXXX()
// to ExceptionPropagationCallback.
uint32_t index_ = kMaxUInt32;
#ifdef DEBUG
// This stores current value of Isolate::javascript_execution_counter().
// It's used for detecting whether JavaScript code was executed between
// PropertyCallbackArguments's constructor and destructor.
uint32_t javascript_execution_counter_;
#endif // DEBUG
};
class FunctionCallbackArguments
: public CustomArguments<FunctionCallbackInfo<Value> > {
public:
using T = FunctionCallbackInfo<Value>;
using Super = CustomArguments<T>;
static constexpr int kArgsLength = T::kArgsLength;
static constexpr int kArgsLengthWithReceiver = T::kArgsLengthWithReceiver;
static constexpr int kUnusedIndex = T::kUnusedIndex;
static constexpr int kIsolateIndex = T::kIsolateIndex;
static constexpr int kContextIndex = T::kContextIndex;
static constexpr int kTargetIndex = T::kTargetIndex;
static constexpr int kNewTargetIndex = T::kNewTargetIndex;
static_assert(T::kThisValuesIndex == BuiltinArguments::kReceiverArgsIndex);
static constexpr int kSize = T::kSize;
static constexpr int kImplicitArgsOffset = T::kImplicitArgsOffset;
static constexpr int kValuesOffset = T::kValuesOffset;
static constexpr int kLengthOffset = T::kLengthOffset;
// Make sure all FunctionCallbackInfo constants are in sync.
static_assert(T::kSize == sizeof(T));
static_assert(T::kImplicitArgsOffset == offsetof(T, implicit_args_));
static_assert(T::kValuesOffset == offsetof(T, values_));
static_assert(T::kLengthOffset == offsetof(T, length_));
FunctionCallbackArguments(Isolate* isolate,
Tagged<FunctionTemplateInfo> target,
Tagged<HeapObject> new_target, Address* argv,
int argc);
/*
* The following Call function wraps the calling of all callbacks to handle
* calling either the old or the new style callbacks depending on which one
* has been registered.
* For old callbacks which return an empty handle, the ReturnValue is checked
* and used if it's been set to anything inside the callback.
* New style callbacks always use the return value.
*/
inline DirectHandle<Object> CallOrConstruct(
Tagged<FunctionTemplateInfo> function, bool is_construct);
// Unofficial way of getting target FunctionTemplateInfo from
// v8::FunctionCallbackInfo<T>.
template <typename T>
static Tagged<Object> GetTarget(const FunctionCallbackInfo<T>& info) {
return Tagged<Object>(info.implicit_args_[kTargetIndex]);
}
private:
Address* argv_;
int const argc_;
};
static_assert(BuiltinArguments::kNumExtraArgs ==
BuiltinExitFrameConstants::kNumExtraArgs);
static_assert(BuiltinArguments::kNumExtraArgsWithReceiver ==
BuiltinExitFrameConstants::kNumExtraArgsWithReceiver);
} // namespace internal
} // namespace v8
#endif // V8_API_API_ARGUMENTS_H_

357
deps/v8/src/api/api-inl.h vendored Normal file
View File

@ -0,0 +1,357 @@
// 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_API_API_INL_H_
#define V8_API_API_INL_H_
#include "src/api/api.h"
// Include the non-inl header before the rest of the headers.
#include "include/v8-fast-api-calls.h"
#include "src/common/assert-scope.h"
#include "src/execution/microtask-queue.h"
#include "src/flags/flags.h"
#include "src/handles/handles-inl.h"
#include "src/heap/heap-inl.h"
#include "src/objects/foreign-inl.h"
#include "src/objects/objects-inl.h"
namespace v8 {
template <typename T, internal::ExternalPointerTag tag>
inline T ToCData(i::Isolate* isolate,
v8::internal::Tagged<v8::internal::Object> obj) {
static_assert(sizeof(T) == sizeof(v8::internal::Address));
if (obj == v8::internal::Smi::zero()) return nullptr;
return reinterpret_cast<T>(
v8::internal::Cast<v8::internal::Foreign>(obj)->foreign_address<tag>(
isolate));
}
template <internal::ExternalPointerTag tag>
inline v8::internal::Address ToCData(
i::Isolate* isolate, v8::internal::Tagged<v8::internal::Object> obj) {
if (obj == v8::internal::Smi::zero()) return v8::internal::kNullAddress;
return v8::internal::Cast<v8::internal::Foreign>(obj)->foreign_address<tag>(
isolate);
}
template <internal::ExternalPointerTag tag, typename T>
inline v8::internal::DirectHandle<i::UnionOf<i::Smi, i::Foreign>> FromCData(
v8::internal::Isolate* isolate, T obj) {
static_assert(sizeof(T) == sizeof(v8::internal::Address));
if (obj == nullptr) return direct_handle(v8::internal::Smi::zero(), isolate);
return isolate->factory()->NewForeign<tag>(
reinterpret_cast<v8::internal::Address>(obj));
}
template <internal::ExternalPointerTag tag>
inline v8::internal::DirectHandle<i::UnionOf<i::Smi, i::Foreign>> FromCData(
v8::internal::Isolate* isolate, v8::internal::Address obj) {
if (obj == v8::internal::kNullAddress) {
return direct_handle(v8::internal::Smi::zero(), isolate);
}
return isolate->factory()->NewForeign<tag>(obj);
}
template <class From, class To>
inline Local<To> Utils::Convert(v8::internal::DirectHandle<From> obj) {
DCHECK(obj.is_null() || IsSmi(*obj) || !IsTheHole(*obj));
#ifdef V8_ENABLE_DIRECT_HANDLE
if (obj.is_null()) return Local<To>();
return Local<To>::FromAddress(obj.address());
#else
// This simply uses the location of the indirect handle wrapped inside a
// "fake" direct handle.
return Local<To>::FromSlot(indirect_handle(obj).location());
#endif
}
// Implementations of ToLocal
#define MAKE_TO_LOCAL(Name) \
template <template <typename> typename HandleType, typename T, typename> \
inline auto Utils::Name(HandleType<T> obj) { \
return Utils::Name##_helper(v8::internal::DirectHandle<T>(obj)); \
}
TO_LOCAL_NAME_LIST(MAKE_TO_LOCAL)
#define MAKE_TO_LOCAL_PRIVATE(Name, From, To) \
inline Local<v8::To> Utils::Name##_helper( \
v8::internal::DirectHandle<v8::internal::From> obj) { \
return Convert<v8::internal::From, v8::To>(obj); \
}
TO_LOCAL_LIST(MAKE_TO_LOCAL_PRIVATE)
#define MAKE_TO_LOCAL_TYPED_ARRAY(Type, typeName, TYPE, ctype) \
Local<v8::Type##Array> Utils::ToLocal##Type##Array( \
v8::internal::DirectHandle<v8::internal::JSTypedArray> obj) { \
DCHECK(obj->type() == v8::internal::kExternal##Type##Array); \
return Convert<v8::internal::JSTypedArray, v8::Type##Array>(obj); \
}
TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY)
#undef MAKE_TO_LOCAL_TYPED_ARRAY
#undef MAKE_TO_LOCAL
#undef MAKE_TO_LOCAL_PRIVATE
#undef TO_LOCAL_LIST
// Implementations of OpenHandle
#ifdef V8_ENABLE_DIRECT_HANDLE
#define MAKE_OPEN_HANDLE(From, To) \
v8::internal::Handle<v8::internal::To> Utils::OpenHandle( \
const v8::From* that, bool allow_empty_handle) { \
DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \
DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \
Is##To(v8::internal::Tagged<v8::internal::Object>( \
v8::internal::ValueHelper::ValueAsAddress(that)))); \
if (v8::internal::ValueHelper::IsEmpty(that)) { \
return v8::internal::Handle<v8::internal::To>::null(); \
} \
return v8::internal::Handle<v8::internal::To>( \
v8::HandleScope::CreateHandleForCurrentIsolate( \
v8::internal::ValueHelper::ValueAsAddress(that))); \
} \
\
v8::internal::DirectHandle<v8::internal::To> Utils::OpenDirectHandle( \
const v8::From* that, bool allow_empty_handle) { \
DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \
DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \
Is##To(v8::internal::Tagged<v8::internal::Object>( \
v8::internal::ValueHelper::ValueAsAddress(that)))); \
return v8::internal::DirectHandle<v8::internal::To>::FromAddress( \
v8::internal::ValueHelper::ValueAsAddress(that)); \
} \
\
v8::internal::IndirectHandle<v8::internal::To> Utils::OpenIndirectHandle( \
const v8::From* that, bool allow_empty_handle) { \
return Utils::OpenHandle(that, allow_empty_handle); \
}
#else // !V8_ENABLE_DIRECT_HANDLE
#define MAKE_OPEN_HANDLE(From, To) \
v8::internal::Handle<v8::internal::To> Utils::OpenHandle( \
const v8::From* that, bool allow_empty_handle) { \
DCHECK(allow_empty_handle || !v8::internal::ValueHelper::IsEmpty(that)); \
DCHECK(v8::internal::ValueHelper::IsEmpty(that) || \
Is##To(v8::internal::Tagged<v8::internal::Object>( \
v8::internal::ValueHelper::ValueAsAddress(that)))); \
return v8::internal::Handle<v8::internal::To>( \
reinterpret_cast<v8::internal::Address*>( \
const_cast<v8::From*>(that))); \
} \
\
v8::internal::DirectHandle<v8::internal::To> Utils::OpenDirectHandle( \
const v8::From* that, bool allow_empty_handle) { \
return Utils::OpenHandle(that, allow_empty_handle); \
} \
\
v8::internal::IndirectHandle<v8::internal::To> Utils::OpenIndirectHandle( \
const v8::From* that, bool allow_empty_handle) { \
return Utils::OpenHandle(that, allow_empty_handle); \
}
#endif // V8_ENABLE_DIRECT_HANDLE
OPEN_HANDLE_LIST(MAKE_OPEN_HANDLE)
#undef MAKE_OPEN_HANDLE
#undef OPEN_HANDLE_LIST
template <bool do_callback>
class V8_NODISCARD CallDepthScope {
public:
CallDepthScope(i::Isolate* isolate, Local<Context> context)
: isolate_(isolate), saved_context_(isolate->context(), isolate_) {
isolate_->thread_local_top()->IncrementCallDepth<do_callback>(this);
i::Tagged<i::NativeContext> env = *Utils::OpenDirectHandle(*context);
isolate->set_context(env);
if (do_callback) isolate_->FireBeforeCallEnteredCallback();
}
~CallDepthScope() {
i::MicrotaskQueue* microtask_queue =
i::Cast<i::NativeContext>(isolate_->context())
->microtask_queue(isolate_);
isolate_->thread_local_top()->DecrementCallDepth(this);
// Clear the exception when exiting V8 to avoid memory leaks.
// Also clear termination exceptions iff there's no TryCatch handler.
// TODO(verwaest): Drop this once we propagate exceptions to external
// TryCatch on Throw. This should be debug-only.
if (isolate_->thread_local_top()->CallDepthIsZero() &&
(isolate_->thread_local_top()->try_catch_handler_ == nullptr ||
!isolate_->is_execution_terminating())) {
isolate_->clear_internal_exception();
}
if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue);
#ifdef DEBUG
if (do_callback) {
if (microtask_queue && microtask_queue->microtasks_policy() ==
v8::MicrotasksPolicy::kScoped) {
DCHECK(microtask_queue->GetMicrotasksScopeDepth() ||
!microtask_queue->DebugMicrotasksScopeDepthIsZero());
}
}
DCHECK(CheckKeptObjectsClearedAfterMicrotaskCheckpoint(microtask_queue));
#endif
isolate_->set_context(*saved_context_);
}
CallDepthScope(const CallDepthScope&) = delete;
CallDepthScope& operator=(const CallDepthScope&) = delete;
private:
#ifdef DEBUG
bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint(
i::MicrotaskQueue* microtask_queue) {
bool did_perform_microtask_checkpoint =
isolate_->thread_local_top()->CallDepthIsZero() && do_callback &&
microtask_queue &&
microtask_queue->microtasks_policy() == MicrotasksPolicy::kAuto &&
!isolate_->is_execution_terminating();
return !did_perform_microtask_checkpoint ||
IsUndefined(isolate_->heap()->weak_refs_keep_during_job(), isolate_);
}
#endif
i::Isolate* const isolate_;
i::Handle<i::Context> saved_context_;
i::Address previous_stack_height_;
friend class i::ThreadLocalTop;
DISALLOW_NEW_AND_DELETE()
};
class V8_NODISCARD InternalEscapableScope : public EscapableHandleScopeBase {
public:
explicit inline InternalEscapableScope(i::Isolate* isolate)
: EscapableHandleScopeBase(reinterpret_cast<v8::Isolate*>(isolate)) {}
/**
* Pushes the value into the previous scope and returns a handle to it.
* Cannot be called twice.
*/
template <class T>
V8_INLINE Local<T> Escape(Local<T> value) {
#ifdef V8_ENABLE_DIRECT_HANDLE
return value;
#else
DCHECK(!value.IsEmpty());
return Local<T>::FromSlot(EscapeSlot(value.slot()));
#endif
}
template <class T>
V8_INLINE MaybeLocal<T> EscapeMaybe(MaybeLocal<T> maybe_value) {
Local<T> value;
if (!maybe_value.ToLocal(&value)) return maybe_value;
return Escape(value);
}
};
template <typename T>
void CopySmiElementsToTypedBuffer(T* dst, uint32_t length,
i::Tagged<i::FixedArray> elements) {
for (uint32_t i = 0; i < length; ++i) {
double value = i::Object::NumberValue(
i::Cast<i::Smi>(elements->get(static_cast<int>(i))));
// TODO(mslekova): Avoid converting back-and-forth when possible, e.g
// avoid int->double->int conversions to boost performance.
dst[i] = i::ConvertDouble<T>(value);
}
}
template <typename T>
void CopyDoubleElementsToTypedBuffer(T* dst, uint32_t length,
i::Tagged<i::FixedDoubleArray> elements) {
for (uint32_t i = 0; i < length; ++i) {
double value = elements->get_scalar(static_cast<int>(i));
// TODO(mslekova): There are certain cases, e.g. double->double, in which
// we could do a memcpy directly.
dst[i] = i::ConvertDouble<T>(value);
}
}
template <CTypeInfo::Identifier type_info_id, typename T>
bool CopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst,
uint32_t max_length) {
static_assert(
std::is_same<T, typename i::CTypeInfoTraits<
CTypeInfo(type_info_id).GetType()>::ctype>::value,
"Type mismatch between the expected CTypeInfo::Type and the destination "
"array");
uint32_t length = src->Length();
if (length == 0) {
// Early return here to avoid a cast error below, as the EmptyFixedArray
// cannot be cast to a FixedDoubleArray.
return true;
}
if (length > max_length) {
return false;
}
i::DisallowGarbageCollection no_gc;
i::Tagged<i::JSArray> obj = *Utils::OpenDirectHandle(*src);
if (i::Object::IterationHasObservableEffects(obj)) {
// The array has a custom iterator.
return false;
}
i::Tagged<i::FixedArrayBase> elements = obj->elements();
switch (obj->GetElementsKind()) {
case i::PACKED_SMI_ELEMENTS:
CopySmiElementsToTypedBuffer(dst, length,
i::Cast<i::FixedArray>(elements));
return true;
case i::PACKED_DOUBLE_ELEMENTS:
CopyDoubleElementsToTypedBuffer(dst, length,
i::Cast<i::FixedDoubleArray>(elements));
return true;
default:
return false;
}
}
// Deprecated; to be removed.
template <const CTypeInfo* type_info, typename T>
inline bool V8_EXPORT TryCopyAndConvertArrayToCppBuffer(Local<Array> src,
T* dst,
uint32_t max_length) {
return CopyAndConvertArrayToCppBuffer<type_info->GetId(), T>(src, dst,
max_length);
}
template <CTypeInfo::Identifier type_info_id, typename T>
inline bool V8_EXPORT TryToCopyAndConvertArrayToCppBuffer(Local<Array> src,
T* dst,
uint32_t max_length) {
return CopyAndConvertArrayToCppBuffer<type_info_id, T>(src, dst, max_length);
}
namespace internal {
void HandleScopeImplementer::EnterContext(Tagged<NativeContext> context) {
entered_contexts_.push_back(context);
}
DirectHandle<NativeContext> HandleScopeImplementer::LastEnteredContext() {
if (entered_contexts_.empty()) return {};
return direct_handle(entered_contexts_.back(), isolate_);
}
} // namespace internal
} // namespace v8
#endif // V8_API_API_INL_H_

19
deps/v8/src/api/api-macros-undef.h vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2021 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.
// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD
#undef LOG_API
#undef ENTER_V8_BASIC
#undef ENTER_V8_HELPER_INTERNAL
#undef PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE
#undef PREPARE_FOR_EXECUTION_WITH_CONTEXT
#undef PREPARE_FOR_EXECUTION
#undef ENTER_V8
#undef ENTER_V8_NO_SCRIPT
#undef ENTER_V8_NO_SCRIPT_NO_EXCEPTION
#undef ENTER_V8_FOR_NEW_CONTEXT
#undef RETURN_ON_FAILED_EXECUTION
#undef RETURN_ON_FAILED_EXECUTION_PRIMITIVE
#undef RETURN_ESCAPED

112
deps/v8/src/api/api-macros.h vendored Normal file
View File

@ -0,0 +1,112 @@
// Copyright 2021 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.
// Note 1: Any file that includes this one should include api-macros-undef.h
// at the bottom.
// Note 2: This file is deliberately missing the include guards (the undeffing
// approach wouldn't work otherwise).
//
// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD
/*
* Most API methods should use one of the three macros:
*
* ENTER_V8, ENTER_V8_NO_SCRIPT, ENTER_V8_NO_SCRIPT_NO_EXCEPTION.
*
* The latter two assume that no script is executed, and no exceptions are
* scheduled in addition (respectively). Creating an exception and
* removing it before returning is ok.
*
* Exceptions should be handled either by invoking one of the
* RETURN_ON_FAILED_EXECUTION* macros.
*
* API methods that are part of the debug interface should use
*
* PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE
*
* in a similar fashion to ENTER_V8.
*/
#define API_RCS_SCOPE(i_isolate, class_name, function_name) \
RCS_SCOPE(i_isolate, \
i::RuntimeCallCounterId::kAPI_##class_name##_##function_name);
#define ENTER_V8_BASIC(i_isolate) \
/* Embedders should never enter V8 after terminating it */ \
DCHECK_IMPLIES(i::v8_flags.strict_termination_checks, \
!i_isolate->is_execution_terminating()); \
i::VMState<v8::OTHER> __state__((i_isolate))
#define ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, \
function_name, HandleScopeClass, do_callback) \
DCHECK(!i_isolate->is_execution_terminating()); \
HandleScopeClass handle_scope(i_isolate); \
CallDepthScope<do_callback> call_depth_scope(i_isolate, context); \
API_RCS_SCOPE(i_isolate, class_name, function_name); \
i::VMState<v8::OTHER> __state__((i_isolate)); \
bool has_exception = false
#define PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(i_isolate, context, \
T) \
DCHECK(!i_isolate->is_execution_terminating()); \
InternalEscapableScope handle_scope(i_isolate); \
CallDepthScope<false> call_depth_scope(i_isolate, context); \
i::VMState<v8::OTHER> __state__((i_isolate)); \
bool has_exception = false
#define PREPARE_FOR_EXECUTION(context, class_name, function_name) \
auto i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate()); \
i_isolate->clear_internal_exception(); \
ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \
InternalEscapableScope, false);
#define ENTER_V8(i_isolate, context, class_name, function_name, \
HandleScopeClass) \
ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \
HandleScopeClass, true)
#ifdef DEBUG
#define ENTER_V8_NO_SCRIPT(i_isolate, context, class_name, function_name, \
HandleScopeClass) \
ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \
HandleScopeClass, false); \
i::DisallowJavascriptExecutionDebugOnly __no_script__((i_isolate))
// Lightweight version for APIs that don't require an active context.
#define DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate) \
i::DisallowJavascriptExecutionDebugOnly __no_script__((i_isolate)); \
i::DisallowExceptions __no_exceptions__((i_isolate))
#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate) \
i::VMState<v8::OTHER> __state__((i_isolate)); \
DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate)
#define ENTER_V8_FOR_NEW_CONTEXT(i_isolate) \
DCHECK_IMPLIES(i::v8_flags.strict_termination_checks, \
!(i_isolate)->is_execution_terminating()); \
i::VMState<v8::OTHER> __state__((i_isolate)); \
i::DisallowExceptions __no_exceptions__((i_isolate))
#else // DEBUG
#define ENTER_V8_NO_SCRIPT(i_isolate, context, class_name, function_name, \
HandleScopeClass) \
ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \
HandleScopeClass, false)
#define DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate)
#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate) \
i::VMState<v8::OTHER> __state__((i_isolate));
#define ENTER_V8_FOR_NEW_CONTEXT(i_isolate) \
i::VMState<v8::OTHER> __state__((i_isolate));
#endif // DEBUG
#define RETURN_ON_FAILED_EXECUTION(T) \
if (has_exception) return MaybeLocal<T>();
#define RETURN_ON_FAILED_EXECUTION_PRIMITIVE(T) \
if (has_exception) return Nothing<T>();
#define RETURN_ESCAPED(value) return handle_scope.Escape(value);

695
deps/v8/src/api/api-natives.cc vendored Normal file
View File

@ -0,0 +1,695 @@
// Copyright 2015 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/api/api-natives.h"
#include "src/api/api-inl.h"
#include "src/common/globals.h"
#include "src/common/message-template.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/protectors-inl.h"
#include "src/heap/heap-inl.h"
#include "src/logging/runtime-call-stats-scope.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/lookup.h"
#include "src/objects/templates.h"
namespace v8 {
namespace internal {
namespace {
class V8_NODISCARD InvokeScope {
public:
explicit InvokeScope(Isolate* isolate)
: isolate_(isolate), save_context_(isolate) {}
~InvokeScope() {
bool has_exception = isolate_->has_exception();
if (has_exception) {
isolate_->ReportPendingMessages();
} else {
isolate_->clear_pending_message();
}
}
private:
Isolate* isolate_;
SaveContext save_context_;
};
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
DirectHandle<ObjectTemplateInfo> data,
DirectHandle<JSReceiver> new_target,
bool is_prototype);
MaybeHandle<JSFunction> InstantiateFunction(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<FunctionTemplateInfo> data,
MaybeDirectHandle<Name> maybe_name = {});
MaybeHandle<JSFunction> InstantiateFunction(
Isolate* isolate, DirectHandle<FunctionTemplateInfo> data,
MaybeDirectHandle<Name> maybe_name = {}) {
return InstantiateFunction(isolate, isolate->native_context(), data,
maybe_name);
}
MaybeDirectHandle<Object> Instantiate(Isolate* isolate,
DirectHandle<Object> data,
MaybeDirectHandle<Name> maybe_name = {}) {
if (IsFunctionTemplateInfo(*data)) {
return InstantiateFunction(isolate, Cast<FunctionTemplateInfo>(data),
maybe_name);
} else if (IsObjectTemplateInfo(*data)) {
return InstantiateObject(isolate, Cast<ObjectTemplateInfo>(data), {},
false);
} else {
return data;
}
}
MaybeDirectHandle<Object> DefineAccessorProperty(
Isolate* isolate, DirectHandle<JSObject> object, DirectHandle<Name> name,
DirectHandle<Object> getter, DirectHandle<Object> setter,
PropertyAttributes attributes) {
DCHECK_IMPLIES(IsFunctionTemplateInfo(*getter),
Cast<FunctionTemplateInfo>(*getter)->is_cacheable());
DCHECK_IMPLIES(IsFunctionTemplateInfo(*setter),
Cast<FunctionTemplateInfo>(*setter)->is_cacheable());
if (IsFunctionTemplateInfo(*getter) &&
Cast<FunctionTemplateInfo>(*getter)->BreakAtEntry(isolate)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, getter,
InstantiateFunction(isolate, Cast<FunctionTemplateInfo>(getter)));
DirectHandle<Code> trampoline = BUILTIN_CODE(isolate, DebugBreakTrampoline);
Cast<JSFunction>(getter)->UpdateCode(*trampoline);
}
if (IsFunctionTemplateInfo(*setter) &&
Cast<FunctionTemplateInfo>(*setter)->BreakAtEntry(isolate)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, setter,
InstantiateFunction(isolate, Cast<FunctionTemplateInfo>(setter)));
DirectHandle<Code> trampoline = BUILTIN_CODE(isolate, DebugBreakTrampoline);
Cast<JSFunction>(setter)->UpdateCode(*trampoline);
}
RETURN_ON_EXCEPTION(isolate, JSObject::DefineOwnAccessorIgnoreAttributes(
object, name, getter, setter, attributes));
return object;
}
MaybeDirectHandle<Object> DefineDataProperty(Isolate* isolate,
DirectHandle<JSObject> object,
DirectHandle<Name> name,
DirectHandle<Object> prop_data,
PropertyAttributes attributes) {
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
Instantiate(isolate, prop_data, name));
PropertyKey key(isolate, name);
LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
#ifdef DEBUG
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
DCHECK(maybe.IsJust());
if (it.IsFound()) {
THROW_NEW_ERROR(
isolate,
NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name));
}
#endif
MAYBE_RETURN_NULL(Object::AddDataProperty(&it, value, attributes,
Just(ShouldThrow::kThrowOnError),
StoreOrigin::kNamed));
return value;
}
void DisableAccessChecks(Isolate* isolate, DirectHandle<JSObject> object) {
DirectHandle<Map> old_map(object->map(), isolate);
// Copy map so it won't interfere constructor's initial map.
DirectHandle<Map> new_map =
Map::Copy(isolate, old_map, "DisableAccessChecks");
new_map->set_is_access_check_needed(false);
JSObject::MigrateToMap(isolate, object, new_map);
}
void EnableAccessChecks(Isolate* isolate, DirectHandle<JSObject> object) {
DirectHandle<Map> old_map(object->map(), isolate);
// Copy map so it won't interfere constructor's initial map.
DirectHandle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks");
new_map->set_is_access_check_needed(true);
new_map->set_may_have_interesting_properties(true);
JSObject::MigrateToMap(isolate, object, new_map);
}
class V8_NODISCARD AccessCheckDisableScope {
public:
AccessCheckDisableScope(Isolate* isolate, DirectHandle<JSObject> obj)
: isolate_(isolate),
disabled_(obj->map()->is_access_check_needed()),
obj_(obj) {
if (disabled_) {
DisableAccessChecks(isolate_, obj_);
}
}
~AccessCheckDisableScope() {
if (disabled_) {
EnableAccessChecks(isolate_, obj_);
}
}
private:
Isolate* isolate_;
const bool disabled_;
DirectHandle<JSObject> obj_;
};
Tagged<Object> GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
DirectHandle<Context> native_context = isolate->native_context();
DCHECK(!native_context.is_null());
switch (intrinsic) {
#define GET_INTRINSIC_VALUE(name, iname) \
case v8::k##name: \
return native_context->iname();
V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
#undef GET_INTRINSIC_VALUE
}
return Tagged<Object>();
}
template <typename TemplateInfoT>
MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
DirectHandle<TemplateInfoT> data) {
RCS_SCOPE(isolate, RuntimeCallCounterId::kConfigureInstance);
HandleScope scope(isolate);
// Disable access checks while instantiating the object.
AccessCheckDisableScope access_check_scope(isolate, obj);
// Walk the inheritance chain and copy all accessors to current object.
int max_number_of_properties = 0;
Tagged<TemplateInfoT> info = *data;
while (!info.is_null()) {
Tagged<Object> props = info->property_accessors();
if (!IsUndefined(props, isolate)) {
max_number_of_properties += Cast<ArrayList>(props)->length();
}
info = info->GetParent(isolate);
}
if (max_number_of_properties > 0) {
int valid_descriptors = 0;
// Use a temporary FixedArray to accumulate unique accessors.
DirectHandle<FixedArray> array =
isolate->factory()->NewFixedArray(max_number_of_properties);
// TODO(leszeks): Avoid creating unnecessary handles for cases where we
// don't need to append anything.
for (DirectHandle<TemplateInfoT> temp(*data, isolate); !(*temp).is_null();
temp = direct_handle(temp->GetParent(isolate), isolate)) {
// Accumulate accessors.
Tagged<Object> maybe_properties = temp->property_accessors();
if (!IsUndefined(maybe_properties, isolate)) {
valid_descriptors = AccessorInfo::AppendUnique(
isolate, direct_handle(maybe_properties, isolate), array,
valid_descriptors);
}
}
// Install accumulated accessors.
for (int i = 0; i < valid_descriptors; i++) {
DirectHandle<AccessorInfo> accessor(Cast<AccessorInfo>(array->get(i)),
isolate);
DirectHandle<Name> name(Cast<Name>(accessor->name()), isolate);
JSObject::SetAccessor(obj, name, accessor,
accessor->initial_property_attributes())
.Assert();
}
}
Tagged<Object> maybe_property_list = data->property_list();
if (IsUndefined(maybe_property_list, isolate)) return obj;
DirectHandle<ArrayList> properties(Cast<ArrayList>(maybe_property_list),
isolate);
if (properties->length() == 0) return obj;
int i = 0;
for (int c = 0; c < data->number_of_properties(); c++) {
auto name = direct_handle(Cast<Name>(properties->get(i++)), isolate);
Tagged<Object> bit = properties->get(i++);
if (IsSmi(bit)) {
PropertyDetails details(Cast<Smi>(bit));
PropertyAttributes attributes = details.attributes();
PropertyKind kind = details.kind();
if (kind == PropertyKind::kData) {
auto prop_data = handle(properties->get(i++), isolate);
RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
prop_data, attributes));
} else {
auto getter = direct_handle(properties->get(i++), isolate);
auto setter = direct_handle(properties->get(i++), isolate);
RETURN_ON_EXCEPTION(
isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
attributes));
}
} else {
// Intrinsic data property --- Get appropriate value from the current
// context.
PropertyDetails details(Cast<Smi>(properties->get(i++)));
PropertyAttributes attributes = details.attributes();
DCHECK_EQ(PropertyKind::kData, details.kind());
v8::Intrinsic intrinsic =
static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
prop_data, attributes));
}
}
return obj;
}
bool IsSimpleInstantiation(Isolate* isolate, Tagged<ObjectTemplateInfo> info,
Tagged<JSReceiver> new_target) {
DisallowGarbageCollection no_gc;
if (!IsJSFunction(new_target)) return false;
Tagged<JSFunction> fun = Cast<JSFunction>(new_target);
if (!fun->shared()->IsApiFunction()) return false;
if (fun->shared()->api_func_data() != info->constructor()) return false;
if (info->immutable_proto()) return false;
return fun->native_context() == isolate->raw_native_context();
}
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
DirectHandle<ObjectTemplateInfo> info,
DirectHandle<JSReceiver> new_target,
bool is_prototype) {
RCS_SCOPE(isolate, RuntimeCallCounterId::kInstantiateObject);
DirectHandle<JSFunction> constructor;
bool should_cache = info->is_cacheable();
if (!new_target.is_null()) {
if (IsSimpleInstantiation(isolate, *info, *new_target)) {
constructor = Cast<JSFunction>(new_target);
} else {
// Disable caching for subclass instantiation.
should_cache = false;
}
}
// Fast path.
Handle<JSObject> result;
if (should_cache) {
if (TemplateInfo::ProbeInstantiationsCache<JSObject>(
isolate, isolate->native_context(), info,
TemplateInfo::CachingMode::kLimited)
.ToHandle(&result)) {
return isolate->factory()->CopyJSObject(result);
}
}
if (constructor.is_null()) {
Tagged<Object> maybe_constructor_info = info->constructor();
if (IsUndefined(maybe_constructor_info, isolate)) {
constructor = isolate->object_function();
} else {
// Enter a new scope. Recursion could otherwise create a lot of handles.
HandleScope scope(isolate);
DirectHandle<FunctionTemplateInfo> cons_templ(
Cast<FunctionTemplateInfo>(maybe_constructor_info), isolate);
DirectHandle<JSFunction> tmp_constructor;
ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
InstantiateFunction(isolate, cons_templ));
constructor = scope.CloseAndEscape(tmp_constructor);
}
if (new_target.is_null()) new_target = constructor;
}
const auto new_js_object_type =
constructor->has_initial_map() &&
IsJSApiWrapperObject(constructor->initial_map())
? NewJSObjectType::kAPIWrapper
: NewJSObjectType::kNoAPIWrapper;
Handle<JSObject> object;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, object,
JSObject::New(constructor, new_target, {}, new_js_object_type));
if (is_prototype) JSObject::OptimizeAsPrototype(object);
ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
ConfigureInstance(isolate, object, info));
if (info->immutable_proto()) {
JSObject::SetImmutableProto(isolate, object);
}
if (!is_prototype) {
// Keep prototypes in slow-mode. Let them be lazily turned fast later on.
// TODO(dcarney): is this necessary?
JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
// Don't cache prototypes.
if (should_cache) {
TemplateInfo::CacheTemplateInstantiation(
isolate, isolate->native_context(), info,
TemplateInfo::CachingMode::kLimited, result);
result = isolate->factory()->CopyJSObject(result);
}
}
return result;
}
namespace {
MaybeDirectHandle<Object> GetInstancePrototype(
Isolate* isolate, DirectHandle<Object> function_template) {
// Enter a new scope. Recursion could otherwise create a lot of handles.
HandleScope scope(isolate);
DirectHandle<JSFunction> parent_instance;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, parent_instance,
InstantiateFunction(isolate,
Cast<FunctionTemplateInfo>(function_template)));
Handle<Object> instance_prototype;
// TODO(cbruni): decide what to do here.
ASSIGN_RETURN_ON_EXCEPTION(
isolate, instance_prototype,
JSObject::GetProperty(isolate, parent_instance,
isolate->factory()->prototype_string()));
return scope.CloseAndEscape(instance_prototype);
}
} // namespace
MaybeHandle<JSFunction> InstantiateFunction(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<FunctionTemplateInfo> info,
MaybeDirectHandle<Name> maybe_name) {
RCS_SCOPE(isolate, RuntimeCallCounterId::kInstantiateFunction);
bool should_cache = info->is_cacheable();
if (should_cache) {
Handle<JSObject> result;
if (TemplateInfo::ProbeInstantiationsCache<JSObject>(
isolate, native_context, info,
TemplateInfo::CachingMode::kUnlimited)
.ToHandle(&result)) {
return Cast<JSFunction>(result);
}
}
DirectHandle<Object> prototype;
if (!info->remove_prototype()) {
DirectHandle<Object> prototype_templ(info->GetPrototypeTemplate(), isolate);
if (IsUndefined(*prototype_templ, isolate)) {
DirectHandle<Object> protoype_provider_templ(
info->GetPrototypeProviderTemplate(), isolate);
if (IsUndefined(*protoype_provider_templ, isolate)) {
prototype = isolate->factory()->NewJSObject(
direct_handle(native_context->object_function(), isolate));
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype,
GetInstancePrototype(isolate, protoype_provider_templ));
}
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype,
InstantiateObject(isolate, Cast<ObjectTemplateInfo>(prototype_templ),
DirectHandle<JSReceiver>(), true));
}
DirectHandle<Object> parent(info->GetParentTemplate(), isolate);
if (!IsUndefined(*parent, isolate)) {
DirectHandle<Object> parent_prototype;
ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
GetInstancePrototype(isolate, parent));
DirectHandle<JSPrototype> checked_parent_prototype;
CHECK(TryCast(parent_prototype, &checked_parent_prototype));
JSObject::ForceSetPrototype(isolate, Cast<JSObject>(prototype),
checked_parent_prototype);
}
}
InstanceType function_type = JS_SPECIAL_API_OBJECT_TYPE;
if (!info->needs_access_check() &&
IsUndefined(info->GetNamedPropertyHandler(), isolate) &&
IsUndefined(info->GetIndexedPropertyHandler(), isolate)) {
function_type = v8_flags.experimental_embedder_instance_types
? info->GetInstanceType()
: JS_API_OBJECT_TYPE;
DCHECK(InstanceTypeChecker::IsJSApiObject(function_type));
}
Handle<JSFunction> function = ApiNatives::CreateApiFunction(
isolate, native_context, info, prototype, function_type, maybe_name);
if (should_cache) {
// Cache the function.
TemplateInfo::CacheTemplateInstantiation(
isolate, native_context, info, TemplateInfo::CachingMode::kUnlimited,
function);
}
MaybeDirectHandle<JSObject> result =
ConfigureInstance(isolate, function, info);
if (result.is_null()) {
// Uncache on error.
TemplateInfo::UncacheTemplateInstantiation(
isolate, native_context, info, TemplateInfo::CachingMode::kUnlimited);
return {};
}
info->set_published(true);
return function;
}
void AddPropertyToPropertyList(Isolate* isolate,
DirectHandle<TemplateInfoWithProperties> info,
base::Vector<DirectHandle<Object>> data) {
Tagged<Object> maybe_list = info->property_list();
DirectHandle<ArrayList> list;
if (IsUndefined(maybe_list, isolate)) {
list = ArrayList::New(isolate, static_cast<int>(data.size()),
AllocationType::kOld);
} else {
list = direct_handle(Cast<ArrayList>(maybe_list), isolate);
}
info->set_number_of_properties(info->number_of_properties() + 1);
for (DirectHandle<Object> value : data) {
if (value.is_null())
value = Cast<Object>(isolate->factory()->undefined_value());
list = ArrayList::Add(isolate, list, value);
}
info->set_property_list(*list);
}
} // namespace
// static
DirectHandle<FunctionTemplateInfo>
ApiNatives::CreateAccessorFunctionTemplateInfo(
Isolate* i_isolate, FunctionCallback callback, int length,
SideEffectType side_effect_type) {
// TODO(v8:5962): move FunctionTemplateNew() from api.cc here.
auto isolate = reinterpret_cast<v8::Isolate*>(i_isolate);
Local<FunctionTemplate> func_template = FunctionTemplate::New(
isolate, callback, v8::Local<Value>{}, v8::Local<v8::Signature>{}, length,
v8::ConstructorBehavior::kThrow, side_effect_type);
return Utils::OpenDirectHandle(*func_template);
}
MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<FunctionTemplateInfo> data,
MaybeDirectHandle<Name> maybe_name) {
InvokeScope invoke_scope(isolate);
return ::v8::internal::InstantiateFunction(isolate, native_context, data,
maybe_name);
}
MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
Isolate* isolate, DirectHandle<FunctionTemplateInfo> data,
MaybeDirectHandle<Name> maybe_name) {
InvokeScope invoke_scope(isolate);
return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
}
MaybeHandle<JSObject> ApiNatives::InstantiateObject(
Isolate* isolate, DirectHandle<ObjectTemplateInfo> data,
DirectHandle<JSReceiver> new_target) {
InvokeScope invoke_scope(isolate);
return ::v8::internal::InstantiateObject(isolate, data, new_target, false);
}
MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
DirectHandle<ObjectTemplateInfo> data) {
Isolate* isolate = data->GetIsolate();
InvokeScope invoke_scope(isolate);
DirectHandle<FunctionTemplateInfo> constructor(
Cast<FunctionTemplateInfo>(data->constructor()), isolate);
DirectHandle<Map> object_map = isolate->factory()->NewContextlessMap(
JS_SPECIAL_API_OBJECT_TYPE,
JSSpecialObject::kHeaderSize +
data->embedder_field_count() * kEmbedderDataSlotSize,
TERMINAL_FAST_ELEMENTS_KIND);
object_map->SetConstructor(*constructor);
object_map->set_is_access_check_needed(true);
object_map->set_may_have_interesting_properties(true);
Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(
object_map, AllocationType::kYoung, DirectHandle<AllocationSite>::null(),
NewJSObjectType::kAPIWrapper);
JSObject::ForceSetPrototype(isolate, object,
isolate->factory()->null_value());
return object;
}
void ApiNatives::AddDataProperty(Isolate* isolate,
DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<Name> name,
DirectHandle<Object> value,
PropertyAttributes attributes) {
PropertyDetails details(PropertyKind::kData, attributes,
PropertyConstness::kMutable);
DirectHandle<Object> data[] = {name, direct_handle(details.AsSmi(), isolate),
value};
AddPropertyToPropertyList(isolate, info, base::VectorOf(data));
}
void ApiNatives::AddDataProperty(Isolate* isolate,
DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<Name> name,
v8::Intrinsic intrinsic,
PropertyAttributes attributes) {
auto value = direct_handle(Smi::FromInt(intrinsic), isolate);
auto intrinsic_marker = isolate->factory()->true_value();
PropertyDetails details(PropertyKind::kData, attributes,
PropertyConstness::kMutable);
DirectHandle<Object> data[] = {
name, intrinsic_marker, direct_handle(details.AsSmi(), isolate), value};
AddPropertyToPropertyList(isolate, info, base::VectorOf(data));
}
void ApiNatives::AddAccessorProperty(
Isolate* isolate, DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<Name> name, DirectHandle<FunctionTemplateInfo> getter,
DirectHandle<FunctionTemplateInfo> setter, PropertyAttributes attributes) {
if (!getter.is_null()) getter->set_published(true);
if (!setter.is_null()) setter->set_published(true);
PropertyDetails details(PropertyKind::kAccessor, attributes,
PropertyConstness::kMutable);
DirectHandle<Object> data[] = {name, direct_handle(details.AsSmi(), isolate),
getter, setter};
AddPropertyToPropertyList(isolate, info, base::VectorOf(data));
}
void ApiNatives::AddNativeDataProperty(
Isolate* isolate, DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<AccessorInfo> property) {
Tagged<Object> maybe_list = info->property_accessors();
DirectHandle<ArrayList> list;
if (IsUndefined(maybe_list, isolate)) {
list = ArrayList::New(isolate, 1, AllocationType::kOld);
} else {
list = direct_handle(Cast<ArrayList>(maybe_list), isolate);
}
list = ArrayList::Add(isolate, list, property);
info->set_property_accessors(*list);
}
Handle<JSFunction> ApiNatives::CreateApiFunction(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<FunctionTemplateInfo> obj, DirectHandle<Object> prototype,
InstanceType type, MaybeDirectHandle<Name> maybe_name) {
RCS_SCOPE(isolate, RuntimeCallCounterId::kCreateApiFunction);
DirectHandle<SharedFunctionInfo> shared =
FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
maybe_name);
// To simplify things, API functions always have shared name.
DCHECK(shared->HasSharedName());
Handle<JSFunction> result =
Factory::JSFunctionBuilder{isolate, shared, native_context}.Build();
if (obj->remove_prototype()) {
DCHECK(prototype.is_null());
DCHECK(result->shared()->IsApiFunction());
DCHECK(!IsConstructor(*result));
DCHECK(!result->has_prototype_slot());
return result;
}
// Down from here is only valid for API functions that can be used as a
// constructor (don't set the "remove prototype" flag).
DCHECK(result->has_prototype_slot());
if (obj->read_only_prototype()) {
result->set_map(isolate,
*isolate->sloppy_function_with_readonly_prototype_map());
}
if (IsTheHole(*prototype, isolate)) {
prototype = isolate->factory()->NewFunctionPrototype(result);
} else if (IsUndefined(obj->GetPrototypeProviderTemplate(), isolate)) {
JSObject::AddProperty(isolate, Cast<JSObject>(prototype),
isolate->factory()->constructor_string(), result,
DONT_ENUM);
}
int embedder_field_count = 0;
bool immutable_proto = false;
if (!IsUndefined(obj->GetInstanceTemplate(), isolate)) {
DirectHandle<ObjectTemplateInfo> GetInstanceTemplate(
Cast<ObjectTemplateInfo>(obj->GetInstanceTemplate()), isolate);
embedder_field_count = GetInstanceTemplate->embedder_field_count();
immutable_proto = GetInstanceTemplate->immutable_proto();
}
// JSFunction requires information about the prototype slot.
DCHECK(!InstanceTypeChecker::IsJSFunction(type));
int instance_size = JSObject::GetHeaderSize(type) +
kEmbedderDataSlotSize * embedder_field_count;
DirectHandle<Map> map = isolate->factory()->NewContextfulMap(
native_context, type, instance_size, TERMINAL_FAST_ELEMENTS_KIND);
// Mark as undetectable if needed.
if (obj->undetectable()) {
// We only allow callable undetectable receivers here, since this whole
// undetectable business is only to support document.all, which is both
// undetectable and callable. If we ever see the need to have an object
// that is undetectable but not callable, we need to update the types.h
// to allow encoding this.
CHECK(!IsUndefined(obj->GetInstanceCallHandler(), isolate));
if (Protectors::IsNoUndetectableObjectsIntact(isolate)) {
Protectors::InvalidateNoUndetectableObjects(isolate);
}
map->set_is_undetectable(true);
}
// Mark as needs_access_check if needed.
if (obj->needs_access_check()) {
map->set_is_access_check_needed(true);
map->set_may_have_interesting_properties(true);
}
// Set interceptor information in the map.
if (!IsUndefined(obj->GetNamedPropertyHandler(), isolate)) {
map->set_has_named_interceptor(true);
map->set_may_have_interesting_properties(true);
}
if (!IsUndefined(obj->GetIndexedPropertyHandler(), isolate)) {
map->set_has_indexed_interceptor(true);
}
// Mark instance as callable in the map.
if (!IsUndefined(obj->GetInstanceCallHandler(), isolate)) {
map->set_is_callable(true);
map->set_is_constructor(!obj->undetectable());
}
if (immutable_proto) map->set_is_immutable_proto(true);
JSFunction::SetInitialMap(isolate, result, map, Cast<JSObject>(prototype));
return result;
}
} // namespace internal
} // namespace v8

79
deps/v8/src/api/api-natives.h vendored Normal file
View File

@ -0,0 +1,79 @@
// Copyright 2015 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_API_API_NATIVES_H_
#define V8_API_API_NATIVES_H_
#include "include/v8-template.h"
#include "src/handles/handles.h"
#include "src/handles/maybe-handles.h"
#include "src/objects/objects.h"
#include "src/objects/property-details.h"
namespace v8 {
namespace internal {
// Forward declarations.
enum InstanceType : uint16_t;
class ObjectTemplateInfo;
class TemplateInfo;
class ApiNatives {
public:
static const int kInitialFunctionCacheSize = 256;
// A convenient internal wrapper around FunctionTemplate::New() for creating
// getter/setter callback function templates.
static DirectHandle<FunctionTemplateInfo> CreateAccessorFunctionTemplateInfo(
Isolate* isolate, FunctionCallback callback, int length,
v8::SideEffectType side_effect_type);
V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> InstantiateFunction(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<FunctionTemplateInfo> data,
MaybeDirectHandle<Name> maybe_name = {});
V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> InstantiateFunction(
Isolate* isolate, DirectHandle<FunctionTemplateInfo> data,
MaybeDirectHandle<Name> maybe_name = {});
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> InstantiateObject(
Isolate* isolate, DirectHandle<ObjectTemplateInfo> data,
DirectHandle<JSReceiver> new_target = {});
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> InstantiateRemoteObject(
DirectHandle<ObjectTemplateInfo> data);
static Handle<JSFunction> CreateApiFunction(
Isolate* isolate, DirectHandle<NativeContext> native_context,
DirectHandle<FunctionTemplateInfo> obj, DirectHandle<Object> prototype,
InstanceType type, MaybeDirectHandle<Name> name = {});
static void AddDataProperty(Isolate* isolate,
DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<Name> name,
DirectHandle<Object> value,
PropertyAttributes attributes);
static void AddDataProperty(Isolate* isolate,
DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<Name> name, v8::Intrinsic intrinsic,
PropertyAttributes attributes);
static void AddAccessorProperty(Isolate* isolate,
DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<Name> name,
DirectHandle<FunctionTemplateInfo> getter,
DirectHandle<FunctionTemplateInfo> setter,
PropertyAttributes attributes);
static void AddNativeDataProperty(
Isolate* isolate, DirectHandle<TemplateInfoWithProperties> info,
DirectHandle<AccessorInfo> property);
};
} // namespace internal
} // namespace v8
#endif // V8_API_API_NATIVES_H_

12499
deps/v8/src/api/api.cc vendored Normal file

File diff suppressed because it is too large Load Diff

554
deps/v8/src/api/api.h vendored Normal file
View File

@ -0,0 +1,554 @@
// 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.
#ifndef V8_API_API_H_
#define V8_API_API_H_
#include <memory>
#include "include/v8-container.h"
#include "include/v8-external.h"
#include "include/v8-function-callback.h"
#include "include/v8-proxy.h"
#include "include/v8-typed-array.h"
#include "include/v8-wasm.h"
#include "src/base/contextual.h"
#include "src/execution/isolate.h"
#include "src/objects/bigint.h"
#include "src/objects/contexts.h"
#include "src/objects/js-array-buffer.h"
#include "src/objects/js-collection.h"
#include "src/objects/js-generator.h"
#include "src/objects/js-promise.h"
#include "src/objects/js-proxy.h"
#include "src/objects/objects.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/source-text-module.h"
#include "src/objects/templates.h"
#include "src/utils/detachable-vector.h"
namespace v8 {
class DictionaryTemplate;
class Extension;
class Signature;
class Template;
namespace internal {
class JSArrayBufferView;
class JSFinalizationRegistry;
} // namespace internal
namespace debug {
class AccessorPair;
class GeneratorObject;
class ScriptSource;
class Script;
class EphemeronTable;
} // namespace debug
template <typename T, internal::ExternalPointerTag tag>
inline T ToCData(i::Isolate* isolate,
v8::internal::Tagged<v8::internal::Object> obj);
template <internal::ExternalPointerTag tag>
inline v8::internal::Address ToCData(
v8::internal::Isolate* isolate,
v8::internal::Tagged<v8::internal::Object> obj);
template <internal::ExternalPointerTag tag, typename T>
inline v8::internal::DirectHandle<
v8::internal::UnionOf<v8::internal::Smi, v8::internal::Foreign>>
FromCData(v8::internal::Isolate* isolate, T obj);
template <internal::ExternalPointerTag tag>
inline v8::internal::DirectHandle<
v8::internal::UnionOf<v8::internal::Smi, v8::internal::Foreign>>
FromCData(v8::internal::Isolate* isolate, v8::internal::Address obj);
class ApiFunction {
public:
explicit ApiFunction(v8::internal::Address addr) : addr_(addr) {}
v8::internal::Address address() { return addr_; }
private:
v8::internal::Address addr_;
};
class RegisteredExtension {
public:
static void Register(std::unique_ptr<Extension>);
static void UnregisterAll();
Extension* extension() const { return extension_.get(); }
RegisteredExtension* next() const { return next_; }
static RegisteredExtension* first_extension() { return first_extension_; }
private:
explicit RegisteredExtension(Extension*);
explicit RegisteredExtension(std::unique_ptr<Extension>);
std::unique_ptr<Extension> extension_;
RegisteredExtension* next_ = nullptr;
static RegisteredExtension* first_extension_;
};
#define TO_LOCAL_LIST(V) \
V(ToLocal, AccessorPair, debug::AccessorPair) \
V(ToLocal, NativeContext, Context) \
V(ToLocal, Object, Value) \
V(ToLocal, Module, Module) \
V(ToLocal, Name, Name) \
V(ToLocal, String, String) \
V(ToLocal, Symbol, Symbol) \
V(ToLocal, JSRegExp, RegExp) \
V(ToLocal, JSReceiver, Object) \
V(ToLocal, JSObject, Object) \
V(ToLocal, JSFunction, Function) \
V(ToLocal, JSArray, Array) \
V(ToLocal, JSMap, Map) \
V(ToLocal, JSSet, Set) \
V(ToLocal, JSProxy, Proxy) \
V(ToLocal, JSArrayBuffer, ArrayBuffer) \
V(ToLocal, JSArrayBufferView, ArrayBufferView) \
V(ToLocal, JSDataView, DataView) \
V(ToLocal, JSRabGsabDataView, DataView) \
V(ToLocal, JSTypedArray, TypedArray) \
V(ToLocalShared, JSArrayBuffer, SharedArrayBuffer) \
V(ToLocal, FunctionTemplateInfo, FunctionTemplate) \
V(ToLocal, ObjectTemplateInfo, ObjectTemplate) \
V(ToLocal, DictionaryTemplateInfo, DictionaryTemplate) \
V(SignatureToLocal, FunctionTemplateInfo, Signature) \
V(MessageToLocal, Object, Message) \
V(PromiseToLocal, JSObject, Promise) \
V(StackTraceToLocal, StackTraceInfo, StackTrace) \
V(StackFrameToLocal, StackFrameInfo, StackFrame) \
V(NumberToLocal, Object, Number) \
V(IntegerToLocal, Object, Integer) \
V(Uint32ToLocal, Object, Uint32) \
V(ToLocal, BigInt, BigInt) \
V(ExternalToLocal, JSObject, External) \
V(CallableToLocal, JSReceiver, Function) \
V(ToLocalPrimitive, Object, Primitive) \
V(FixedArrayToLocal, FixedArray, FixedArray) \
V(PrimitiveArrayToLocal, FixedArray, PrimitiveArray) \
V(ToLocal, ScriptOrModule, ScriptOrModule) \
IF_WASM(V, ToLocal, WasmMemoryMapDescriptor, WasmMemoryMapDescriptor) \
IF_WASM(V, ToLocal, WasmModuleObject, WasmModuleObject)
#define TO_LOCAL_NAME_LIST(V) \
V(ToLocal) \
V(ToLocalShared) \
V(SignatureToLocal) \
V(MessageToLocal) \
V(PromiseToLocal) \
V(StackTraceToLocal) \
V(StackFrameToLocal) \
V(NumberToLocal) \
V(IntegerToLocal) \
V(Uint32ToLocal) \
V(ExternalToLocal) \
V(CallableToLocal) \
V(ToLocalPrimitive) \
V(FixedArrayToLocal) \
V(PrimitiveArrayToLocal)
#define OPEN_HANDLE_LIST(V) \
V(Template, TemplateInfoWithProperties) \
V(FunctionTemplate, FunctionTemplateInfo) \
V(ObjectTemplate, ObjectTemplateInfo) \
V(DictionaryTemplate, DictionaryTemplateInfo) \
V(Signature, FunctionTemplateInfo) \
V(Data, Object) \
V(Number, Number) \
V(RegExp, JSRegExp) \
V(Object, JSReceiver) \
V(Array, JSArray) \
V(Map, JSMap) \
V(Set, JSSet) \
V(ArrayBuffer, JSArrayBuffer) \
V(ArrayBufferView, JSArrayBufferView) \
V(TypedArray, JSTypedArray) \
V(Uint8Array, JSTypedArray) \
V(Uint8ClampedArray, JSTypedArray) \
V(Int8Array, JSTypedArray) \
V(Uint16Array, JSTypedArray) \
V(Int16Array, JSTypedArray) \
V(Uint32Array, JSTypedArray) \
V(Int32Array, JSTypedArray) \
V(Float16Array, JSTypedArray) \
V(Float32Array, JSTypedArray) \
V(Float64Array, JSTypedArray) \
V(DataView, JSDataViewOrRabGsabDataView) \
V(SharedArrayBuffer, JSArrayBuffer) \
V(Name, Name) \
V(String, String) \
V(Symbol, Symbol) \
V(Script, JSFunction) \
V(UnboundModuleScript, SharedFunctionInfo) \
V(UnboundScript, SharedFunctionInfo) \
V(Module, Module) \
V(Function, JSReceiver) \
V(CompileHintsCollector, Script) \
V(Message, JSMessageObject) \
V(Context, NativeContext) \
V(External, Object) \
V(StackTrace, StackTraceInfo) \
V(StackFrame, StackFrameInfo) \
V(Proxy, JSProxy) \
V(debug::GeneratorObject, JSGeneratorObject) \
V(debug::ScriptSource, HeapObject) \
V(debug::Script, Script) \
V(debug::EphemeronTable, EphemeronHashTable) \
V(debug::AccessorPair, AccessorPair) \
V(Promise, JSPromise) \
V(Primitive, Object) \
V(PrimitiveArray, FixedArray) \
V(BigInt, BigInt) \
V(ScriptOrModule, ScriptOrModule) \
V(FixedArray, FixedArray) \
V(ModuleRequest, ModuleRequest) \
IF_WASM(V, WasmMemoryMapDescriptor, WasmMemoryMapDescriptor) \
IF_WASM(V, WasmMemoryObject, WasmMemoryObject)
class Utils {
public:
static V8_INLINE bool ApiCheck(bool condition, const char* location,
const char* message) {
if (V8_UNLIKELY(!condition)) {
Utils::ReportApiFailure(location, message);
}
return condition;
}
static void ReportOOMFailure(v8::internal::Isolate* isolate,
const char* location, const OOMDetails& details);
// TODO(42203211): It would be nice if we could keep only a version with
// direct handles. But the implicit conversion from handles to direct handles
// combined with the heterogeneous copy constructor for direct handles make
// this ambiguous.
// TODO(42203211): Use C++20 concepts instead of the enable_if trait, when
// they are fully supported in V8.
#define DECLARE_TO_LOCAL(Name) \
template <template <typename> typename HandleType, typename T, \
typename = std::enable_if_t<std::is_convertible_v< \
HandleType<T>, v8::internal::DirectHandle<T>>>> \
static inline auto Name(HandleType<T> obj);
TO_LOCAL_NAME_LIST(DECLARE_TO_LOCAL)
#define DECLARE_TO_LOCAL_TYPED_ARRAY(Type, typeName, TYPE, ctype) \
static inline Local<v8::Type##Array> ToLocal##Type##Array( \
v8::internal::DirectHandle<v8::internal::JSTypedArray> obj);
TYPED_ARRAYS(DECLARE_TO_LOCAL_TYPED_ARRAY)
#define DECLARE_OPEN_HANDLE(From, To) \
static inline v8::internal::Handle<v8::internal::To> OpenHandle( \
const From* that, bool allow_empty_handle = false); \
static inline v8::internal::DirectHandle<v8::internal::To> OpenDirectHandle( \
const From* that, bool allow_empty_handle = false); \
static inline v8::internal::IndirectHandle<v8::internal::To> \
OpenIndirectHandle(const From* that, bool allow_empty_handle = false);
OPEN_HANDLE_LIST(DECLARE_OPEN_HANDLE)
#undef DECLARE_OPEN_HANDLE
#undef DECLARE_TO_LOCAL_TYPED_ARRAY
#undef DECLARE_TO_LOCAL
template <class From, class To>
static inline Local<To> Convert(v8::internal::DirectHandle<From> obj);
template <class T>
static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
const v8::PersistentBase<T>& persistent) {
return v8::internal::Handle<v8::internal::Object>(persistent.slot());
}
template <class T>
static inline v8::internal::DirectHandle<v8::internal::Object> OpenPersistent(
v8::Persistent<T>* persistent) {
return OpenPersistent(*persistent);
}
template <class From, class To>
static inline v8::internal::Handle<To> OpenHandle(v8::Local<From> handle) {
return OpenHandle(*handle);
}
template <class From, class To>
static inline v8::internal::DirectHandle<To> OpenDirectHandle(
v8::Local<From> handle) {
return OpenDirectHandle(*handle);
}
private:
V8_NOINLINE V8_PRESERVE_MOST static void ReportApiFailure(
const char* location, const char* message);
#define DECLARE_TO_LOCAL_PRIVATE(Name, From, To) \
static inline Local<v8::To> Name##_helper( \
v8::internal::DirectHandle<v8::internal::From> obj);
TO_LOCAL_LIST(DECLARE_TO_LOCAL_PRIVATE)
#undef DECLARE_TO_LOCAL_PRIVATE
};
template <class T>
inline v8::Local<T> ToApiHandle(
v8::internal::DirectHandle<v8::internal::Object> obj) {
return Utils::Convert<v8::internal::Object, T>(obj);
}
template <class T>
inline bool ToLocal(v8::internal::MaybeDirectHandle<v8::internal::Object> maybe,
Local<T>* local) {
v8::internal::DirectHandle<v8::internal::Object> handle;
if (maybe.ToHandle(&handle)) {
*local = Utils::Convert<v8::internal::Object, T>(handle);
return true;
}
return false;
}
namespace internal {
class PersistentHandles;
// This class is here in order to be able to declare it a friend of
// HandleScope. Moving these methods to be members of HandleScope would be
// neat in some ways, but it would expose internal implementation details in
// our public header file, which is undesirable.
//
// An isolate has a single instance of this class to hold the current thread's
// data. In multithreaded V8 programs this data is copied in and out of storage
// so that the currently executing thread always has its own copy of this
// data.
class HandleScopeImplementer {
public:
class V8_NODISCARD EnteredContextRewindScope {
public:
explicit EnteredContextRewindScope(HandleScopeImplementer* hsi)
: hsi_(hsi), saved_entered_context_count_(hsi->EnteredContextCount()) {}
~EnteredContextRewindScope() {
DCHECK_LE(saved_entered_context_count_, hsi_->EnteredContextCount());
while (saved_entered_context_count_ < hsi_->EnteredContextCount())
hsi_->LeaveContext();
}
private:
HandleScopeImplementer* hsi_;
size_t saved_entered_context_count_;
};
explicit HandleScopeImplementer(Isolate* isolate)
: isolate_(isolate), spare_(nullptr) {}
~HandleScopeImplementer() { DeleteArray(spare_); }
HandleScopeImplementer(const HandleScopeImplementer&) = delete;
HandleScopeImplementer& operator=(const HandleScopeImplementer&) = delete;
// Threading support for handle data.
static int ArchiveSpacePerThread();
char* RestoreThread(char* from);
char* ArchiveThread(char* to);
void FreeThreadResources();
// Garbage collection support.
V8_EXPORT_PRIVATE void Iterate(v8::internal::RootVisitor* v);
V8_EXPORT_PRIVATE static char* Iterate(v8::internal::RootVisitor* v,
char* data);
inline internal::Address* GetSpareOrNewBlock();
inline void DeleteExtensions(internal::Address* prev_limit);
inline void EnterContext(Tagged<NativeContext> context);
inline void LeaveContext();
inline bool LastEnteredContextWas(Tagged<NativeContext> context);
inline size_t EnteredContextCount() const { return entered_contexts_.size(); }
// Returns the last entered context or an empty handle if no
// contexts have been entered.
inline DirectHandle<NativeContext> LastEnteredContext();
inline void SaveContext(Tagged<Context> context);
inline Tagged<Context> RestoreContext();
inline bool HasSavedContexts();
inline DetachableVector<Address*>* blocks() { return &blocks_; }
Isolate* isolate() const { return isolate_; }
void ReturnBlock(Address* block) {
DCHECK_NOT_NULL(block);
if (spare_ != nullptr) DeleteArray(spare_);
spare_ = block;
}
static const size_t kEnteredContextsOffset;
private:
void ResetAfterArchive() {
blocks_.detach();
entered_contexts_.detach();
saved_contexts_.detach();
spare_ = nullptr;
last_handle_before_persistent_block_.reset();
}
void Free() {
DCHECK(blocks_.empty());
DCHECK(entered_contexts_.empty());
DCHECK(saved_contexts_.empty());
blocks_.free();
entered_contexts_.free();
saved_contexts_.free();
if (spare_ != nullptr) {
DeleteArray(spare_);
spare_ = nullptr;
}
DCHECK(isolate_->thread_local_top()->CallDepthIsZero());
}
void BeginPersistentScope() {
DCHECK(!last_handle_before_persistent_block_.has_value());
last_handle_before_persistent_block_ = isolate()->handle_scope_data()->next;
}
bool HasPersistentScope() const {
return last_handle_before_persistent_block_.has_value();
}
std::unique_ptr<PersistentHandles> DetachPersistent(Address* first_block);
Isolate* isolate_;
DetachableVector<Address*> blocks_;
// Used as a stack to keep track of entered contexts.
DetachableVector<Tagged<NativeContext>> entered_contexts_;
// Used as a stack to keep track of saved contexts.
DetachableVector<Tagged<Context>> saved_contexts_;
Address* spare_;
std::optional<Address*> last_handle_before_persistent_block_;
// This is only used for threading support.
HandleScopeData handle_scope_data_;
void IterateThis(RootVisitor* v);
char* RestoreThreadHelper(char* from);
char* ArchiveThreadHelper(char* to);
friend class HandleScopeImplementerOffsets;
friend class PersistentHandlesScope;
};
const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page
void HandleScopeImplementer::SaveContext(Tagged<Context> context) {
saved_contexts_.push_back(context);
}
Tagged<Context> HandleScopeImplementer::RestoreContext() {
Tagged<Context> last_context = saved_contexts_.back();
saved_contexts_.pop_back();
return last_context;
}
bool HandleScopeImplementer::HasSavedContexts() {
return !saved_contexts_.empty();
}
void HandleScopeImplementer::LeaveContext() {
DCHECK(!entered_contexts_.empty());
entered_contexts_.pop_back();
}
bool HandleScopeImplementer::LastEnteredContextWas(
Tagged<NativeContext> context) {
return !entered_contexts_.empty() && entered_contexts_.back() == context;
}
// If there's a spare block, use it for growing the current scope.
internal::Address* HandleScopeImplementer::GetSpareOrNewBlock() {
internal::Address* block =
(spare_ != nullptr) ? spare_
: NewArray<internal::Address>(kHandleBlockSize);
spare_ = nullptr;
return block;
}
void HandleScopeImplementer::DeleteExtensions(internal::Address* prev_limit) {
while (!blocks_.empty()) {
internal::Address* block_start = blocks_.back();
internal::Address* block_limit = block_start + kHandleBlockSize;
// SealHandleScope may make the prev_limit to point inside the block.
// Cast possibly-unrelated pointers to plain Address before comparing them
// to avoid undefined behavior.
if (reinterpret_cast<Address>(block_start) <
reinterpret_cast<Address>(prev_limit) &&
reinterpret_cast<Address>(prev_limit) <=
reinterpret_cast<Address>(block_limit)) {
#ifdef ENABLE_LOCAL_HANDLE_ZAPPING
internal::HandleScope::ZapRange(prev_limit, block_limit);
#endif
break;
}
blocks_.pop_back();
#ifdef ENABLE_LOCAL_HANDLE_ZAPPING
internal::HandleScope::ZapRange(block_start, block_limit);
#endif
if (spare_ != nullptr) {
DeleteArray(spare_);
}
spare_ = block_start;
}
DCHECK((blocks_.empty() && prev_limit == nullptr) ||
(!blocks_.empty() && prev_limit != nullptr));
}
// This is a wrapper function called from CallApiGetter builtin when profiling
// or side-effect checking is enabled. It's supposed to set up the runtime
// call stats scope and check if the getter has side-effects in case debugger
// enabled the side-effects checking mode.
// It gets additional argument, the AccessorInfo object, via
// IsolateData::api_callback_thunk_argument slot.
void InvokeAccessorGetterCallback(
v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info);
// This is a wrapper function called from CallApiCallback builtin when profiling
// or side-effect checking is enabled. It's supposed to set up the runtime
// call stats scope and check if the callback has side-effects in case debugger
// enabled the side-effects checking mode.
// It gets additional argument, the v8::FunctionCallback address, via
// IsolateData::api_callback_thunk_argument slot.
void InvokeFunctionCallbackGeneric(
const v8::FunctionCallbackInfo<v8::Value>& info);
void InvokeFunctionCallbackOptimized(
const v8::FunctionCallbackInfo<v8::Value>& info);
void InvokeFinalizationRegistryCleanupFromTask(
DirectHandle<NativeContext> native_context,
DirectHandle<JSFinalizationRegistry> finalization_registry);
template <typename T>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
T ConvertDouble(double d);
template <typename T>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
bool ValidateCallbackInfo(const FunctionCallbackInfo<T>& info);
template <typename T>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
bool ValidateCallbackInfo(const PropertyCallbackInfo<T>& info);
#ifdef ENABLE_SLOW_DCHECKS
DECLARE_CONTEXTUAL_VARIABLE_WITH_DEFAULT(StackAllocatedCheck, const bool, true);
#endif
} // namespace internal
} // namespace v8
#endif // V8_API_API_H_