#include "src/objects/js-function.h"
#include <optional>
#include "src/baseline/baseline-batch-compiler.h"
#include "src/codegen/compiler.h"
#include "src/common/globals.h"
#include "src/diagnostics/code-tracer.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate.h"
#include "src/execution/tiering-manager.h"
#include "src/heap/heap-inl.h"
#include "src/ic/ic.h"
#include "src/init/bootstrapper.h"
#include "src/objects/feedback-cell-inl.h"
#include "src/objects/feedback-vector.h"
#include "src/strings/string-builder-inl.h"
#include "src/objects/object-macros.h"
namespace v8::internal {
CodeKinds JSFunction::GetAttachedCodeKinds(IsolateForSandbox isolate) const {
const CodeKind kind = code(isolate)->kind();
if (!CodeKindIsJSFunction(kind)) return {};
if (CodeKindIsOptimizedJSFunction(kind) &&
code(isolate)->marked_for_deoptimization()) {
return {};
}
return CodeKindToCodeKindFlag(kind);
}
CodeKinds JSFunction::GetAvailableCodeKinds(IsolateForSandbox isolate) const {
CodeKinds result = GetAttachedCodeKinds(isolate);
if ((result & CodeKindFlag::INTERPRETED_FUNCTION) == 0) {
if (shared()->HasBytecodeArray()) {
result |= CodeKindFlag::INTERPRETED_FUNCTION;
}
}
if ((result & CodeKindFlag::BASELINE) == 0) {
if (shared()->HasBaselineCode()) {
result |= CodeKindFlag::BASELINE;
}
}
DCHECK_EQ((result & ~kJSFunctionCodeKindsMask), 0);
return result;
}
void JSFunction::TraceOptimizationStatus(const char* format, ...) {
if (!v8_flags.trace_opt_status) return;
Isolate* const isolate = Isolate::Current();
PrintF("[optimization status (");
{
va_list arguments;
va_start(arguments, format);
base::OS::VPrint(format, arguments);
va_end(arguments);
}
PrintF(")");
if (strlen(DebugNameCStr().get()) == 0) {
PrintF(" (anonymous %p)", reinterpret_cast<void*>(ptr()));
} else {
PrintF(" %s", DebugNameCStr().get());
}
if (!has_feedback_vector()) {
PrintF(" !feedback]\n");
return;
}
PrintF(" %s", CodeKindToString(GetActiveTier(isolate).value()));
if (IsMaglevRequested(isolate)) {
PrintF(" ^M");
} else if (IsTurbofanRequested(isolate)) {
PrintF(" ^TF");
}
Tagged<FeedbackVector> feedback = feedback_vector();
Tagged<FeedbackMetadata> metadata = feedback->metadata();
for (int i = 0; i < metadata->slot_count(); i++) {
FeedbackSlot slot(i);
if (metadata->GetKind(slot) == FeedbackSlotKind::kJumpLoop) {
Tagged<MaybeObject> value = feedback->Get(slot);
if (value.IsCleared()) {
PrintF(" .");
} else {
Tagged<Code> code =
Tagged<CodeWrapper>::cast(value.GetHeapObjectAssumeWeak())
->code(isolate);
PrintF(" %i:", code->osr_offset().ToInt());
if (code->kind() == CodeKind::MAGLEV) {
PrintF("m");
} else {
DCHECK_EQ(CodeKind::TURBOFAN_JS, code->kind());
PrintF("t");
}
}
}
}
PrintF("]\n");
}
bool JSFunction::HasAttachedOptimizedCode(IsolateForSandbox isolate) const {
CodeKinds result = GetAttachedCodeKinds(isolate);
return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
}
bool JSFunction::HasAvailableHigherTierCodeThan(IsolateForSandbox isolate,
CodeKind kind) const {
return HasAvailableHigherTierCodeThanWithFilter(isolate, kind,
kJSFunctionCodeKindsMask);
}
bool JSFunction::HasAvailableHigherTierCodeThanWithFilter(
IsolateForSandbox isolate, CodeKind kind, CodeKinds filter_mask) const {
const int kind_as_int_flag = static_cast<int>(CodeKindToCodeKindFlag(kind));
DCHECK(base::bits::IsPowerOfTwo(kind_as_int_flag));
const int mask = kind_as_int_flag | (kind_as_int_flag - 1);
const CodeKinds masked_available_kinds =
GetAvailableCodeKinds(isolate) & filter_mask;
return (masked_available_kinds & static_cast<CodeKinds>(~mask)) != 0;
}
bool JSFunction::HasAvailableOptimizedCode(IsolateForSandbox isolate) const {
CodeKinds result = GetAvailableCodeKinds(isolate);
return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
}
bool JSFunction::HasAttachedCodeKind(IsolateForSandbox isolate,
CodeKind kind) const {
CodeKinds result = GetAttachedCodeKinds(isolate);
return (result & CodeKindToCodeKindFlag(kind)) != 0;
}
bool JSFunction::HasAvailableCodeKind(IsolateForSandbox isolate,
CodeKind kind) const {
CodeKinds result = GetAvailableCodeKinds(isolate);
return (result & CodeKindToCodeKindFlag(kind)) != 0;
}
namespace {
V8_WARN_UNUSED_RESULT bool HighestTierOf(CodeKinds kinds,
CodeKind* highest_tier) {
DCHECK_EQ((kinds & ~kJSFunctionCodeKindsMask), 0);
static_assert(CodeKind::TURBOFAN_JS > CodeKind::INTERPRETED_FUNCTION);
if (kinds == 0) return false;
const int highest_tier_log2 =
31 - base::bits::CountLeadingZeros(static_cast<uint32_t>(kinds));
DCHECK(CodeKindIsJSFunction(static_cast<CodeKind>(highest_tier_log2)));
*highest_tier = static_cast<CodeKind>(highest_tier_log2);
return true;
}
}
std::optional<CodeKind> JSFunction::GetActiveTier(
IsolateForSandbox isolate) const {
#if V8_ENABLE_WEBASSEMBLY
if (shared()->HasAsmWasmData() ||
code(isolate)->builtin_id() == Builtin::kInstantiateAsmJs) {
return {};
}
#endif
CodeKind highest_tier;
if (!HighestTierOf(GetAvailableCodeKinds(isolate), &highest_tier)) return {};
#ifdef DEBUG
CHECK(highest_tier == CodeKind::TURBOFAN_JS ||
highest_tier == CodeKind::BASELINE ||
highest_tier == CodeKind::MAGLEV ||
highest_tier == CodeKind::INTERPRETED_FUNCTION);
if (highest_tier == CodeKind::INTERPRETED_FUNCTION) {
CHECK(code(isolate)->is_interpreter_trampoline_builtin() ||
(CodeKindIsOptimizedJSFunction(code(isolate)->kind()) &&
code(isolate)->marked_for_deoptimization()) ||
(code(isolate)->builtin_id() == Builtin::kCompileLazy &&
shared()->HasBytecodeArray() && !shared()->HasBaselineCode()));
}
#endif
return highest_tier;
}
bool JSFunction::ActiveTierIsIgnition(IsolateForSandbox isolate) const {
return GetActiveTier(isolate) == CodeKind::INTERPRETED_FUNCTION;
}
bool JSFunction::ActiveTierIsBaseline(IsolateForSandbox isolate) const {
return GetActiveTier(isolate) == CodeKind::BASELINE;
}
bool JSFunction::ActiveTierIsMaglev(IsolateForSandbox isolate) const {
return GetActiveTier(isolate) == CodeKind::MAGLEV;
}
bool JSFunction::ActiveTierIsTurbofan(IsolateForSandbox isolate) const {
return GetActiveTier(isolate) == CodeKind::TURBOFAN_JS;
}
bool JSFunction::CanDiscardCompiled(IsolateForSandbox isolate) const {
if (CodeKindIsOptimizedJSFunction(code(isolate)->kind())) return true;
CodeKinds result = GetAvailableCodeKinds(isolate);
return (result & kJSFunctionCodeKindsMask) != 0;
}
DirectHandle<Object> JSFunction::GetFunctionPrototype(
Isolate* isolate, DirectHandle<JSFunction> function) {
if (!function->has_prototype()) {
DisableTemporaryObjectTracking no_temp_tracking(isolate->debug());
DirectHandle<JSObject> proto =
isolate->factory()->NewFunctionPrototype(function);
JSFunction::SetPrototype(isolate, function, proto);
}
return DirectHandle<Object>(function->prototype(), isolate);
}
void JSFunction::RequestOptimization(Isolate* isolate, CodeKind target_kind,
ConcurrencyMode mode) {
if (!isolate->concurrent_recompilation_enabled() ||
isolate->bootstrapper()->IsActive()) {
mode = ConcurrencyMode::kSynchronous;
}
DCHECK(CodeKindIsOptimizedJSFunction(target_kind));
DCHECK(!is_compiled(isolate) || ActiveTierIsIgnition(isolate) ||
ActiveTierIsBaseline(isolate) || ActiveTierIsMaglev(isolate));
DCHECK(!ActiveTierIsTurbofan(isolate));
DCHECK(shared()->HasBytecodeArray());
DCHECK(shared()->allows_lazy_compilation() ||
!shared()->optimization_disabled(target_kind));
if (IsConcurrent(mode)) {
if (tiering_in_progress()) {
if (v8_flags.trace_concurrent_recompilation) {
PrintF(" ** Not marking ");
ShortPrint(*this);
PrintF(" -- already in optimization queue.\n");
}
return;
}
if (v8_flags.trace_concurrent_recompilation) {
PrintF(" ** Marking ");
ShortPrint(*this);
PrintF(" for concurrent %s recompilation.\n",
CodeKindToString(target_kind));
}
}
JSDispatchTable* jdt = IsolateGroup::current()->js_dispatch_table();
switch (target_kind) {
case CodeKind::MAGLEV:
switch (mode) {
case ConcurrencyMode::kConcurrent:
jdt->SetTieringRequest(dispatch_handle(),
TieringBuiltin::kStartMaglevOptimizeJob,
isolate);
break;
case ConcurrencyMode::kSynchronous:
jdt->SetTieringRequest(dispatch_handle(),
TieringBuiltin::kOptimizeMaglevEager, isolate);
break;
}
break;
case CodeKind::TURBOFAN_JS:
switch (mode) {
case ConcurrencyMode::kConcurrent:
jdt->SetTieringRequest(dispatch_handle(),
TieringBuiltin::kStartTurbofanOptimizeJob,
isolate);
break;
case ConcurrencyMode::kSynchronous:
jdt->SetTieringRequest(dispatch_handle(),
TieringBuiltin::kOptimizeTurbofanEager,
isolate);
break;
}
break;
default:
UNREACHABLE();
}
}
void JSFunction::SetInterruptBudget(
Isolate* isolate, BudgetModification kind,
std::optional<CodeKind> override_active_tier) {
int32_t current = raw_feedback_cell()->interrupt_budget();
int32_t new_budget =
TieringManager::InterruptBudgetFor(isolate, *this, override_active_tier);
switch (kind) {
case BudgetModification::kRaise:
new_budget = std::max(current, new_budget);
break;
case BudgetModification::kReduce:
new_budget = std::min(current, new_budget);
break;
case BudgetModification::kReset:
break;
}
raw_feedback_cell()->set_interrupt_budget(new_budget);
}
Maybe<bool> JSFunctionOrBoundFunctionOrWrappedFunction::CopyNameAndLength(
Isolate* isolate,
DirectHandle<JSFunctionOrBoundFunctionOrWrappedFunction> function,
DirectHandle<JSReceiver> target, DirectHandle<String> prefix,
int arg_count) {
DirectHandle<AccessorInfo> function_length_accessor =
isolate->factory()->function_length_accessor();
LookupIterator length_lookup(isolate, target,
isolate->factory()->length_string(), target,
LookupIterator::OWN);
if (!IsJSFunction(*target) ||
length_lookup.state() != LookupIterator::ACCESSOR ||
!length_lookup.GetAccessors().is_identical_to(function_length_accessor)) {
DirectHandle<Object> length(Smi::zero(), isolate);
Maybe<PropertyAttributes> attributes =
JSReceiver::GetPropertyAttributes(&length_lookup);
if (attributes.IsNothing()) return Nothing<bool>();
if (attributes.FromJust() != ABSENT) {
DirectHandle<Object> target_length;
ASSIGN_RETURN_ON_EXCEPTION(isolate, target_length,
Object::GetProperty(&length_lookup));
if (IsNumber(*target_length)) {
length = isolate->factory()->NewNumber(std::max(
0.0,
DoubleToInteger(Object::NumberValue(*target_length)) - arg_count));
}
}
LookupIterator it(isolate, function, isolate->factory()->length_string(),
function);
DCHECK_EQ(LookupIterator::ACCESSOR, it.state());
RETURN_ON_EXCEPTION_VALUE(isolate,
JSObject::DefineOwnPropertyIgnoreAttributes(
&it, length, it.property_attributes()),
Nothing<bool>());
}
DirectHandle<AccessorInfo> function_name_accessor =
isolate->factory()->function_name_accessor();
LookupIterator name_lookup(isolate, target, isolate->factory()->name_string(),
target);
if (!IsJSFunction(*target) ||
name_lookup.state() != LookupIterator::ACCESSOR ||
!name_lookup.GetAccessors().is_identical_to(function_name_accessor) ||
(name_lookup.IsFound() && !name_lookup.HolderIsReceiver())) {
DirectHandle<Object> target_name;
ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
Object::GetProperty(&name_lookup));
DirectHandle<String> name;
if (IsString(*target_name)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, name,
Name::ToFunctionName(isolate, Cast<String>(target_name)));
if (!prefix.is_null()) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, name, isolate->factory()->NewConsString(prefix, name));
}
} else if (prefix.is_null()) {
name = isolate->factory()->empty_string();
} else {
name = prefix;
}
LookupIterator it(isolate, function, isolate->factory()->name_string());
DCHECK_EQ(LookupIterator::ACCESSOR, it.state());
RETURN_ON_EXCEPTION_VALUE(isolate,
JSObject::DefineOwnPropertyIgnoreAttributes(
&it, name, it.property_attributes()),
Nothing<bool>());
}
return Just(true);
}
MaybeHandle<String> JSBoundFunction::GetName(
Isolate* isolate, DirectHandle<JSBoundFunction> function) {
Handle<String> prefix = isolate->factory()->bound__string();
Handle<String> target_name = prefix;
Factory* factory = isolate->factory();
while (IsJSBoundFunction(function->bound_target_function())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
factory->NewConsString(prefix, target_name));
function = direct_handle(
Cast<JSBoundFunction>(function->bound_target_function()), isolate);
}
if (IsJSWrappedFunction(function->bound_target_function())) {
DirectHandle<JSWrappedFunction> target(
Cast<JSWrappedFunction>(function->bound_target_function()), isolate);
Handle<String> name;
ASSIGN_RETURN_ON_EXCEPTION(isolate, name,
JSWrappedFunction::GetName(isolate, target));
return factory->NewConsString(target_name, name);
}
if (IsJSFunction(function->bound_target_function())) {
DirectHandle<JSFunction> target(
Cast<JSFunction>(function->bound_target_function()), isolate);
Handle<String> name = JSFunction::GetName(isolate, target);
return factory->NewConsString(target_name, name);
}
return target_name;
}
Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
DirectHandle<JSBoundFunction> function) {
int nof_bound_arguments = function->bound_arguments()->length();
while (IsJSBoundFunction(function->bound_target_function())) {
function = direct_handle(
Cast<JSBoundFunction>(function->bound_target_function()), isolate);
int length = function->bound_arguments()->length();
if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
nof_bound_arguments += length;
} else {
nof_bound_arguments = Smi::kMaxValue;
}
}
if (IsJSWrappedFunction(function->bound_target_function())) {
DirectHandle<JSWrappedFunction> target(
Cast<JSWrappedFunction>(function->bound_target_function()), isolate);
int target_length = 0;
ASSIGN_RETURN_ON_EXCEPTION(isolate, target_length,
JSWrappedFunction::GetLength(isolate, target));
int length = std::max(0, target_length - nof_bound_arguments);
return Just(length);
}
DirectHandle<JSFunction> target(
Cast<JSFunction>(function->bound_target_function()), isolate);
int target_length = target->length();
int length = std::max(0, target_length - nof_bound_arguments);
return Just(length);
}
DirectHandle<String> JSBoundFunction::ToString(
Isolate* isolate, DirectHandle<JSBoundFunction> function) {
return isolate->factory()->function_native_code_string();
}
MaybeHandle<String> JSWrappedFunction::GetName(
Isolate* isolate, DirectHandle<JSWrappedFunction> function) {
STACK_CHECK(isolate, MaybeHandle<String>());
Factory* factory = isolate->factory();
Handle<String> target_name = factory->empty_string();
DirectHandle<JSReceiver> target(function->wrapped_target_function(), isolate);
if (IsJSBoundFunction(*target)) {
return JSBoundFunction::GetName(
isolate, direct_handle(
Cast<JSBoundFunction>(function->wrapped_target_function()),
isolate));
} else if (IsJSFunction(*target)) {
return JSFunction::GetName(
isolate,
direct_handle(Cast<JSFunction>(function->wrapped_target_function()),
isolate));
}
return target_name;
}
Maybe<int> JSWrappedFunction::GetLength(
Isolate* isolate, DirectHandle<JSWrappedFunction> function) {
STACK_CHECK(isolate, Nothing<int>());
DirectHandle<JSReceiver> target(function->wrapped_target_function(), isolate);
if (IsJSBoundFunction(*target)) {
return JSBoundFunction::GetLength(
isolate, direct_handle(
Cast<JSBoundFunction>(function->wrapped_target_function()),
isolate));
}
return Just(Cast<JSFunction>(target)->length());
}
DirectHandle<String> JSWrappedFunction::ToString(
Isolate* isolate, DirectHandle<JSWrappedFunction> function) {
return isolate->factory()->function_native_code_string();
}
MaybeDirectHandle<Object> JSWrappedFunction::Create(
Isolate* isolate, DirectHandle<NativeContext> creation_context,
DirectHandle<JSReceiver> value) {
DCHECK(IsCallable(*value));
if (IsJSWrappedFunction(*value)) {
auto target_wrapped = Cast<JSWrappedFunction>(value);
value = direct_handle(target_wrapped->wrapped_target_function(), isolate);
}
DirectHandle<JSWrappedFunction> wrapped =
isolate->factory()->NewJSWrappedFunction(creation_context, value);
Maybe<bool> is_abrupt =
JSFunctionOrBoundFunctionOrWrappedFunction::CopyNameAndLength(
isolate, wrapped, value, DirectHandle<String>(), 0);
if (is_abrupt.IsNothing()) {
DCHECK(isolate->has_exception());
DirectHandle<Object> exception(isolate->exception(), isolate);
isolate->clear_exception();
DirectHandle<JSFunction> type_error_function(
creation_context->type_error_function(), isolate);
DirectHandle<String> string =
Object::NoSideEffectsToString(isolate, exception);
THROW_NEW_ERROR(isolate, NewError(type_error_function,
MessageTemplate::kCannotWrap, string));
}
DCHECK(is_abrupt.FromJust());
return wrapped;
}
Handle<String> JSFunction::GetName(Isolate* isolate,
DirectHandle<JSFunction> function) {
if (function->shared()->name_should_print_as_anonymous()) {
return isolate->factory()->anonymous_string();
}
return handle(function->shared()->Name(), isolate);
}
void JSFunction::EnsureClosureFeedbackCellArray(
Isolate* isolate, DirectHandle<JSFunction> function) {
DCHECK(function->shared()->is_compiled());
DCHECK(function->shared()->HasFeedbackMetadata());
#if V8_ENABLE_WEBASSEMBLY
if (function->shared()->HasAsmWasmData()) return;
#endif
DirectHandle<SharedFunctionInfo> shared(function->shared(), isolate);
DCHECK(shared->HasBytecodeArray());
const bool has_closure_feedback_cell_array =
(function->has_closure_feedback_cell_array() ||
function->has_feedback_vector());
if (has_closure_feedback_cell_array) {
return;
}
const bool allocate_new_feedback_cell =
function->raw_feedback_cell() ==
*isolate->factory()->many_closures_cell();
DirectHandle<ClosureFeedbackCellArray> feedback_cell_array =
ClosureFeedbackCellArray::New(isolate, shared);
if (allocate_new_feedback_cell) {
DirectHandle<FeedbackCell> feedback_cell =
isolate->factory()->NewOneClosureCell(feedback_cell_array);
DCHECK_NE(function->dispatch_handle(), kNullJSDispatchHandle);
DCHECK(!function->code(isolate)->is_context_specialized());
feedback_cell->set_dispatch_handle(function->dispatch_handle());
function->set_raw_feedback_cell(*feedback_cell, kReleaseStore);
} else {
function->raw_feedback_cell()->set_value(*feedback_cell_array,
kReleaseStore);
}
function->SetInterruptBudget(isolate, BudgetModification::kReset);
}
void JSFunction::EnsureFeedbackVector(Isolate* isolate,
DirectHandle<JSFunction> function,
IsCompiledScope* compiled_scope) {
CHECK(compiled_scope->is_compiled());
DCHECK(function->shared()->HasFeedbackMetadata());
if (function->has_feedback_vector()) return;
#if V8_ENABLE_WEBASSEMBLY
if (function->shared()->HasAsmWasmData()) return;
#endif
CreateAndAttachFeedbackVector(isolate, function, compiled_scope);
}
void JSFunction::CreateAndAttachFeedbackVector(
Isolate* isolate, DirectHandle<JSFunction> function,
IsCompiledScope* compiled_scope) {
CHECK(compiled_scope->is_compiled());
DCHECK(function->shared()->HasFeedbackMetadata());
DCHECK(!function->has_feedback_vector());
#if V8_ENABLE_WEBASSEMBLY
DCHECK(!function->shared()->HasAsmWasmData());
#endif
DirectHandle<SharedFunctionInfo> shared(function->shared(), isolate);
DCHECK(function->shared()->HasBytecodeArray());
EnsureClosureFeedbackCellArray(isolate, function);
DirectHandle<ClosureFeedbackCellArray> closure_feedback_cell_array(
function->closure_feedback_cell_array(), isolate);
DirectHandle<FeedbackVector> feedback_vector = FeedbackVector::New(
isolate, shared, closure_feedback_cell_array,
direct_handle(function->raw_feedback_cell(isolate), isolate),
compiled_scope);
USE(feedback_vector);
DCHECK(function->raw_feedback_cell() !=
*isolate->factory()->many_closures_cell());
DCHECK_EQ(function->raw_feedback_cell()->value(), *feedback_vector);
function->SetInterruptBudget(isolate, BudgetModification::kRaise);
if (v8_flags.profile_guided_optimization &&
v8_flags.profile_guided_optimization_for_empty_feedback_vector &&
function->feedback_vector()->length() == 0) {
if (function->shared()->cached_tiering_decision() ==
CachedTieringDecision::kEarlyMaglev) {
function->RequestOptimization(isolate, CodeKind::MAGLEV,
ConcurrencyMode::kConcurrent);
} else if (function->shared()->cached_tiering_decision() ==
CachedTieringDecision::kEarlyTurbofan) {
function->RequestOptimization(isolate, CodeKind::TURBOFAN_JS,
ConcurrencyMode::kConcurrent);
}
}
}
void JSFunction::InitializeFeedbackCell(
Isolate* isolate, DirectHandle<JSFunction> function,
IsCompiledScope* is_compiled_scope,
bool reset_budget_for_feedback_allocation) {
#if V8_ENABLE_WEBASSEMBLY
if (function->shared()->HasAsmWasmData()) return;
#endif
if (function->has_feedback_vector()) {
CHECK_EQ(function->feedback_vector()->length(),
function->feedback_vector()->metadata()->slot_count());
return;
}
bool has_closure_feedback_cell_array =
function->has_closure_feedback_cell_array();
if (has_closure_feedback_cell_array) {
CHECK_EQ(
function->closure_feedback_cell_array()->length(),
function->shared()->feedback_metadata()->create_closure_slot_count());
}
const bool needs_feedback_vector =
!v8_flags.lazy_feedback_allocation ||
v8_flags.log_function_events ||
!isolate->is_best_effort_code_coverage() ||
function->shared()->cached_tiering_decision() !=
CachedTieringDecision::kPending;
if (needs_feedback_vector) {
CreateAndAttachFeedbackVector(isolate, function, is_compiled_scope);
} else if (has_closure_feedback_cell_array) {
if (reset_budget_for_feedback_allocation) {
function->SetInterruptBudget(isolate, BudgetModification::kReset);
}
} else {
EnsureClosureFeedbackCellArray(isolate, function);
}
#ifdef V8_ENABLE_SPARKPLUG
if (function->shared()->cached_tiering_decision() !=
CachedTieringDecision::kPending &&
CanCompileWithBaseline(isolate, function->shared()) &&
function->ActiveTierIsIgnition(isolate)) {
if (v8_flags.baseline_batch_compilation) {
isolate->baseline_batch_compiler()->EnqueueFunction(function);
} else {
IsCompiledScope is_compiled_inner_scope(
function->shared()->is_compiled_scope(isolate));
Compiler::CompileBaseline(isolate, function, Compiler::CLEAR_EXCEPTION,
&is_compiled_inner_scope);
}
}
#endif
}
namespace {
void SetInstancePrototype(Isolate* isolate, DirectHandle<JSFunction> function,
DirectHandle<JSReceiver> value) {
if (function->has_initial_map()) {
function->CompleteInobjectSlackTrackingIfActive(isolate);
DirectHandle<Map> initial_map(function->initial_map(), isolate);
if (!isolate->bootstrapper()->IsActive() &&
initial_map->instance_type() == JS_OBJECT_TYPE) {
function->set_prototype_or_initial_map(*value, kReleaseStore);
if (IsJSObjectThatCanBeTrackedAsPrototype(*value)) {
JSObject::OptimizeAsPrototype(Cast<JSObject>(value));
}
} else {
DirectHandle<Map> new_map =
Map::Copy(isolate, initial_map, "SetInstancePrototype");
JSFunction::SetInitialMap(isolate, function, new_map, value);
DCHECK_IMPLIES(!isolate->bootstrapper()->IsActive(),
*function != function->native_context()->array_function());
}
DependentCode::DeoptimizeDependencyGroups(
isolate, *initial_map, DependentCode::kInitialMapChangedGroup);
} else {
function->set_prototype_or_initial_map(*value, kReleaseStore);
if (IsJSObjectThatCanBeTrackedAsPrototype(*value)) {
JSObject::OptimizeAsPrototype(Cast<JSObject>(value));
}
}
}
}
void JSFunction::SetPrototype(Isolate* isolate,
DirectHandle<JSFunction> function,
DirectHandle<Object> value) {
DCHECK(IsConstructor(*function) ||
IsGeneratorFunction(function->shared()->kind()));
DirectHandle<JSReceiver> construct_prototype;
if (!IsJSReceiver(*value)) {
DirectHandle<Map> new_map = Map::Copy(
isolate, direct_handle(function->map(), isolate), "SetPrototype");
DirectHandle<Object> constructor(new_map->GetConstructor(), isolate);
DirectHandle<Tuple2> non_instance_prototype_constructor_tuple =
isolate->factory()->NewTuple2(constructor, value, AllocationType::kOld);
new_map->set_has_non_instance_prototype(true);
new_map->SetConstructor(*non_instance_prototype_constructor_tuple);
JSObject::MigrateToMap(isolate, function, new_map);
FunctionKind kind = function->shared()->kind();
DirectHandle<Context> native_context(function->native_context(), isolate);
construct_prototype = direct_handle(
IsGeneratorFunction(kind)
? IsAsyncFunction(kind)
? native_context->initial_async_generator_prototype()
: native_context->initial_generator_prototype()
: native_context->initial_object_prototype(),
isolate);
} else {
construct_prototype = Cast<JSReceiver>(value);
function->map()->set_has_non_instance_prototype(false);
}
SetInstancePrototype(isolate, function, construct_prototype);
}
void JSFunction::SetInitialMap(Isolate* isolate,
DirectHandle<JSFunction> function,
DirectHandle<Map> map,
DirectHandle<JSPrototype> prototype) {
SetInitialMap(isolate, function, map, prototype, function);
}
void JSFunction::SetInitialMap(Isolate* isolate,
DirectHandle<JSFunction> function,
DirectHandle<Map> map,
DirectHandle<JSPrototype> prototype,
DirectHandle<JSFunction> constructor) {
if (map->prototype() != *prototype) {
Map::SetPrototype(isolate, map, prototype);
}
map->SetConstructor(*constructor);
function->set_prototype_or_initial_map(*map, kReleaseStore);
if (v8_flags.log_maps) {
LOG(isolate,
MapEvent("InitialMap", {}, map, "",
SharedFunctionInfo::DebugName(
isolate, direct_handle(function->shared(), isolate))));
}
}
void JSFunction::EnsureHasInitialMap(Isolate* isolate,
DirectHandle<JSFunction> function) {
DCHECK(function->has_prototype_slot());
DCHECK(IsConstructor(*function) ||
IsResumableFunction(function->shared()->kind()));
if (function->has_initial_map()) return;
int expected_nof_properties =
CalculateExpectedNofProperties(isolate, function);
if (function->has_initial_map()) return;
InstanceType instance_type;
if (IsResumableFunction(function->shared()->kind())) {
instance_type = IsAsyncGeneratorFunction(function->shared()->kind())
? JS_ASYNC_GENERATOR_OBJECT_TYPE
: JS_GENERATOR_OBJECT_TYPE;
} else {
instance_type = JS_OBJECT_TYPE;
}
int instance_size;
int inobject_properties;
CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
&instance_size, &inobject_properties);
DirectHandle<NativeContext> creation_context(function->native_context(),
isolate);
DirectHandle<Map> map = isolate->factory()->NewContextfulMap(
creation_context, instance_type, instance_size,
TERMINAL_FAST_ELEMENTS_KIND, inobject_properties);
DirectHandle<JSPrototype> prototype;
if (function->has_instance_prototype()) {
prototype = direct_handle(function->instance_prototype(), isolate);
map->set_prototype(*prototype);
} else {
prototype = isolate->factory()->NewFunctionPrototype(function);
Map::SetPrototype(isolate, map, prototype);
}
DCHECK(map->has_fast_object_elements());
CHECK(IsJSReceiver(*prototype));
JSFunction::SetInitialMap(isolate, function, map, prototype);
map->StartInobjectSlackTracking();
}
namespace {
#ifdef DEBUG
bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
switch (instance_type) {
case JS_API_OBJECT_TYPE:
case JS_ARRAY_BUFFER_TYPE:
case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE:
case JS_ARRAY_TYPE:
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_DATA_VIEW_TYPE:
case JS_RAB_GSAB_DATA_VIEW_TYPE:
case JS_DATE_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_FUNCTION_TYPE:
case JS_CLASS_CONSTRUCTOR_TYPE:
case JS_PROMISE_CONSTRUCTOR_TYPE:
case JS_REG_EXP_CONSTRUCTOR_TYPE:
case JS_ARRAY_CONSTRUCTOR_TYPE:
case JS_ASYNC_DISPOSABLE_STACK_TYPE:
case JS_SYNC_DISPOSABLE_STACK_TYPE:
#define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype) \
case TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE:
TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTORS_SWITCH)
#undef TYPED_ARRAY_CONSTRUCTORS_SWITCH
case JS_ITERATOR_PROTOTYPE_TYPE:
case JS_MAP_ITERATOR_PROTOTYPE_TYPE:
case JS_OBJECT_PROTOTYPE_TYPE:
case JS_PROMISE_PROTOTYPE_TYPE:
case JS_REG_EXP_PROTOTYPE_TYPE:
case JS_SET_ITERATOR_PROTOTYPE_TYPE:
case JS_SET_PROTOTYPE_TYPE:
case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
case JS_TYPED_ARRAY_PROTOTYPE_TYPE:
#ifdef V8_INTL_SUPPORT
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_DURATION_FORMAT_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:
case JS_PLURAL_RULES_TYPE:
case JS_RELATIVE_TIME_FORMAT_TYPE:
case JS_SEGMENT_ITERATOR_TYPE:
case JS_SEGMENTER_TYPE:
case JS_SEGMENTS_TYPE:
case JS_V8_BREAK_ITERATOR_TYPE:
#endif
case JS_ASYNC_FUNCTION_OBJECT_TYPE:
case JS_ASYNC_GENERATOR_OBJECT_TYPE:
case JS_MAP_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_OBJECT_TYPE:
case JS_ERROR_TYPE:
case JS_FINALIZATION_REGISTRY_TYPE:
case JS_ARGUMENTS_OBJECT_TYPE:
case JS_PROMISE_TYPE:
case JS_REG_EXP_TYPE:
case JS_SET_TYPE:
case JS_SHADOW_REALM_TYPE:
case JS_SPECIAL_API_OBJECT_TYPE:
case JS_TYPED_ARRAY_TYPE:
case JS_PRIMITIVE_WRAPPER_TYPE:
#ifdef V8_TEMPORAL_SUPPORT
case JS_TEMPORAL_DURATION_TYPE:
case JS_TEMPORAL_INSTANT_TYPE:
case JS_TEMPORAL_PLAIN_DATE_TYPE:
case JS_TEMPORAL_PLAIN_DATE_TIME_TYPE:
case JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE:
case JS_TEMPORAL_PLAIN_TIME_TYPE:
case JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE:
case JS_TEMPORAL_ZONED_DATE_TIME_TYPE:
#endif
case JS_WEAK_MAP_TYPE:
case JS_WEAK_REF_TYPE:
case JS_WEAK_SET_TYPE:
#if V8_ENABLE_WEBASSEMBLY
case WASM_GLOBAL_OBJECT_TYPE:
case WASM_INSTANCE_OBJECT_TYPE:
case WASM_MEMORY_OBJECT_TYPE:
case WASM_MODULE_OBJECT_TYPE:
case WASM_TABLE_OBJECT_TYPE:
case WASM_VALUE_OBJECT_TYPE:
#endif
return true;
case BIGINT_TYPE:
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
case BYTECODE_ARRAY_TYPE:
case BYTE_ARRAY_TYPE:
case CELL_TYPE:
case INSTRUCTION_STREAM_TYPE:
case FILLER_TYPE:
case FIXED_ARRAY_TYPE:
case SCRIPT_CONTEXT_TABLE_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
case FEEDBACK_METADATA_TYPE:
case FOREIGN_TYPE:
case FREE_SPACE_TYPE:
case HASH_TABLE_TYPE:
case ORDERED_HASH_MAP_TYPE:
case ORDERED_HASH_SET_TYPE:
case ORDERED_NAME_DICTIONARY_TYPE:
case NAME_DICTIONARY_TYPE:
case GLOBAL_DICTIONARY_TYPE:
case NUMBER_DICTIONARY_TYPE:
case SIMPLE_NUMBER_DICTIONARY_TYPE:
case HEAP_NUMBER_TYPE:
case JS_BOUND_FUNCTION_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
case JS_GLOBAL_PROXY_TYPE:
case JS_PROXY_TYPE:
case JS_WRAPPED_FUNCTION_TYPE:
case MAP_TYPE:
case ODDBALL_TYPE:
case PROPERTY_CELL_TYPE:
case CONTEXT_CELL_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
case SYMBOL_TYPE:
case ALLOCATION_SITE_TYPE:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case FIXED_##TYPE##_ARRAY_TYPE:
#undef TYPED_ARRAY_CASE
#define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
STRUCT_LIST(MAKE_STRUCT_CASE)
#undef MAKE_STRUCT_CASE
UNREACHABLE();
default:
if (InstanceTypeChecker::IsJSApiObject(instance_type)) return true;
return false;
}
}
#endif
bool FastInitializeDerivedMap(Isolate* isolate,
DirectHandle<JSFunction> new_target,
DirectHandle<JSFunction> constructor,
DirectHandle<Map> constructor_initial_map) {
if (!new_target->has_prototype_slot()) return false;
if (new_target->has_initial_map() &&
new_target->initial_map()->GetConstructor() == *constructor) {
DCHECK(IsJSReceiver(new_target->instance_prototype()));
return true;
}
InstanceType instance_type = constructor_initial_map->instance_type();
DCHECK(CanSubclassHaveInobjectProperties(instance_type));
if (!IsDerivedConstructor(new_target->shared()->kind())) return false;
int instance_size;
int in_object_properties;
int embedder_fields =
JSObject::GetEmbedderFieldCount(*constructor_initial_map);
int expected_nof_properties = std::max(
static_cast<int>(constructor->shared()->expected_nof_properties()),
JSFunction::CalculateExpectedNofProperties(isolate, new_target));
JSFunction::CalculateInstanceSizeHelper(
instance_type, constructor_initial_map->has_prototype_slot(),
embedder_fields, expected_nof_properties, &instance_size,
&in_object_properties);
int pre_allocated = constructor_initial_map->GetInObjectProperties() -
constructor_initial_map->UnusedPropertyFields();
CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
int unused_property_fields = in_object_properties - pre_allocated;
DirectHandle<Map> map =
Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
in_object_properties, unused_property_fields);
map->set_new_target_is_base(false);
DirectHandle<JSPrototype> prototype(new_target->instance_prototype(),
isolate);
JSFunction::SetInitialMap(isolate, new_target, map, prototype, constructor);
DCHECK(IsJSReceiver(new_target->instance_prototype()));
map->set_construction_counter(Map::kNoSlackTracking);
map->StartInobjectSlackTracking();
return true;
}
}
MaybeHandle<Map> JSFunction::GetDerivedMap(
Isolate* isolate, DirectHandle<JSFunction> constructor,
DirectHandle<JSReceiver> new_target) {
EnsureHasInitialMap(isolate, constructor);
DirectHandle<Map> constructor_initial_map(constructor->initial_map(),
isolate);
if (*new_target == *constructor) {
return indirect_handle(constructor_initial_map, isolate);
}
DirectHandle<Map> result_map;
InstanceType new_target_instance_type = new_target->map()->instance_type();
if (InstanceTypeChecker::IsJSFunction(new_target_instance_type)) {
DirectHandle<JSFunction> function = Cast<JSFunction>(new_target);
if (FastInitializeDerivedMap(isolate, function, constructor,
constructor_initial_map)) {
return handle(function->initial_map(), isolate);
}
}
DirectHandle<Object> prototype;
if (InstanceTypeChecker::IsJSFunction(new_target_instance_type) &&
Cast<JSFunction>(new_target)->has_prototype_slot()) {
DirectHandle<JSFunction> function = Cast<JSFunction>(new_target);
EnsureHasInitialMap(isolate, function);
prototype = direct_handle(function->prototype(), isolate);
} else {
DirectHandle<String> prototype_string =
isolate->factory()->prototype_string();
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype,
JSReceiver::GetProperty(isolate, new_target, prototype_string));
EnsureHasInitialMap(isolate, constructor);
constructor_initial_map =
direct_handle(constructor->initial_map(), isolate);
}
if (!IsJSReceiver(*prototype)) {
DirectHandle<NativeContext> native_context;
ASSIGN_RETURN_ON_EXCEPTION(isolate, native_context,
JSReceiver::GetFunctionRealm(new_target));
DirectHandle<Object> maybe_index = JSReceiver::GetDataProperty(
isolate, constructor,
isolate->factory()->native_context_index_symbol());
int index = IsSmi(*maybe_index) ? Smi::ToInt(*maybe_index)
: Context::OBJECT_FUNCTION_INDEX;
DirectHandle<JSFunction> realm_constructor(
Cast<JSFunction>(native_context->GetNoCell(index)), isolate);
prototype = direct_handle(realm_constructor->prototype(), isolate);
}
DCHECK_EQ(constructor_initial_map->constructor_or_back_pointer(),
*constructor);
return Map::GetDerivedMap(isolate, constructor_initial_map,
Cast<JSReceiver>(prototype));
}
namespace {
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
static_assert(Context::TYPE##_ARRAY_FUN_INDEX == \
Context::FIRST_FIXED_TYPED_ARRAY_FUN_INDEX + \
ElementsKind::TYPE##_ELEMENTS - \
ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); \
static_assert(Context::RAB_GSAB_##TYPE##_ARRAY_MAP_INDEX == \
Context::FIRST_RAB_GSAB_TYPED_ARRAY_MAP_INDEX + \
ElementsKind::TYPE##_ELEMENTS - \
ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
int TypedArrayElementsKindToConstructorIndex(ElementsKind elements_kind) {
return Context::FIRST_FIXED_TYPED_ARRAY_FUN_INDEX + elements_kind -
ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
}
int TypedArrayElementsKindToRabGsabCtorIndex(ElementsKind elements_kind) {
return Context::FIRST_RAB_GSAB_TYPED_ARRAY_MAP_INDEX + elements_kind -
ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
}
}
MaybeDirectHandle<Map> JSFunction::GetDerivedRabGsabTypedArrayMap(
Isolate* isolate, DirectHandle<JSFunction> constructor,
DirectHandle<JSReceiver> new_target) {
MaybeDirectHandle<Map> maybe_map =
GetDerivedMap(isolate, constructor, new_target);
DirectHandle<Map> map;
if (!maybe_map.ToHandle(&map)) return {};
{
DisallowHeapAllocation no_alloc;
Tagged<NativeContext> context = isolate->context()->native_context();
int ctor_index =
TypedArrayElementsKindToConstructorIndex(map->elements_kind());
if (*new_target == context->GetNoCell(ctor_index)) {
ctor_index =
TypedArrayElementsKindToRabGsabCtorIndex(map->elements_kind());
return direct_handle(Cast<Map>(context->GetNoCell(ctor_index)), isolate);
}
}
DirectHandle<Map> rab_gsab_map = Map::Copy(isolate, map, "RAB / GSAB");
rab_gsab_map->set_elements_kind(
GetCorrespondingRabGsabElementsKind(map->elements_kind()));
return rab_gsab_map;
}
MaybeDirectHandle<Map> JSFunction::GetDerivedRabGsabDataViewMap(
Isolate* isolate, DirectHandle<JSReceiver> new_target) {
DirectHandle<Context> context(isolate->context()->native_context(), isolate);
DirectHandle<JSFunction> constructor(context->data_view_fun(), isolate);
MaybeDirectHandle<Map> maybe_map =
GetDerivedMap(isolate, constructor, new_target);
DirectHandle<Map> map;
if (!maybe_map.ToHandle(&map)) return {};
if (*map == constructor->initial_map()) {
return direct_handle(Cast<Map>(context->js_rab_gsab_data_view_map()),
isolate);
}
DirectHandle<Map> rab_gsab_map = Map::Copy(isolate, map, "RAB / GSAB");
rab_gsab_map->set_instance_type(JS_RAB_GSAB_DATA_VIEW_TYPE);
return rab_gsab_map;
}
int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
CHECK(has_initial_map());
if (initial_map()->IsInobjectSlackTrackingInProgress()) {
int slack = initial_map()->ComputeMinObjectSlack(isolate);
return initial_map()->InstanceSizeFromSlack(slack);
}
return initial_map()->instance_size();
}
std::unique_ptr<char[]> JSFunction::DebugNameCStr() {
return shared()->DebugNameCStr();
}
void JSFunction::PrintName(FILE* out) {
PrintF(out, "%s", DebugNameCStr().get());
}
namespace {
bool UseFastFunctionNameLookup(Isolate* isolate, Tagged<Map> map) {
DCHECK(IsJSFunctionMap(map));
if (map->NumberOfOwnDescriptors() <
JSFunction::kMinDescriptorsForFastBindAndWrap) {
return false;
}
DCHECK(!map->is_dictionary_map());
Tagged<HeapObject> value;
ReadOnlyRoots roots(isolate);
auto descriptors = map->instance_descriptors(isolate);
InternalIndex kNameIndex{JSFunction::kNameDescriptorIndex};
if (descriptors->GetKey(kNameIndex) != roots.name_string() ||
!descriptors->GetValue(kNameIndex)
.GetHeapObjectIfStrong(isolate, &value)) {
return false;
}
return IsAccessorInfo(value);
}
}
DirectHandle<String> JSFunction::GetDebugName(
Isolate* isolate, DirectHandle<JSFunction> function) {
if (!UseFastFunctionNameLookup(isolate, function->map())) {
DirectHandle<Object> name =
GetDataProperty(isolate, function, isolate->factory()->name_string());
if (IsString(*name)) return Cast<String>(name);
}
return SharedFunctionInfo::DebugName(
isolate, direct_handle(function->shared(), isolate));
}
bool JSFunction::SetName(Isolate* isolate, DirectHandle<JSFunction> function,
DirectHandle<Name> name, DirectHandle<String> prefix) {
DirectHandle<String> function_name;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
Name::ToFunctionName(isolate, name), false);
if (prefix->length() > 0) {
IncrementalStringBuilder builder(isolate);
builder.AppendString(prefix);
builder.AppendCharacter(' ');
builder.AppendString(function_name);
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
false);
}
RETURN_ON_EXCEPTION_VALUE(
isolate,
JSObject::DefinePropertyOrElementIgnoreAttributes(
function, isolate->factory()->name_string(), function_name,
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
false);
return true;
}
namespace {
DirectHandle<String> NativeCodeFunctionSourceString(
Isolate* isolate, DirectHandle<SharedFunctionInfo> shared_info) {
IncrementalStringBuilder builder(isolate);
builder.AppendCStringLiteral("function ");
builder.AppendString(direct_handle(shared_info->Name(), isolate));
builder.AppendCStringLiteral("() { [native code] }");
return builder.Finish().ToHandleChecked();
}
}
DirectHandle<String> JSFunction::ToString(Isolate* isolate,
DirectHandle<JSFunction> function) {
DirectHandle<SharedFunctionInfo> shared_info(function->shared(), isolate);
if (!shared_info->IsUserJavaScript()) {
return NativeCodeFunctionSourceString(isolate, shared_info);
}
if (IsClassConstructor(shared_info->kind())) {
DirectHandle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
isolate, function, isolate->factory()->class_positions_symbol());
if (IsClassPositions(*maybe_class_positions)) {
Tagged<ClassPositions> class_positions =
Cast<ClassPositions>(*maybe_class_positions);
int start_position = class_positions->start();
int end_position = class_positions->end();
Handle<String> script_source(
Cast<String>(Cast<Script>(shared_info->script())->source()), isolate);
return isolate->factory()->NewSubString(script_source, start_position,
end_position);
}
}
if (!shared_info->HasSourceCode()) {
return NativeCodeFunctionSourceString(isolate, shared_info);
}
#if V8_ENABLE_WEBASSEMBLY
if (shared_info->HasWasmExportedFunctionData(isolate)) {
DirectHandle<WasmExportedFunctionData> function_data(
shared_info->wasm_exported_function_data(), isolate);
const wasm::WasmModule* module = function_data->instance_data()->module();
if (is_asmjs_module(module)) {
std::pair<int, int> offsets =
module->asm_js_offset_information->GetFunctionOffsets(
declared_function_index(module, function_data->function_index()));
Handle<String> source(
Cast<String>(Cast<Script>(shared_info->script())->source()), isolate);
return isolate->factory()->NewSubString(source, offsets.first,
offsets.second);
}
}
#endif
if (shared_info->function_token_position() == kNoSourcePosition) {
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kFunctionTokenOffsetTooLongForToString);
return NativeCodeFunctionSourceString(isolate, shared_info);
}
return Cast<String>(
SharedFunctionInfo::GetSourceCodeHarmony(isolate, shared_info));
}
int JSFunction::CalculateExpectedNofProperties(
Isolate* isolate, DirectHandle<JSFunction> function) {
int expected_nof_properties = 0;
for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
!iter.IsAtEnd(); iter.Advance()) {
DirectHandle<JSReceiver> current =
PrototypeIterator::GetCurrent<JSReceiver>(iter);
if (!IsJSFunction(*current)) break;
DirectHandle<JSFunction> func = Cast<JSFunction>(current);
DirectHandle<SharedFunctionInfo> shared(func->shared(), isolate);
IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
if (is_compiled_scope.is_compiled() ||
Compiler::Compile(isolate, func, Compiler::CLEAR_EXCEPTION,
&is_compiled_scope)) {
DCHECK(shared->is_compiled());
int count = shared->expected_nof_properties();
if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
expected_nof_properties += count;
} else {
return JSObject::kMaxInObjectProperties;
}
} else {
continue;
}
}
if (expected_nof_properties > 0) {
expected_nof_properties += 8;
if (expected_nof_properties > JSObject::kMaxInObjectProperties) {
expected_nof_properties = JSObject::kMaxInObjectProperties;
}
}
return expected_nof_properties;
}
void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
bool has_prototype_slot,
int requested_embedder_fields,
int requested_in_object_properties,
int* instance_size,
int* in_object_properties) {
DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
JSObject::kMaxEmbedderFields);
int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
requested_embedder_fields *= kEmbedderDataSlotSizeInTaggedSlots;
int max_nof_fields =
(JSObject::kMaxInstanceSize - header_size) >> kTaggedSizeLog2;
CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
static_cast<unsigned>(max_nof_fields));
*in_object_properties = std::min(requested_in_object_properties,
max_nof_fields - requested_embedder_fields);
*instance_size =
header_size +
((requested_embedder_fields + *in_object_properties) << kTaggedSizeLog2);
CHECK_EQ(*in_object_properties,
((*instance_size - header_size) >> kTaggedSizeLog2) -
requested_embedder_fields);
CHECK_LE(static_cast<unsigned>(*instance_size),
static_cast<unsigned>(JSObject::kMaxInstanceSize));
}
void JSFunction::ClearAllTypeFeedbackInfoForTesting(Isolate* isolate) {
ResetIfCodeFlushed(isolate);
if (has_feedback_vector()) {
Tagged<FeedbackVector> vector = feedback_vector();
if (vector->ClearAllSlotsForTesting(isolate)) {
IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(),
"ClearAllTypeFeedbackInfoForTesting");
}
}
}
}
#include "src/objects/object-macros-undef.h"