Extract JSFunction code into dedicated files
A small step for a JSFunction, one giant leap for V8. Tbr: clemensb@chromium.org Bug: v8:8888 Change-Id: I968bb819763994ec611cde7e502adea30339a387 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2315979 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Stanton <mvstanton@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#69018}
This commit is contained in:
parent
1a9c73c3c9
commit
9414d53980
46
BUILD.gn
46
BUILD.gn
@ -1004,48 +1004,52 @@ action("postmortem-metadata") {
|
||||
|
||||
# NOSORT
|
||||
sources = [
|
||||
"src/objects/objects.h",
|
||||
"src/objects/objects-inl.h",
|
||||
"src/objects/allocation-site-inl.h",
|
||||
"$target_gen_dir/torque-generated/instance-types-tq.h",
|
||||
"src/objects/allocation-site.h",
|
||||
"src/objects/cell-inl.h",
|
||||
"src/objects/allocation-site-inl.h",
|
||||
"src/objects/cell.h",
|
||||
"src/objects/code-inl.h",
|
||||
"src/objects/cell-inl.h",
|
||||
"src/objects/code.h",
|
||||
"src/objects/code-inl.h",
|
||||
"src/objects/data-handler.h",
|
||||
"src/objects/data-handler-inl.h",
|
||||
"src/objects/descriptor-array.h",
|
||||
"src/objects/descriptor-array-inl.h",
|
||||
"src/objects/feedback-cell.h",
|
||||
"src/objects/feedback-cell-inl.h",
|
||||
"src/objects/fixed-array-inl.h",
|
||||
"src/objects/fixed-array.h",
|
||||
"src/objects/heap-number-inl.h",
|
||||
"src/objects/fixed-array-inl.h",
|
||||
"src/objects/heap-number.h",
|
||||
"src/objects/heap-object-inl.h",
|
||||
"src/objects/heap-number-inl.h",
|
||||
"src/objects/heap-object.h",
|
||||
"src/objects/heap-object-inl.h",
|
||||
"src/objects/instance-type.h",
|
||||
"src/objects/js-array-inl.h",
|
||||
"src/objects/js-array.h",
|
||||
"src/objects/js-array-buffer-inl.h",
|
||||
"src/objects/js-array-buffer.h",
|
||||
"src/objects/js-objects-inl.h",
|
||||
"src/objects/js-array-buffer-inl.h",
|
||||
"src/objects/js-array.h",
|
||||
"src/objects/js-array-inl.h",
|
||||
"src/objects/js-function.cc",
|
||||
"src/objects/js-function.h",
|
||||
"src/objects/js-function-inl.h",
|
||||
"src/objects/js-objects.cc",
|
||||
"src/objects/js-objects.h",
|
||||
"src/objects/js-promise-inl.h",
|
||||
"src/objects/js-objects-inl.h",
|
||||
"src/objects/js-promise.h",
|
||||
"src/objects/js-regexp-inl.h",
|
||||
"src/objects/js-promise-inl.h",
|
||||
"src/objects/js-regexp.cc",
|
||||
"src/objects/js-regexp.h",
|
||||
"src/objects/js-regexp-string-iterator-inl.h",
|
||||
"src/objects/js-regexp-inl.h",
|
||||
"src/objects/js-regexp-string-iterator.h",
|
||||
"src/objects/map.h",
|
||||
"src/objects/js-regexp-string-iterator-inl.h",
|
||||
"src/objects/map.cc",
|
||||
"src/objects/map.h",
|
||||
"src/objects/map-inl.h",
|
||||
"src/objects/js-objects.cc",
|
||||
"src/objects/name.h",
|
||||
"src/objects/name-inl.h",
|
||||
"src/objects/oddball-inl.h",
|
||||
"src/objects/objects.h",
|
||||
"src/objects/objects-inl.h",
|
||||
"src/objects/oddball.h",
|
||||
"src/objects/oddball-inl.h",
|
||||
"src/objects/primitive-heap-object.h",
|
||||
"src/objects/primitive-heap-object-inl.h",
|
||||
"src/objects/scope-info.h",
|
||||
@ -1055,13 +1059,12 @@ action("postmortem-metadata") {
|
||||
"src/objects/shared-function-info.h",
|
||||
"src/objects/shared-function-info-inl.h",
|
||||
"src/objects/string.cc",
|
||||
"src/objects/string.h",
|
||||
"src/objects/string-comparator.cc",
|
||||
"src/objects/string-comparator.h",
|
||||
"src/objects/string.h",
|
||||
"src/objects/string-inl.h",
|
||||
"src/objects/struct.h",
|
||||
"src/objects/struct-inl.h",
|
||||
"$target_gen_dir/torque-generated/instance-types-tq.h",
|
||||
]
|
||||
|
||||
outputs = [ "$target_gen_dir/debug-support.cc" ]
|
||||
@ -2822,6 +2825,9 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/objects/js-display-names-inl.h",
|
||||
"src/objects/js-display-names.cc",
|
||||
"src/objects/js-display-names.h",
|
||||
"src/objects/js-function-inl.h",
|
||||
"src/objects/js-function.cc",
|
||||
"src/objects/js-function.h",
|
||||
"src/objects/js-generator-inl.h",
|
||||
"src/objects/js-generator.h",
|
||||
"src/objects/js-list-format-inl.h",
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include 'src/objects/bigint.h'
|
||||
#include 'src/objects/elements-kind.h'
|
||||
#include 'src/objects/free-space.h'
|
||||
#include 'src/objects/js-function.h'
|
||||
#include 'src/objects/js-generator.h'
|
||||
#include 'src/objects/js-promise.h'
|
||||
#include 'src/objects/js-regexp-string-iterator.h'
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "src/compiler/code-assembler.h"
|
||||
#include "src/objects/arguments.h"
|
||||
#include "src/objects/bigint.h"
|
||||
#include "src/objects/js-function.h"
|
||||
#include "src/objects/objects.h"
|
||||
#include "src/objects/promise.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "src/execution/frame-constants.h"
|
||||
#include "src/execution/isolate.h"
|
||||
#include "src/objects/feedback-vector.h"
|
||||
#include "src/objects/js-function.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/utils/allocation.h"
|
||||
#include "src/utils/boxed-float.h"
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/execution/isolate.h"
|
||||
#include "src/objects/cell-inl.h"
|
||||
#include "src/objects/js-function-inl.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/oddball.h"
|
||||
#include "src/objects/property-cell.h"
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "src/objects/contexts.h"
|
||||
#include "src/objects/dictionary-inl.h"
|
||||
#include "src/objects/fixed-array-inl.h"
|
||||
#include "src/objects/js-function-inl.h"
|
||||
#include "src/objects/js-objects-inl.h"
|
||||
#include "src/objects/map-inl.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
|
@ -5,12 +5,12 @@
|
||||
#ifndef V8_OBJECTS_FEEDBACK_VECTOR_INL_H_
|
||||
#define V8_OBJECTS_FEEDBACK_VECTOR_INL_H_
|
||||
|
||||
#include "src/objects/feedback-vector.h"
|
||||
|
||||
#include "src/common/globals.h"
|
||||
#include "src/heap/factory-inl.h"
|
||||
#include "src/heap/heap-write-barrier-inl.h"
|
||||
#include "src/objects/code-inl.h"
|
||||
#include "src/objects/feedback-cell-inl.h"
|
||||
#include "src/objects/feedback-vector.h"
|
||||
#include "src/objects/maybe-object-inl.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/objects/smi.h"
|
||||
|
289
src/objects/js-function-inl.h
Normal file
289
src/objects/js-function-inl.h
Normal file
@ -0,0 +1,289 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_OBJECTS_JS_FUNCTION_INL_H_
|
||||
#define V8_OBJECTS_JS_FUNCTION_INL_H_
|
||||
|
||||
#include "src/diagnostics/code-tracer.h"
|
||||
#include "src/objects/feedback-cell-inl.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSFunctionOrBoundFunction)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSBoundFunction)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSFunction, JSFunctionOrBoundFunction)
|
||||
|
||||
CAST_ACCESSOR(JSFunction)
|
||||
|
||||
ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset)
|
||||
|
||||
FeedbackVector JSFunction::feedback_vector() const {
|
||||
DCHECK(has_feedback_vector());
|
||||
return FeedbackVector::cast(raw_feedback_cell().value());
|
||||
}
|
||||
|
||||
ClosureFeedbackCellArray JSFunction::closure_feedback_cell_array() const {
|
||||
DCHECK(has_closure_feedback_cell_array());
|
||||
return ClosureFeedbackCellArray::cast(raw_feedback_cell().value());
|
||||
}
|
||||
|
||||
// Code objects that are marked for deoptimization are not considered to be
|
||||
// optimized. This is because the JSFunction might have been already
|
||||
// deoptimized but its code() still needs to be unlinked, which will happen on
|
||||
// its next activation.
|
||||
// TODO(jupvfranco): rename this function. Maybe RunOptimizedCode,
|
||||
// or IsValidOptimizedCode.
|
||||
bool JSFunction::IsOptimized() {
|
||||
return is_compiled() && code().kind() == Code::OPTIMIZED_FUNCTION &&
|
||||
!code().marked_for_deoptimization();
|
||||
}
|
||||
|
||||
bool JSFunction::HasOptimizedCode() {
|
||||
return IsOptimized() ||
|
||||
(has_feedback_vector() && feedback_vector().has_optimized_code() &&
|
||||
!feedback_vector().optimized_code().marked_for_deoptimization());
|
||||
}
|
||||
|
||||
bool JSFunction::HasOptimizationMarker() {
|
||||
return has_feedback_vector() && feedback_vector().has_optimization_marker();
|
||||
}
|
||||
|
||||
void JSFunction::ClearOptimizationMarker() {
|
||||
DCHECK(has_feedback_vector());
|
||||
feedback_vector().ClearOptimizationMarker();
|
||||
}
|
||||
|
||||
// Optimized code marked for deoptimization will tier back down to running
|
||||
// interpreted on its next activation, and already doesn't count as IsOptimized.
|
||||
bool JSFunction::IsInterpreted() {
|
||||
return is_compiled() && (code().is_interpreter_trampoline_builtin() ||
|
||||
(code().kind() == Code::OPTIMIZED_FUNCTION &&
|
||||
code().marked_for_deoptimization()));
|
||||
}
|
||||
|
||||
bool JSFunction::ChecksOptimizationMarker() {
|
||||
return code().checks_optimization_marker();
|
||||
}
|
||||
|
||||
bool JSFunction::IsMarkedForOptimization() {
|
||||
return has_feedback_vector() && feedback_vector().optimization_marker() ==
|
||||
OptimizationMarker::kCompileOptimized;
|
||||
}
|
||||
|
||||
bool JSFunction::IsMarkedForConcurrentOptimization() {
|
||||
return has_feedback_vector() &&
|
||||
feedback_vector().optimization_marker() ==
|
||||
OptimizationMarker::kCompileOptimizedConcurrent;
|
||||
}
|
||||
|
||||
bool JSFunction::IsInOptimizationQueue() {
|
||||
return has_feedback_vector() && feedback_vector().optimization_marker() ==
|
||||
OptimizationMarker::kInOptimizationQueue;
|
||||
}
|
||||
|
||||
void JSFunction::CompleteInobjectSlackTrackingIfActive() {
|
||||
if (!has_prototype_slot()) return;
|
||||
if (has_initial_map() && initial_map().IsInobjectSlackTrackingInProgress()) {
|
||||
initial_map().CompleteInobjectSlackTracking(GetIsolate());
|
||||
}
|
||||
}
|
||||
|
||||
AbstractCode JSFunction::abstract_code() {
|
||||
if (IsInterpreted()) {
|
||||
return AbstractCode::cast(shared().GetBytecodeArray());
|
||||
} else {
|
||||
return AbstractCode::cast(code());
|
||||
}
|
||||
}
|
||||
|
||||
int JSFunction::length() { return shared().length(); }
|
||||
|
||||
Code JSFunction::code() const {
|
||||
return Code::cast(RELAXED_READ_FIELD(*this, kCodeOffset));
|
||||
}
|
||||
|
||||
void JSFunction::set_code(Code value) {
|
||||
DCHECK(!ObjectInYoungGeneration(value));
|
||||
RELAXED_WRITE_FIELD(*this, kCodeOffset, value);
|
||||
#ifndef V8_DISABLE_WRITE_BARRIERS
|
||||
WriteBarrier::Marking(*this, RawField(kCodeOffset), value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void JSFunction::set_code_no_write_barrier(Code value) {
|
||||
DCHECK(!ObjectInYoungGeneration(value));
|
||||
RELAXED_WRITE_FIELD(*this, kCodeOffset, value);
|
||||
}
|
||||
|
||||
// TODO(ishell): Why relaxed read but release store?
|
||||
DEF_GETTER(JSFunction, shared, SharedFunctionInfo) {
|
||||
return SharedFunctionInfo::cast(
|
||||
RELAXED_READ_FIELD(*this, kSharedFunctionInfoOffset));
|
||||
}
|
||||
|
||||
void JSFunction::set_shared(SharedFunctionInfo value, WriteBarrierMode mode) {
|
||||
// Release semantics to support acquire read in NeedsResetDueToFlushedBytecode
|
||||
RELEASE_WRITE_FIELD(*this, kSharedFunctionInfoOffset, value);
|
||||
CONDITIONAL_WRITE_BARRIER(*this, kSharedFunctionInfoOffset, value, mode);
|
||||
}
|
||||
|
||||
void JSFunction::ClearOptimizedCodeSlot(const char* reason) {
|
||||
if (has_feedback_vector() && feedback_vector().has_optimized_code()) {
|
||||
if (FLAG_trace_opt) {
|
||||
CodeTracer::Scope scope(GetIsolate()->GetCodeTracer());
|
||||
PrintF(scope.file(),
|
||||
"[evicting entry from optimizing code feedback slot (%s) for ",
|
||||
reason);
|
||||
ShortPrint(scope.file());
|
||||
PrintF(scope.file(), "]\n");
|
||||
}
|
||||
feedback_vector().ClearOptimizedCode();
|
||||
}
|
||||
}
|
||||
|
||||
void JSFunction::SetOptimizationMarker(OptimizationMarker marker) {
|
||||
DCHECK(has_feedback_vector());
|
||||
DCHECK(ChecksOptimizationMarker());
|
||||
DCHECK(!HasOptimizedCode());
|
||||
|
||||
feedback_vector().SetOptimizationMarker(marker);
|
||||
}
|
||||
|
||||
bool JSFunction::has_feedback_vector() const {
|
||||
return shared().is_compiled() &&
|
||||
raw_feedback_cell().value().IsFeedbackVector();
|
||||
}
|
||||
|
||||
bool JSFunction::has_closure_feedback_cell_array() const {
|
||||
return shared().is_compiled() &&
|
||||
raw_feedback_cell().value().IsClosureFeedbackCellArray();
|
||||
}
|
||||
|
||||
Context JSFunction::context() {
|
||||
return TaggedField<Context, kContextOffset>::load(*this);
|
||||
}
|
||||
|
||||
bool JSFunction::has_context() const {
|
||||
return TaggedField<HeapObject, kContextOffset>::load(*this).IsContext();
|
||||
}
|
||||
|
||||
JSGlobalProxy JSFunction::global_proxy() { return context().global_proxy(); }
|
||||
|
||||
NativeContext JSFunction::native_context() {
|
||||
return context().native_context();
|
||||
}
|
||||
|
||||
void JSFunction::set_context(HeapObject value) {
|
||||
DCHECK(value.IsUndefined() || value.IsContext());
|
||||
WRITE_FIELD(*this, kContextOffset, value);
|
||||
WRITE_BARRIER(*this, kContextOffset, value);
|
||||
}
|
||||
|
||||
ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, HeapObject,
|
||||
kPrototypeOrInitialMapOffset, map().has_prototype_slot())
|
||||
|
||||
DEF_GETTER(JSFunction, has_prototype_slot, bool) {
|
||||
return map(isolate).has_prototype_slot();
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, initial_map, Map) {
|
||||
return Map::cast(prototype_or_initial_map(isolate));
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_initial_map, bool) {
|
||||
DCHECK(has_prototype_slot(isolate));
|
||||
return prototype_or_initial_map(isolate).IsMap(isolate);
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_instance_prototype, bool) {
|
||||
DCHECK(has_prototype_slot(isolate));
|
||||
// Can't use ReadOnlyRoots(isolate) as this isolate could be produced by
|
||||
// i::GetIsolateForPtrCompr(HeapObject).
|
||||
return has_initial_map(isolate) ||
|
||||
!prototype_or_initial_map(isolate).IsTheHole(
|
||||
GetReadOnlyRoots(isolate));
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_prototype, bool) {
|
||||
DCHECK(has_prototype_slot(isolate));
|
||||
return map(isolate).has_non_instance_prototype() ||
|
||||
has_instance_prototype(isolate);
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_prototype_property, bool) {
|
||||
return (has_prototype_slot(isolate) && IsConstructor(isolate)) ||
|
||||
IsGeneratorFunction(shared(isolate).kind());
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, PrototypeRequiresRuntimeLookup, bool) {
|
||||
return !has_prototype_property(isolate) ||
|
||||
map(isolate).has_non_instance_prototype();
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, instance_prototype, HeapObject) {
|
||||
DCHECK(has_instance_prototype(isolate));
|
||||
if (has_initial_map(isolate)) return initial_map(isolate).prototype(isolate);
|
||||
// When there is no initial map and the prototype is a JSReceiver, the
|
||||
// initial map field is used for the prototype field.
|
||||
return HeapObject::cast(prototype_or_initial_map(isolate));
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, prototype, Object) {
|
||||
DCHECK(has_prototype(isolate));
|
||||
// If the function's prototype property has been set to a non-JSReceiver
|
||||
// value, that value is stored in the constructor field of the map.
|
||||
if (map(isolate).has_non_instance_prototype()) {
|
||||
Object prototype = map(isolate).GetConstructor(isolate);
|
||||
// The map must have a prototype in that field, not a back pointer.
|
||||
DCHECK(!prototype.IsMap(isolate));
|
||||
DCHECK(!prototype.IsFunctionTemplateInfo(isolate));
|
||||
return prototype;
|
||||
}
|
||||
return instance_prototype(isolate);
|
||||
}
|
||||
|
||||
bool JSFunction::is_compiled() const {
|
||||
return code().builtin_index() != Builtins::kCompileLazy &&
|
||||
shared().is_compiled();
|
||||
}
|
||||
|
||||
bool JSFunction::NeedsResetDueToFlushedBytecode() {
|
||||
// Do a raw read for shared and code fields here since this function may be
|
||||
// called on a concurrent thread and the JSFunction might not be fully
|
||||
// initialized yet.
|
||||
Object maybe_shared = ACQUIRE_READ_FIELD(*this, kSharedFunctionInfoOffset);
|
||||
Object maybe_code = RELAXED_READ_FIELD(*this, kCodeOffset);
|
||||
|
||||
if (!maybe_shared.IsSharedFunctionInfo() || !maybe_code.IsCode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedFunctionInfo shared = SharedFunctionInfo::cast(maybe_shared);
|
||||
Code code = Code::cast(maybe_code);
|
||||
return !shared.is_compiled() &&
|
||||
code.builtin_index() != Builtins::kCompileLazy;
|
||||
}
|
||||
|
||||
void JSFunction::ResetIfBytecodeFlushed(
|
||||
base::Optional<std::function<void(HeapObject object, ObjectSlot slot,
|
||||
HeapObject target)>>
|
||||
gc_notify_updated_slot) {
|
||||
if (FLAG_flush_bytecode && NeedsResetDueToFlushedBytecode()) {
|
||||
// Bytecode was flushed and function is now uncompiled, reset JSFunction
|
||||
// by setting code to CompileLazy and clearing the feedback vector.
|
||||
set_code(GetIsolate()->builtins()->builtin(i::Builtins::kCompileLazy));
|
||||
raw_feedback_cell().reset_feedback_vector(gc_notify_updated_slot);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#include "src/objects/object-macros-undef.h"
|
||||
|
||||
#endif // V8_OBJECTS_JS_FUNCTION_INL_H_
|
822
src/objects/js-function.cc
Normal file
822
src/objects/js-function.cc
Normal file
@ -0,0 +1,822 @@
|
||||
// Copyright 2020 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/objects/js-function.h"
|
||||
|
||||
#include "src/codegen/compiler.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/ic/ic.h"
|
||||
#include "src/init/bootstrapper.h"
|
||||
#include "src/objects/js-function-inl.h"
|
||||
#include "src/strings/string-builder-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// static
|
||||
MaybeHandle<NativeContext> JSBoundFunction::GetFunctionRealm(
|
||||
Handle<JSBoundFunction> function) {
|
||||
DCHECK(function->map().is_constructor());
|
||||
return JSReceiver::GetFunctionRealm(
|
||||
handle(function->bound_target_function(), function->GetIsolate()));
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function) {
|
||||
Handle<String> prefix = isolate->factory()->bound__string();
|
||||
Handle<String> target_name = prefix;
|
||||
Factory* factory = isolate->factory();
|
||||
// Concatenate the "bound " up to the last non-bound target.
|
||||
while (function->bound_target_function().IsJSBoundFunction()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
|
||||
factory->NewConsString(prefix, target_name),
|
||||
String);
|
||||
function = handle(JSBoundFunction::cast(function->bound_target_function()),
|
||||
isolate);
|
||||
}
|
||||
if (function->bound_target_function().IsJSFunction()) {
|
||||
Handle<JSFunction> target(
|
||||
JSFunction::cast(function->bound_target_function()), isolate);
|
||||
Handle<Object> name = JSFunction::GetName(isolate, target);
|
||||
if (!name->IsString()) return target_name;
|
||||
return factory->NewConsString(target_name, Handle<String>::cast(name));
|
||||
}
|
||||
// This will omit the proper target name for bound JSProxies.
|
||||
return target_name;
|
||||
}
|
||||
|
||||
// static
|
||||
Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function) {
|
||||
int nof_bound_arguments = function->bound_arguments().length();
|
||||
while (function->bound_target_function().IsJSBoundFunction()) {
|
||||
function = handle(JSBoundFunction::cast(function->bound_target_function()),
|
||||
isolate);
|
||||
// Make sure we never overflow {nof_bound_arguments}, the number of
|
||||
// arguments of a function is strictly limited by the max length of an
|
||||
// JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
|
||||
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;
|
||||
}
|
||||
}
|
||||
// All non JSFunction targets get a direct property and don't use this
|
||||
// accessor.
|
||||
Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
|
||||
isolate);
|
||||
int target_length = target->length();
|
||||
|
||||
int length = Max(0, target_length - nof_bound_arguments);
|
||||
return Just(length);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
return isolate->factory()->function_native_code_string();
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<Object> JSFunction::GetName(Isolate* isolate,
|
||||
Handle<JSFunction> function) {
|
||||
if (function->shared().name_should_print_as_anonymous()) {
|
||||
return isolate->factory()->anonymous_string();
|
||||
}
|
||||
return handle(function->shared().Name(), isolate);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<NativeContext> JSFunction::GetFunctionRealm(
|
||||
Handle<JSFunction> function) {
|
||||
DCHECK(function->map().is_constructor());
|
||||
return handle(function->context().native_context(), function->GetIsolate());
|
||||
}
|
||||
|
||||
void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
|
||||
Isolate* isolate = GetIsolate();
|
||||
if (!isolate->concurrent_recompilation_enabled() ||
|
||||
isolate->bootstrapper()->IsActive()) {
|
||||
mode = ConcurrencyMode::kNotConcurrent;
|
||||
}
|
||||
|
||||
DCHECK(!is_compiled() || IsInterpreted());
|
||||
DCHECK(shared().IsInterpreted());
|
||||
DCHECK(!IsOptimized());
|
||||
DCHECK(!HasOptimizedCode());
|
||||
DCHECK(shared().allows_lazy_compilation() ||
|
||||
!shared().optimization_disabled());
|
||||
|
||||
if (mode == ConcurrencyMode::kConcurrent) {
|
||||
if (IsInOptimizationQueue()) {
|
||||
if (FLAG_trace_concurrent_recompilation) {
|
||||
PrintF(" ** Not marking ");
|
||||
ShortPrint();
|
||||
PrintF(" -- already in optimization queue.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (FLAG_trace_concurrent_recompilation) {
|
||||
PrintF(" ** Marking ");
|
||||
ShortPrint();
|
||||
PrintF(" for concurrent recompilation.\n");
|
||||
}
|
||||
}
|
||||
|
||||
SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
|
||||
? OptimizationMarker::kCompileOptimizedConcurrent
|
||||
: OptimizationMarker::kCompileOptimized);
|
||||
}
|
||||
|
||||
// static
|
||||
void JSFunction::EnsureClosureFeedbackCellArray(Handle<JSFunction> function) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
DCHECK(function->shared().is_compiled());
|
||||
DCHECK(function->shared().HasFeedbackMetadata());
|
||||
if (function->has_closure_feedback_cell_array() ||
|
||||
function->has_feedback_vector()) {
|
||||
return;
|
||||
}
|
||||
if (function->shared().HasAsmWasmData()) return;
|
||||
|
||||
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
|
||||
DCHECK(function->shared().HasBytecodeArray());
|
||||
Handle<HeapObject> feedback_cell_array =
|
||||
ClosureFeedbackCellArray::New(isolate, shared);
|
||||
// Many closure cell is used as a way to specify that there is no
|
||||
// feedback cell for this function and a new feedback cell has to be
|
||||
// allocated for this funciton. For ex: for eval functions, we have to create
|
||||
// a feedback cell and cache it along with the code. It is safe to use
|
||||
// many_closure_cell to indicate this because in regular cases, it should
|
||||
// already have a feedback_vector / feedback cell array allocated.
|
||||
if (function->raw_feedback_cell() == isolate->heap()->many_closures_cell()) {
|
||||
Handle<FeedbackCell> feedback_cell =
|
||||
isolate->factory()->NewOneClosureCell(feedback_cell_array);
|
||||
function->set_raw_feedback_cell(*feedback_cell);
|
||||
} else {
|
||||
function->raw_feedback_cell().set_value(*feedback_cell_array);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function,
|
||||
IsCompiledScope* is_compiled_scope) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
DCHECK(is_compiled_scope->is_compiled());
|
||||
DCHECK(function->shared().HasFeedbackMetadata());
|
||||
if (function->has_feedback_vector()) return;
|
||||
if (function->shared().HasAsmWasmData()) return;
|
||||
|
||||
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
|
||||
DCHECK(function->shared().HasBytecodeArray());
|
||||
|
||||
EnsureClosureFeedbackCellArray(function);
|
||||
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
|
||||
handle(function->closure_feedback_cell_array(), isolate);
|
||||
Handle<HeapObject> feedback_vector = FeedbackVector::New(
|
||||
isolate, shared, closure_feedback_cell_array, is_compiled_scope);
|
||||
// EnsureClosureFeedbackCellArray should handle the special case where we need
|
||||
// to allocate a new feedback cell. Please look at comment in that function
|
||||
// for more details.
|
||||
DCHECK(function->raw_feedback_cell() !=
|
||||
isolate->heap()->many_closures_cell());
|
||||
function->raw_feedback_cell().set_value(*feedback_vector);
|
||||
function->raw_feedback_cell().SetInterruptBudget();
|
||||
}
|
||||
|
||||
// static
|
||||
void JSFunction::InitializeFeedbackCell(Handle<JSFunction> function,
|
||||
IsCompiledScope* is_compiled_scope) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
|
||||
if (function->has_feedback_vector()) {
|
||||
CHECK_EQ(function->feedback_vector().length(),
|
||||
function->feedback_vector().metadata().slot_count());
|
||||
return;
|
||||
}
|
||||
|
||||
const bool needs_feedback_vector =
|
||||
!FLAG_lazy_feedback_allocation || FLAG_always_opt ||
|
||||
function->shared().may_have_cached_code() ||
|
||||
// We also need a feedback vector for certain log events, collecting type
|
||||
// profile and more precise code coverage.
|
||||
FLAG_log_function_events || !isolate->is_best_effort_code_coverage() ||
|
||||
isolate->is_collecting_type_profile();
|
||||
|
||||
if (needs_feedback_vector) {
|
||||
EnsureFeedbackVector(function, is_compiled_scope);
|
||||
} else {
|
||||
EnsureClosureFeedbackCellArray(function);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
|
||||
Handle<JSReceiver> value) {
|
||||
// Now some logic for the maps of the objects that are created by using this
|
||||
// function as a constructor.
|
||||
if (function->has_initial_map()) {
|
||||
// If the function has allocated the initial map replace it with a
|
||||
// copy containing the new prototype. Also complete any in-object
|
||||
// slack tracking that is in progress at this point because it is
|
||||
// still tracking the old copy.
|
||||
function->CompleteInobjectSlackTrackingIfActive();
|
||||
|
||||
Handle<Map> initial_map(function->initial_map(), isolate);
|
||||
|
||||
if (!isolate->bootstrapper()->IsActive() &&
|
||||
initial_map->instance_type() == JS_OBJECT_TYPE) {
|
||||
// Put the value in the initial map field until an initial map is needed.
|
||||
// At that point, a new initial map is created and the prototype is put
|
||||
// into the initial map where it belongs.
|
||||
function->set_prototype_or_initial_map(*value);
|
||||
} else {
|
||||
Handle<Map> new_map =
|
||||
Map::Copy(isolate, initial_map, "SetInstancePrototype");
|
||||
JSFunction::SetInitialMap(function, new_map, value);
|
||||
|
||||
// If the function is used as the global Array function, cache the
|
||||
// updated initial maps (and transitioned versions) in the native context.
|
||||
Handle<Context> native_context(function->context().native_context(),
|
||||
isolate);
|
||||
Handle<Object> array_function(
|
||||
native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
|
||||
if (array_function->IsJSFunction() &&
|
||||
*function == JSFunction::cast(*array_function)) {
|
||||
CacheInitialJSArrayMaps(isolate, native_context, new_map);
|
||||
}
|
||||
}
|
||||
|
||||
// Deoptimize all code that embeds the previous initial map.
|
||||
initial_map->dependent_code().DeoptimizeDependentCodeGroup(
|
||||
DependentCode::kInitialMapChangedGroup);
|
||||
} else {
|
||||
// Put the value in the initial map field until an initial map is
|
||||
// needed. At that point, a new initial map is created and the
|
||||
// prototype is put into the initial map where it belongs.
|
||||
function->set_prototype_or_initial_map(*value);
|
||||
if (value->IsJSObject()) {
|
||||
// Optimize as prototype to detach it from its transition tree.
|
||||
JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void JSFunction::SetPrototype(Handle<JSFunction> function,
|
||||
Handle<Object> value) {
|
||||
DCHECK(function->IsConstructor() ||
|
||||
IsGeneratorFunction(function->shared().kind()));
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<JSReceiver> construct_prototype;
|
||||
|
||||
// If the value is not a JSReceiver, store the value in the map's
|
||||
// constructor field so it can be accessed. Also, set the prototype
|
||||
// used for constructing objects to the original object prototype.
|
||||
// See ECMA-262 13.2.2.
|
||||
if (!value->IsJSReceiver()) {
|
||||
// Copy the map so this does not affect unrelated functions.
|
||||
// Remove map transitions because they point to maps with a
|
||||
// different prototype.
|
||||
Handle<Map> new_map =
|
||||
Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
|
||||
|
||||
JSObject::MigrateToMap(isolate, function, new_map);
|
||||
new_map->SetConstructor(*value);
|
||||
new_map->set_has_non_instance_prototype(true);
|
||||
|
||||
FunctionKind kind = function->shared().kind();
|
||||
Handle<Context> native_context(function->context().native_context(),
|
||||
isolate);
|
||||
|
||||
construct_prototype = Handle<JSReceiver>(
|
||||
IsGeneratorFunction(kind)
|
||||
? IsAsyncFunction(kind)
|
||||
? native_context->initial_async_generator_prototype()
|
||||
: native_context->initial_generator_prototype()
|
||||
: native_context->initial_object_prototype(),
|
||||
isolate);
|
||||
} else {
|
||||
construct_prototype = Handle<JSReceiver>::cast(value);
|
||||
function->map().set_has_non_instance_prototype(false);
|
||||
}
|
||||
|
||||
SetInstancePrototype(isolate, function, construct_prototype);
|
||||
}
|
||||
|
||||
void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
|
||||
Handle<HeapObject> prototype) {
|
||||
if (map->prototype() != *prototype)
|
||||
Map::SetPrototype(function->GetIsolate(), map, prototype);
|
||||
function->set_prototype_or_initial_map(*map);
|
||||
map->SetConstructor(*function);
|
||||
if (FLAG_trace_maps) {
|
||||
LOG(function->GetIsolate(), MapEvent("InitialMap", Handle<Map>(), map, "",
|
||||
handle(function->shared().DebugName(),
|
||||
function->GetIsolate())));
|
||||
}
|
||||
}
|
||||
|
||||
void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
||||
DCHECK(function->has_prototype_slot());
|
||||
DCHECK(function->IsConstructor() ||
|
||||
IsResumableFunction(function->shared().kind()));
|
||||
if (function->has_initial_map()) return;
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
|
||||
int expected_nof_properties =
|
||||
CalculateExpectedNofProperties(isolate, function);
|
||||
|
||||
// {CalculateExpectedNofProperties} can have had the side effect of creating
|
||||
// the initial map (e.g. it could have triggered an optimized compilation
|
||||
// whose dependency installation reentered {EnsureHasInitialMap}).
|
||||
if (function->has_initial_map()) return;
|
||||
|
||||
// Create a new map with the size and number of in-object properties suggested
|
||||
// by the function.
|
||||
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);
|
||||
|
||||
Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
|
||||
TERMINAL_FAST_ELEMENTS_KIND,
|
||||
inobject_properties);
|
||||
|
||||
// Fetch or allocate prototype.
|
||||
Handle<HeapObject> prototype;
|
||||
if (function->has_instance_prototype()) {
|
||||
prototype = handle(function->instance_prototype(), isolate);
|
||||
} else {
|
||||
prototype = isolate->factory()->NewFunctionPrototype(function);
|
||||
}
|
||||
DCHECK(map->has_fast_object_elements());
|
||||
|
||||
// Finally link initial map and constructor function.
|
||||
DCHECK(prototype->IsJSReceiver());
|
||||
JSFunction::SetInitialMap(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_TYPE:
|
||||
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
|
||||
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
||||
case JS_DATA_VIEW_TYPE:
|
||||
case JS_DATE_TYPE:
|
||||
case JS_FUNCTION_TYPE:
|
||||
case JS_GENERATOR_OBJECT_TYPE:
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
case JS_COLLATOR_TYPE:
|
||||
case JS_DATE_TIME_FORMAT_TYPE:
|
||||
case JS_DISPLAY_NAMES_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_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_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
case JS_PRIMITIVE_WRAPPER_TYPE:
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
case JS_WEAK_REF_TYPE:
|
||||
case JS_WEAK_SET_TYPE:
|
||||
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:
|
||||
return true;
|
||||
|
||||
case BIGINT_TYPE:
|
||||
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
|
||||
case BYTECODE_ARRAY_TYPE:
|
||||
case BYTE_ARRAY_TYPE:
|
||||
case CELL_TYPE:
|
||||
case CODE_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 STRING_TABLE_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 MAP_TYPE:
|
||||
case ODDBALL_TYPE:
|
||||
case PROPERTY_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
|
||||
// We must not end up here for these instance types at all.
|
||||
UNREACHABLE();
|
||||
// Fall through.
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
|
||||
Handle<JSFunction> constructor,
|
||||
Handle<Map> constructor_initial_map) {
|
||||
// Use the default intrinsic prototype instead.
|
||||
if (!new_target->has_prototype_slot()) return false;
|
||||
// Check that |function|'s initial map still in sync with the |constructor|,
|
||||
// otherwise we must create a new initial map for |function|.
|
||||
if (new_target->has_initial_map() &&
|
||||
new_target->initial_map().GetConstructor() == *constructor) {
|
||||
DCHECK(new_target->instance_prototype().IsJSReceiver());
|
||||
return true;
|
||||
}
|
||||
InstanceType instance_type = constructor_initial_map->instance_type();
|
||||
DCHECK(CanSubclassHaveInobjectProperties(instance_type));
|
||||
// Create a new map with the size and number of in-object properties
|
||||
// suggested by |function|.
|
||||
|
||||
// Link initial map and constructor function if the new.target is actually a
|
||||
// subclass constructor.
|
||||
if (!IsDerivedConstructor(new_target->shared().kind())) return false;
|
||||
|
||||
int instance_size;
|
||||
int in_object_properties;
|
||||
int embedder_fields =
|
||||
JSObject::GetEmbedderFieldCount(*constructor_initial_map);
|
||||
// Constructor expects certain number of in-object properties to be in the
|
||||
// object. However, CalculateExpectedNofProperties() may return smaller value
|
||||
// if 1) the constructor is not in the prototype chain of new_target, or
|
||||
// 2) the prototype chain is modified during iteration, or 3) compilation
|
||||
// failure occur during prototype chain iteration.
|
||||
// So we take the maximum of two values.
|
||||
int expected_nof_properties =
|
||||
Max(static_cast<int>(constructor->shared().expected_nof_properties()),
|
||||
JSFunction::CalculateExpectedNofProperties(isolate, new_target));
|
||||
JSFunction::CalculateInstanceSizeHelper(
|
||||
instance_type, true, 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;
|
||||
Handle<Map> map =
|
||||
Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
|
||||
in_object_properties, unused_property_fields);
|
||||
map->set_new_target_is_base(false);
|
||||
Handle<HeapObject> prototype(new_target->instance_prototype(), isolate);
|
||||
JSFunction::SetInitialMap(new_target, map, prototype);
|
||||
DCHECK(new_target->instance_prototype().IsJSReceiver());
|
||||
map->SetConstructor(*constructor);
|
||||
map->set_construction_counter(Map::kNoSlackTracking);
|
||||
map->StartInobjectSlackTracking();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
|
||||
Handle<JSFunction> constructor,
|
||||
Handle<JSReceiver> new_target) {
|
||||
EnsureHasInitialMap(constructor);
|
||||
|
||||
Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
|
||||
if (*new_target == *constructor) return constructor_initial_map;
|
||||
|
||||
Handle<Map> result_map;
|
||||
// Fast case, new.target is a subclass of constructor. The map is cacheable
|
||||
// (and may already have been cached). new.target.prototype is guaranteed to
|
||||
// be a JSReceiver.
|
||||
if (new_target->IsJSFunction()) {
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
|
||||
if (FastInitializeDerivedMap(isolate, function, constructor,
|
||||
constructor_initial_map)) {
|
||||
return handle(function->initial_map(), isolate);
|
||||
}
|
||||
}
|
||||
|
||||
// Slow path, new.target is either a proxy or can't cache the map.
|
||||
// new.target.prototype is not guaranteed to be a JSReceiver, and may need to
|
||||
// fall back to the intrinsicDefaultProto.
|
||||
Handle<Object> prototype;
|
||||
if (new_target->IsJSFunction()) {
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
|
||||
if (function->has_prototype_slot()) {
|
||||
// Make sure the new.target.prototype is cached.
|
||||
EnsureHasInitialMap(function);
|
||||
prototype = handle(function->prototype(), isolate);
|
||||
} else {
|
||||
// No prototype property, use the intrinsict default proto further down.
|
||||
prototype = isolate->factory()->undefined_value();
|
||||
}
|
||||
} else {
|
||||
Handle<String> prototype_string = isolate->factory()->prototype_string();
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, prototype,
|
||||
JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
|
||||
// The above prototype lookup might change the constructor and its
|
||||
// prototype, hence we have to reload the initial map.
|
||||
EnsureHasInitialMap(constructor);
|
||||
constructor_initial_map = handle(constructor->initial_map(), isolate);
|
||||
}
|
||||
|
||||
// If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
|
||||
// correct realm. Rather than directly fetching the .prototype, we fetch the
|
||||
// constructor that points to the .prototype. This relies on
|
||||
// constructor.prototype being FROZEN for those constructors.
|
||||
if (!prototype->IsJSReceiver()) {
|
||||
Handle<Context> context;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
|
||||
JSReceiver::GetFunctionRealm(new_target), Map);
|
||||
DCHECK(context->IsNativeContext());
|
||||
Handle<Object> maybe_index = JSReceiver::GetDataProperty(
|
||||
constructor, isolate->factory()->native_context_index_symbol());
|
||||
int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
|
||||
: Context::OBJECT_FUNCTION_INDEX;
|
||||
Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
|
||||
isolate);
|
||||
prototype = handle(realm_constructor->prototype(), isolate);
|
||||
}
|
||||
|
||||
Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
|
||||
map->set_new_target_is_base(false);
|
||||
CHECK(prototype->IsJSReceiver());
|
||||
if (map->prototype() != *prototype)
|
||||
Map::SetPrototype(isolate, map, Handle<HeapObject>::cast(prototype));
|
||||
map->SetConstructor(*constructor);
|
||||
return 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();
|
||||
}
|
||||
|
||||
void JSFunction::PrintName(FILE* out) {
|
||||
std::unique_ptr<char[]> name = shared().DebugName().ToCString();
|
||||
PrintF(out, "%s", name.get());
|
||||
}
|
||||
|
||||
Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<Object> name =
|
||||
JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
|
||||
if (name->IsString()) return Handle<String>::cast(name);
|
||||
return handle(function->shared().DebugName(), isolate);
|
||||
}
|
||||
|
||||
Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<Object> name = JSReceiver::GetDataProperty(
|
||||
function, isolate->factory()->display_name_string());
|
||||
if (name->IsString()) return Handle<String>::cast(name);
|
||||
return JSFunction::GetName(function);
|
||||
}
|
||||
|
||||
bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
|
||||
Handle<String> prefix) {
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<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 {
|
||||
|
||||
Handle<String> NativeCodeFunctionSourceString(
|
||||
Handle<SharedFunctionInfo> shared_info) {
|
||||
Isolate* const isolate = shared_info->GetIsolate();
|
||||
IncrementalStringBuilder builder(isolate);
|
||||
builder.AppendCString("function ");
|
||||
builder.AppendString(handle(shared_info->Name(), isolate));
|
||||
builder.AppendCString("() { [native code] }");
|
||||
return builder.Finish().ToHandleChecked();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
|
||||
|
||||
// Check if {function} should hide its source code.
|
||||
if (!shared_info->IsUserJavaScript()) {
|
||||
return NativeCodeFunctionSourceString(shared_info);
|
||||
}
|
||||
|
||||
// Check if we should print {function} as a class.
|
||||
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
|
||||
function, isolate->factory()->class_positions_symbol());
|
||||
if (maybe_class_positions->IsClassPositions()) {
|
||||
ClassPositions class_positions =
|
||||
ClassPositions::cast(*maybe_class_positions);
|
||||
int start_position = class_positions.start();
|
||||
int end_position = class_positions.end();
|
||||
Handle<String> script_source(
|
||||
String::cast(Script::cast(shared_info->script()).source()), isolate);
|
||||
return isolate->factory()->NewSubString(script_source, start_position,
|
||||
end_position);
|
||||
}
|
||||
|
||||
// Check if we have source code for the {function}.
|
||||
if (!shared_info->HasSourceCode()) {
|
||||
return NativeCodeFunctionSourceString(shared_info);
|
||||
}
|
||||
|
||||
// If this function was compiled from asm.js, use the recorded offset
|
||||
// information.
|
||||
if (shared_info->HasWasmExportedFunctionData()) {
|
||||
Handle<WasmExportedFunctionData> function_data(
|
||||
shared_info->wasm_exported_function_data(), isolate);
|
||||
const wasm::WasmModule* module = function_data->instance().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(
|
||||
String::cast(Script::cast(shared_info->script()).source()), isolate);
|
||||
return isolate->factory()->NewSubString(source, offsets.first,
|
||||
offsets.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (shared_info->function_token_position() == kNoSourcePosition) {
|
||||
// If the function token position isn't valid, return [native code] to
|
||||
// ensure calling eval on the returned source code throws rather than
|
||||
// giving inconsistent call behaviour.
|
||||
isolate->CountUsage(
|
||||
v8::Isolate::UseCounterFeature::kFunctionTokenOffsetTooLongForToString);
|
||||
return NativeCodeFunctionSourceString(shared_info);
|
||||
}
|
||||
return Handle<String>::cast(
|
||||
SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
|
||||
}
|
||||
|
||||
// static
|
||||
int JSFunction::CalculateExpectedNofProperties(Isolate* isolate,
|
||||
Handle<JSFunction> function) {
|
||||
int expected_nof_properties = 0;
|
||||
for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
|
||||
!iter.IsAtEnd(); iter.Advance()) {
|
||||
Handle<JSReceiver> current =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(iter);
|
||||
if (!current->IsJSFunction()) break;
|
||||
Handle<JSFunction> func = Handle<JSFunction>::cast(current);
|
||||
// The super constructor should be compiled for the number of expected
|
||||
// properties to be available.
|
||||
Handle<SharedFunctionInfo> shared(func->shared(), isolate);
|
||||
IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
|
||||
if (is_compiled_scope.is_compiled() ||
|
||||
Compiler::Compile(func, Compiler::CLEAR_EXCEPTION,
|
||||
&is_compiled_scope)) {
|
||||
DCHECK(shared->is_compiled());
|
||||
int count = shared->expected_nof_properties();
|
||||
// Check that the estimate is sensible.
|
||||
if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
|
||||
expected_nof_properties += count;
|
||||
} else {
|
||||
return JSObject::kMaxInObjectProperties;
|
||||
}
|
||||
} else {
|
||||
// In case there was a compilation error proceed iterating in case there
|
||||
// will be a builtin function in the prototype chain that requires
|
||||
// certain number of in-object properties.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Inobject slack tracking will reclaim redundant inobject space
|
||||
// later, so we can afford to adjust the estimate generously,
|
||||
// meaning we over-allocate by at least 8 slots in the beginning.
|
||||
if (expected_nof_properties > 0) {
|
||||
expected_nof_properties += 8;
|
||||
if (expected_nof_properties > JSObject::kMaxInObjectProperties) {
|
||||
expected_nof_properties = JSObject::kMaxInObjectProperties;
|
||||
}
|
||||
}
|
||||
return expected_nof_properties;
|
||||
}
|
||||
|
||||
// static
|
||||
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);
|
||||
if (requested_embedder_fields) {
|
||||
// If there are embedder fields, then the embedder fields start offset must
|
||||
// be properly aligned (embedder fields are located between object header
|
||||
// and inobject fields).
|
||||
header_size = RoundUp<kSystemPointerSize>(header_size);
|
||||
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 = 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::ClearTypeFeedbackInfo() {
|
||||
ResetIfBytecodeFlushed();
|
||||
if (has_feedback_vector()) {
|
||||
FeedbackVector vector = feedback_vector();
|
||||
Isolate* isolate = GetIsolate();
|
||||
if (vector.ClearSlots(isolate)) {
|
||||
IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(),
|
||||
"ClearTypeFeedbackInfo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
292
src/objects/js-function.h
Normal file
292
src/objects/js-function.h
Normal file
@ -0,0 +1,292 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_OBJECTS_JS_FUNCTION_H_
|
||||
#define V8_OBJECTS_JS_FUNCTION_H_
|
||||
|
||||
#include "src/objects/js-objects.h"
|
||||
#include "torque-generated/class-definitions-tq.h"
|
||||
#include "torque-generated/field-offsets-tq.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// An abstract superclass for classes representing JavaScript function values.
|
||||
// It doesn't carry any functionality but allows function classes to be
|
||||
// identified in the type system.
|
||||
class JSFunctionOrBoundFunction
|
||||
: public TorqueGeneratedJSFunctionOrBoundFunction<JSFunctionOrBoundFunction,
|
||||
JSObject> {
|
||||
public:
|
||||
STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize);
|
||||
TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction)
|
||||
};
|
||||
|
||||
// JSBoundFunction describes a bound function exotic object.
|
||||
class JSBoundFunction
|
||||
: public TorqueGeneratedJSBoundFunction<JSBoundFunction,
|
||||
JSFunctionOrBoundFunction> {
|
||||
public:
|
||||
static MaybeHandle<String> GetName(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function);
|
||||
static Maybe<int> GetLength(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function);
|
||||
static MaybeHandle<NativeContext> GetFunctionRealm(
|
||||
Handle<JSBoundFunction> function);
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_PRINTER(JSBoundFunction)
|
||||
DECL_VERIFIER(JSBoundFunction)
|
||||
|
||||
// The bound function's string representation implemented according
|
||||
// to ES6 section 19.2.3.5 Function.prototype.toString ( ).
|
||||
static Handle<String> ToString(Handle<JSBoundFunction> function);
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(JSBoundFunction)
|
||||
};
|
||||
|
||||
// JSFunction describes JavaScript functions.
|
||||
class JSFunction : public JSFunctionOrBoundFunction {
|
||||
public:
|
||||
// [prototype_or_initial_map]:
|
||||
DECL_ACCESSORS(prototype_or_initial_map, HeapObject)
|
||||
|
||||
// [shared]: The information about the function that
|
||||
// can be shared by instances.
|
||||
DECL_ACCESSORS(shared, SharedFunctionInfo)
|
||||
|
||||
static const int kLengthDescriptorIndex = 0;
|
||||
static const int kNameDescriptorIndex = 1;
|
||||
// Home object descriptor index when function has a [[HomeObject]] slot.
|
||||
static const int kMaybeHomeObjectDescriptorIndex = 2;
|
||||
// Fast binding requires length and name accessors.
|
||||
static const int kMinDescriptorsForFastBind = 2;
|
||||
|
||||
// [context]: The context for this function.
|
||||
inline Context context();
|
||||
inline bool has_context() const;
|
||||
inline void set_context(HeapObject context);
|
||||
inline JSGlobalProxy global_proxy();
|
||||
inline NativeContext native_context();
|
||||
inline int length();
|
||||
|
||||
static Handle<Object> GetName(Isolate* isolate, Handle<JSFunction> function);
|
||||
static Handle<NativeContext> GetFunctionRealm(Handle<JSFunction> function);
|
||||
|
||||
// [code]: The generated code object for this function. Executed
|
||||
// when the function is invoked, e.g. foo() or new foo(). See
|
||||
// [[Call]] and [[Construct]] description in ECMA-262, section
|
||||
// 8.6.2, page 27.
|
||||
inline Code code() const;
|
||||
inline void set_code(Code code);
|
||||
inline void set_code_no_write_barrier(Code code);
|
||||
|
||||
// Get the abstract code associated with the function, which will either be
|
||||
// a Code object or a BytecodeArray.
|
||||
inline AbstractCode abstract_code();
|
||||
|
||||
// Tells whether or not this function is interpreted.
|
||||
//
|
||||
// Note: function->IsInterpreted() does not necessarily return the same value
|
||||
// as function->shared()->IsInterpreted() because the closure might have been
|
||||
// optimized.
|
||||
inline bool IsInterpreted();
|
||||
|
||||
// Tells whether or not this function checks its optimization marker in its
|
||||
// feedback vector.
|
||||
inline bool ChecksOptimizationMarker();
|
||||
|
||||
// Tells whether or not this function holds optimized code.
|
||||
//
|
||||
// Note: Returning false does not necessarily mean that this function hasn't
|
||||
// been optimized, as it may have optimized code on its feedback vector.
|
||||
inline bool IsOptimized();
|
||||
|
||||
// Tells whether or not this function has optimized code available to it,
|
||||
// either because it is optimized or because it has optimized code in its
|
||||
// feedback vector.
|
||||
inline bool HasOptimizedCode();
|
||||
|
||||
// Tells whether or not this function has a (non-zero) optimization marker.
|
||||
inline bool HasOptimizationMarker();
|
||||
|
||||
// Mark this function for lazy recompilation. The function will be recompiled
|
||||
// the next time it is executed.
|
||||
void MarkForOptimization(ConcurrencyMode mode);
|
||||
|
||||
// Tells whether or not the function is already marked for lazy recompilation.
|
||||
inline bool IsMarkedForOptimization();
|
||||
inline bool IsMarkedForConcurrentOptimization();
|
||||
|
||||
// Tells whether or not the function is on the concurrent recompilation queue.
|
||||
inline bool IsInOptimizationQueue();
|
||||
|
||||
// Clears the optimized code slot in the function's feedback vector.
|
||||
inline void ClearOptimizedCodeSlot(const char* reason);
|
||||
|
||||
// Sets the optimization marker in the function's feedback vector.
|
||||
inline void SetOptimizationMarker(OptimizationMarker marker);
|
||||
|
||||
// Clears the optimization marker in the function's feedback vector.
|
||||
inline void ClearOptimizationMarker();
|
||||
|
||||
// If slack tracking is active, it computes instance size of the initial map
|
||||
// with minimum permissible object slack. If it is not active, it simply
|
||||
// returns the initial map's instance size.
|
||||
int ComputeInstanceSizeWithMinSlack(Isolate* isolate);
|
||||
|
||||
// Completes inobject slack tracking on initial map if it is active.
|
||||
inline void CompleteInobjectSlackTrackingIfActive();
|
||||
|
||||
// [raw_feedback_cell]: Gives raw access to the FeedbackCell used to hold the
|
||||
/// FeedbackVector eventually. Generally this shouldn't be used to get the
|
||||
// feedback_vector, instead use feedback_vector() which correctly deals with
|
||||
// the JSFunction's bytecode being flushed.
|
||||
DECL_ACCESSORS(raw_feedback_cell, FeedbackCell)
|
||||
|
||||
// Functions related to feedback vector. feedback_vector() can be used once
|
||||
// the function has feedback vectors allocated. feedback vectors may not be
|
||||
// available after compile when lazily allocating feedback vectors.
|
||||
inline FeedbackVector feedback_vector() const;
|
||||
inline bool has_feedback_vector() const;
|
||||
V8_EXPORT_PRIVATE static void EnsureFeedbackVector(
|
||||
Handle<JSFunction> function, IsCompiledScope* compiled_scope);
|
||||
|
||||
// Functions related to clousre feedback cell array that holds feedback cells
|
||||
// used to create closures from this function. We allocate closure feedback
|
||||
// cell arrays after compile, when we want to allocate feedback vectors
|
||||
// lazily.
|
||||
inline bool has_closure_feedback_cell_array() const;
|
||||
inline ClosureFeedbackCellArray closure_feedback_cell_array() const;
|
||||
static void EnsureClosureFeedbackCellArray(Handle<JSFunction> function);
|
||||
|
||||
// Initializes the feedback cell of |function|. In lite mode, this would be
|
||||
// initialized to the closure feedback cell array that holds the feedback
|
||||
// cells for create closure calls from this function. In the regular mode,
|
||||
// this allocates feedback vector.
|
||||
static void InitializeFeedbackCell(Handle<JSFunction> function,
|
||||
IsCompiledScope* compiled_scope);
|
||||
|
||||
// Unconditionally clear the type feedback vector.
|
||||
void ClearTypeFeedbackInfo();
|
||||
|
||||
// Resets function to clear compiled data after bytecode has been flushed.
|
||||
inline bool NeedsResetDueToFlushedBytecode();
|
||||
inline void ResetIfBytecodeFlushed(
|
||||
base::Optional<std::function<void(HeapObject object, ObjectSlot slot,
|
||||
HeapObject target)>>
|
||||
gc_notify_updated_slot = base::nullopt);
|
||||
|
||||
DECL_GETTER(has_prototype_slot, bool)
|
||||
|
||||
// The initial map for an object created by this constructor.
|
||||
DECL_GETTER(initial_map, Map)
|
||||
|
||||
static void SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
|
||||
Handle<HeapObject> prototype);
|
||||
DECL_GETTER(has_initial_map, bool)
|
||||
V8_EXPORT_PRIVATE static void EnsureHasInitialMap(
|
||||
Handle<JSFunction> function);
|
||||
|
||||
// Creates a map that matches the constructor's initial map, but with
|
||||
// [[prototype]] being new.target.prototype. Because new.target can be a
|
||||
// JSProxy, this can call back into JavaScript.
|
||||
static V8_WARN_UNUSED_RESULT MaybeHandle<Map> GetDerivedMap(
|
||||
Isolate* isolate, Handle<JSFunction> constructor,
|
||||
Handle<JSReceiver> new_target);
|
||||
|
||||
// Get and set the prototype property on a JSFunction. If the
|
||||
// function has an initial map the prototype is set on the initial
|
||||
// map. Otherwise, the prototype is put in the initial map field
|
||||
// until an initial map is needed.
|
||||
DECL_GETTER(has_prototype, bool)
|
||||
DECL_GETTER(has_instance_prototype, bool)
|
||||
DECL_GETTER(prototype, Object)
|
||||
DECL_GETTER(instance_prototype, HeapObject)
|
||||
DECL_GETTER(has_prototype_property, bool)
|
||||
DECL_GETTER(PrototypeRequiresRuntimeLookup, bool)
|
||||
static void SetPrototype(Handle<JSFunction> function, Handle<Object> value);
|
||||
|
||||
// Returns if this function has been compiled to native code yet.
|
||||
inline bool is_compiled() const;
|
||||
|
||||
static int GetHeaderSize(bool function_has_prototype_slot) {
|
||||
return function_has_prototype_slot ? JSFunction::kSizeWithPrototype
|
||||
: JSFunction::kSizeWithoutPrototype;
|
||||
}
|
||||
|
||||
// Prints the name of the function using PrintF.
|
||||
void PrintName(FILE* out = stdout);
|
||||
|
||||
DECL_CAST(JSFunction)
|
||||
|
||||
// Calculate the instance size and in-object properties count.
|
||||
// {CalculateExpectedNofProperties} can trigger compilation.
|
||||
static V8_WARN_UNUSED_RESULT int CalculateExpectedNofProperties(
|
||||
Isolate* isolate, Handle<JSFunction> function);
|
||||
static void CalculateInstanceSizeHelper(InstanceType instance_type,
|
||||
bool has_prototype_slot,
|
||||
int requested_embedder_fields,
|
||||
int requested_in_object_properties,
|
||||
int* instance_size,
|
||||
int* in_object_properties);
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_PRINTER(JSFunction)
|
||||
DECL_VERIFIER(JSFunction)
|
||||
|
||||
// The function's name if it is configured, otherwise shared function info
|
||||
// debug name.
|
||||
static Handle<String> GetName(Handle<JSFunction> function);
|
||||
|
||||
// ES6 section 9.2.11 SetFunctionName
|
||||
// Because of the way this abstract operation is used in the spec,
|
||||
// it should never fail, but in practice it will fail if the generated
|
||||
// function name's length exceeds String::kMaxLength.
|
||||
static V8_WARN_UNUSED_RESULT bool SetName(Handle<JSFunction> function,
|
||||
Handle<Name> name,
|
||||
Handle<String> prefix);
|
||||
|
||||
// The function's displayName if it is set, otherwise name if it is
|
||||
// configured, otherwise shared function info
|
||||
// debug name.
|
||||
static Handle<String> GetDebugName(Handle<JSFunction> function);
|
||||
|
||||
// The function's string representation implemented according to
|
||||
// ES6 section 19.2.3.5 Function.prototype.toString ( ).
|
||||
static Handle<String> ToString(Handle<JSFunction> function);
|
||||
|
||||
struct FieldOffsets {
|
||||
DEFINE_FIELD_OFFSET_CONSTANTS(JSFunctionOrBoundFunction::kHeaderSize,
|
||||
TORQUE_GENERATED_JS_FUNCTION_FIELDS)
|
||||
};
|
||||
static constexpr int kSharedFunctionInfoOffset =
|
||||
FieldOffsets::kSharedFunctionInfoOffset;
|
||||
static constexpr int kContextOffset = FieldOffsets::kContextOffset;
|
||||
static constexpr int kFeedbackCellOffset = FieldOffsets::kFeedbackCellOffset;
|
||||
static constexpr int kCodeOffset = FieldOffsets::kCodeOffset;
|
||||
static constexpr int kPrototypeOrInitialMapOffset =
|
||||
FieldOffsets::kPrototypeOrInitialMapOffset;
|
||||
|
||||
private:
|
||||
// JSFunction doesn't have a fixed header size:
|
||||
// Hide JSFunctionOrBoundFunction::kHeaderSize to avoid confusion.
|
||||
static const int kHeaderSize;
|
||||
|
||||
public:
|
||||
static constexpr int kSizeWithoutPrototype = kPrototypeOrInitialMapOffset;
|
||||
static constexpr int kSizeWithPrototype = FieldOffsets::kHeaderSize;
|
||||
|
||||
OBJECT_CONSTRUCTORS(JSFunction, JSFunctionOrBoundFunction);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#include "src/objects/object-macros-undef.h"
|
||||
|
||||
#endif // V8_OBJECTS_JS_FUNCTION_H_
|
@ -5,11 +5,9 @@
|
||||
#ifndef V8_OBJECTS_JS_OBJECTS_INL_H_
|
||||
#define V8_OBJECTS_JS_OBJECTS_INL_H_
|
||||
|
||||
#include "src/diagnostics/code-tracer.h"
|
||||
#include "src/heap/heap-write-barrier.h"
|
||||
#include "src/objects/elements.h"
|
||||
#include "src/objects/embedder-data-slot-inl.h"
|
||||
#include "src/objects/feedback-cell-inl.h"
|
||||
#include "src/objects/feedback-vector.h"
|
||||
#include "src/objects/field-index-inl.h"
|
||||
#include "src/objects/hash-table-inl.h"
|
||||
@ -34,10 +32,7 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(JSObject)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSCustomElementsObject)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSSpecialObject)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSAsyncFromSyncIterator)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSFunctionOrBoundFunction)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSBoundFunction)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSDate)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSFunction, JSFunctionOrBoundFunction)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSGlobalObject, JSSpecialObject)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSGlobalProxy)
|
||||
JSIteratorResult::JSIteratorResult(Address ptr) : JSObject(ptr) {}
|
||||
@ -47,7 +42,6 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(JSStringIterator)
|
||||
|
||||
NEVER_READ_ONLY_SPACE_IMPL(JSReceiver)
|
||||
|
||||
CAST_ACCESSOR(JSFunction)
|
||||
CAST_ACCESSOR(JSGlobalObject)
|
||||
CAST_ACCESSOR(JSIteratorResult)
|
||||
CAST_ACCESSOR(JSMessageObject)
|
||||
@ -451,8 +445,6 @@ void JSObject::InitializeBody(Map map, int start_offset,
|
||||
}
|
||||
}
|
||||
|
||||
ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset)
|
||||
|
||||
ACCESSORS(JSGlobalObject, native_context, NativeContext, kNativeContextOffset)
|
||||
ACCESSORS(JSGlobalObject, global_proxy, JSGlobalProxy, kGlobalProxyOffset)
|
||||
|
||||
@ -460,265 +452,6 @@ DEF_GETTER(JSGlobalObject, native_context_unchecked, Object) {
|
||||
return TaggedField<Object, kNativeContextOffset>::load(isolate, *this);
|
||||
}
|
||||
|
||||
FeedbackVector JSFunction::feedback_vector() const {
|
||||
DCHECK(has_feedback_vector());
|
||||
return FeedbackVector::cast(raw_feedback_cell().value());
|
||||
}
|
||||
|
||||
ClosureFeedbackCellArray JSFunction::closure_feedback_cell_array() const {
|
||||
DCHECK(has_closure_feedback_cell_array());
|
||||
return ClosureFeedbackCellArray::cast(raw_feedback_cell().value());
|
||||
}
|
||||
|
||||
// Code objects that are marked for deoptimization are not considered to be
|
||||
// optimized. This is because the JSFunction might have been already
|
||||
// deoptimized but its code() still needs to be unlinked, which will happen on
|
||||
// its next activation.
|
||||
// TODO(jupvfranco): rename this function. Maybe RunOptimizedCode,
|
||||
// or IsValidOptimizedCode.
|
||||
bool JSFunction::IsOptimized() {
|
||||
return is_compiled() && code().kind() == Code::OPTIMIZED_FUNCTION &&
|
||||
!code().marked_for_deoptimization();
|
||||
}
|
||||
|
||||
bool JSFunction::HasOptimizedCode() {
|
||||
return IsOptimized() ||
|
||||
(has_feedback_vector() && feedback_vector().has_optimized_code() &&
|
||||
!feedback_vector().optimized_code().marked_for_deoptimization());
|
||||
}
|
||||
|
||||
bool JSFunction::HasOptimizationMarker() {
|
||||
return has_feedback_vector() && feedback_vector().has_optimization_marker();
|
||||
}
|
||||
|
||||
void JSFunction::ClearOptimizationMarker() {
|
||||
DCHECK(has_feedback_vector());
|
||||
feedback_vector().ClearOptimizationMarker();
|
||||
}
|
||||
|
||||
// Optimized code marked for deoptimization will tier back down to running
|
||||
// interpreted on its next activation, and already doesn't count as IsOptimized.
|
||||
bool JSFunction::IsInterpreted() {
|
||||
return is_compiled() && (code().is_interpreter_trampoline_builtin() ||
|
||||
(code().kind() == Code::OPTIMIZED_FUNCTION &&
|
||||
code().marked_for_deoptimization()));
|
||||
}
|
||||
|
||||
bool JSFunction::ChecksOptimizationMarker() {
|
||||
return code().checks_optimization_marker();
|
||||
}
|
||||
|
||||
bool JSFunction::IsMarkedForOptimization() {
|
||||
return has_feedback_vector() && feedback_vector().optimization_marker() ==
|
||||
OptimizationMarker::kCompileOptimized;
|
||||
}
|
||||
|
||||
bool JSFunction::IsMarkedForConcurrentOptimization() {
|
||||
return has_feedback_vector() &&
|
||||
feedback_vector().optimization_marker() ==
|
||||
OptimizationMarker::kCompileOptimizedConcurrent;
|
||||
}
|
||||
|
||||
bool JSFunction::IsInOptimizationQueue() {
|
||||
return has_feedback_vector() && feedback_vector().optimization_marker() ==
|
||||
OptimizationMarker::kInOptimizationQueue;
|
||||
}
|
||||
|
||||
void JSFunction::CompleteInobjectSlackTrackingIfActive() {
|
||||
if (!has_prototype_slot()) return;
|
||||
if (has_initial_map() && initial_map().IsInobjectSlackTrackingInProgress()) {
|
||||
initial_map().CompleteInobjectSlackTracking(GetIsolate());
|
||||
}
|
||||
}
|
||||
|
||||
AbstractCode JSFunction::abstract_code() {
|
||||
if (IsInterpreted()) {
|
||||
return AbstractCode::cast(shared().GetBytecodeArray());
|
||||
} else {
|
||||
return AbstractCode::cast(code());
|
||||
}
|
||||
}
|
||||
|
||||
int JSFunction::length() { return shared().length(); }
|
||||
|
||||
Code JSFunction::code() const {
|
||||
return Code::cast(RELAXED_READ_FIELD(*this, kCodeOffset));
|
||||
}
|
||||
|
||||
void JSFunction::set_code(Code value) {
|
||||
DCHECK(!ObjectInYoungGeneration(value));
|
||||
RELAXED_WRITE_FIELD(*this, kCodeOffset, value);
|
||||
#ifndef V8_DISABLE_WRITE_BARRIERS
|
||||
WriteBarrier::Marking(*this, RawField(kCodeOffset), value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void JSFunction::set_code_no_write_barrier(Code value) {
|
||||
DCHECK(!ObjectInYoungGeneration(value));
|
||||
RELAXED_WRITE_FIELD(*this, kCodeOffset, value);
|
||||
}
|
||||
|
||||
// TODO(ishell): Why relaxed read but release store?
|
||||
DEF_GETTER(JSFunction, shared, SharedFunctionInfo) {
|
||||
return SharedFunctionInfo::cast(
|
||||
RELAXED_READ_FIELD(*this, kSharedFunctionInfoOffset));
|
||||
}
|
||||
|
||||
void JSFunction::set_shared(SharedFunctionInfo value, WriteBarrierMode mode) {
|
||||
// Release semantics to support acquire read in NeedsResetDueToFlushedBytecode
|
||||
RELEASE_WRITE_FIELD(*this, kSharedFunctionInfoOffset, value);
|
||||
CONDITIONAL_WRITE_BARRIER(*this, kSharedFunctionInfoOffset, value, mode);
|
||||
}
|
||||
|
||||
void JSFunction::ClearOptimizedCodeSlot(const char* reason) {
|
||||
if (has_feedback_vector() && feedback_vector().has_optimized_code()) {
|
||||
if (FLAG_trace_opt) {
|
||||
CodeTracer::Scope scope(GetIsolate()->GetCodeTracer());
|
||||
PrintF(scope.file(),
|
||||
"[evicting entry from optimizing code feedback slot (%s) for ",
|
||||
reason);
|
||||
ShortPrint(scope.file());
|
||||
PrintF(scope.file(), "]\n");
|
||||
}
|
||||
feedback_vector().ClearOptimizedCode();
|
||||
}
|
||||
}
|
||||
|
||||
void JSFunction::SetOptimizationMarker(OptimizationMarker marker) {
|
||||
DCHECK(has_feedback_vector());
|
||||
DCHECK(ChecksOptimizationMarker());
|
||||
DCHECK(!HasOptimizedCode());
|
||||
|
||||
feedback_vector().SetOptimizationMarker(marker);
|
||||
}
|
||||
|
||||
bool JSFunction::has_feedback_vector() const {
|
||||
return shared().is_compiled() &&
|
||||
raw_feedback_cell().value().IsFeedbackVector();
|
||||
}
|
||||
|
||||
bool JSFunction::has_closure_feedback_cell_array() const {
|
||||
return shared().is_compiled() &&
|
||||
raw_feedback_cell().value().IsClosureFeedbackCellArray();
|
||||
}
|
||||
|
||||
Context JSFunction::context() {
|
||||
return TaggedField<Context, kContextOffset>::load(*this);
|
||||
}
|
||||
|
||||
bool JSFunction::has_context() const {
|
||||
return TaggedField<HeapObject, kContextOffset>::load(*this).IsContext();
|
||||
}
|
||||
|
||||
JSGlobalProxy JSFunction::global_proxy() { return context().global_proxy(); }
|
||||
|
||||
NativeContext JSFunction::native_context() {
|
||||
return context().native_context();
|
||||
}
|
||||
|
||||
void JSFunction::set_context(HeapObject value) {
|
||||
DCHECK(value.IsUndefined() || value.IsContext());
|
||||
WRITE_FIELD(*this, kContextOffset, value);
|
||||
WRITE_BARRIER(*this, kContextOffset, value);
|
||||
}
|
||||
|
||||
ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, HeapObject,
|
||||
kPrototypeOrInitialMapOffset, map().has_prototype_slot())
|
||||
|
||||
DEF_GETTER(JSFunction, has_prototype_slot, bool) {
|
||||
return map(isolate).has_prototype_slot();
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, initial_map, Map) {
|
||||
return Map::cast(prototype_or_initial_map(isolate));
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_initial_map, bool) {
|
||||
DCHECK(has_prototype_slot(isolate));
|
||||
return prototype_or_initial_map(isolate).IsMap(isolate);
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_instance_prototype, bool) {
|
||||
DCHECK(has_prototype_slot(isolate));
|
||||
// Can't use ReadOnlyRoots(isolate) as this isolate could be produced by
|
||||
// i::GetIsolateForPtrCompr(HeapObject).
|
||||
return has_initial_map(isolate) ||
|
||||
!prototype_or_initial_map(isolate).IsTheHole(
|
||||
GetReadOnlyRoots(isolate));
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_prototype, bool) {
|
||||
DCHECK(has_prototype_slot(isolate));
|
||||
return map(isolate).has_non_instance_prototype() ||
|
||||
has_instance_prototype(isolate);
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, has_prototype_property, bool) {
|
||||
return (has_prototype_slot(isolate) && IsConstructor(isolate)) ||
|
||||
IsGeneratorFunction(shared(isolate).kind());
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, PrototypeRequiresRuntimeLookup, bool) {
|
||||
return !has_prototype_property(isolate) ||
|
||||
map(isolate).has_non_instance_prototype();
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, instance_prototype, HeapObject) {
|
||||
DCHECK(has_instance_prototype(isolate));
|
||||
if (has_initial_map(isolate)) return initial_map(isolate).prototype(isolate);
|
||||
// When there is no initial map and the prototype is a JSReceiver, the
|
||||
// initial map field is used for the prototype field.
|
||||
return HeapObject::cast(prototype_or_initial_map(isolate));
|
||||
}
|
||||
|
||||
DEF_GETTER(JSFunction, prototype, Object) {
|
||||
DCHECK(has_prototype(isolate));
|
||||
// If the function's prototype property has been set to a non-JSReceiver
|
||||
// value, that value is stored in the constructor field of the map.
|
||||
if (map(isolate).has_non_instance_prototype()) {
|
||||
Object prototype = map(isolate).GetConstructor(isolate);
|
||||
// The map must have a prototype in that field, not a back pointer.
|
||||
DCHECK(!prototype.IsMap(isolate));
|
||||
DCHECK(!prototype.IsFunctionTemplateInfo(isolate));
|
||||
return prototype;
|
||||
}
|
||||
return instance_prototype(isolate);
|
||||
}
|
||||
|
||||
bool JSFunction::is_compiled() const {
|
||||
return code().builtin_index() != Builtins::kCompileLazy &&
|
||||
shared().is_compiled();
|
||||
}
|
||||
|
||||
bool JSFunction::NeedsResetDueToFlushedBytecode() {
|
||||
// Do a raw read for shared and code fields here since this function may be
|
||||
// called on a concurrent thread and the JSFunction might not be fully
|
||||
// initialized yet.
|
||||
Object maybe_shared = ACQUIRE_READ_FIELD(*this, kSharedFunctionInfoOffset);
|
||||
Object maybe_code = RELAXED_READ_FIELD(*this, kCodeOffset);
|
||||
|
||||
if (!maybe_shared.IsSharedFunctionInfo() || !maybe_code.IsCode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedFunctionInfo shared = SharedFunctionInfo::cast(maybe_shared);
|
||||
Code code = Code::cast(maybe_code);
|
||||
return !shared.is_compiled() &&
|
||||
code.builtin_index() != Builtins::kCompileLazy;
|
||||
}
|
||||
|
||||
void JSFunction::ResetIfBytecodeFlushed(
|
||||
base::Optional<std::function<void(HeapObject object, ObjectSlot slot,
|
||||
HeapObject target)>>
|
||||
gc_notify_updated_slot) {
|
||||
if (FLAG_flush_bytecode && NeedsResetDueToFlushedBytecode()) {
|
||||
// Bytecode was flushed and function is now uncompiled, reset JSFunction
|
||||
// by setting code to CompileLazy and clearing the feedback vector.
|
||||
set_code(GetIsolate()->builtins()->builtin(i::Builtins::kCompileLazy));
|
||||
raw_feedback_cell().reset_feedback_vector(gc_notify_updated_slot);
|
||||
}
|
||||
}
|
||||
|
||||
bool JSMessageObject::DidEnsureSourcePositionsAvailable() const {
|
||||
return shared_info().IsUndefined();
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "src/objects/js-objects.h"
|
||||
|
||||
#include "src/api/api-arguments-inl.h"
|
||||
#include "src/codegen/compiler.h"
|
||||
#include "src/date/date.h"
|
||||
#include "src/execution/arguments.h"
|
||||
#include "src/execution/frames.h"
|
||||
@ -15,7 +14,6 @@
|
||||
#include "src/heap/factory-inl.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/memory-chunk.h"
|
||||
#include "src/ic/ic.h"
|
||||
#include "src/init/bootstrapper.h"
|
||||
#include "src/logging/counters.h"
|
||||
#include "src/logging/log.h"
|
||||
@ -4863,814 +4861,6 @@ bool JSObject::IsDroppableApiWrapper() {
|
||||
instance_type == JS_SPECIAL_API_OBJECT_TYPE;
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<NativeContext> JSBoundFunction::GetFunctionRealm(
|
||||
Handle<JSBoundFunction> function) {
|
||||
DCHECK(function->map().is_constructor());
|
||||
return JSReceiver::GetFunctionRealm(
|
||||
handle(function->bound_target_function(), function->GetIsolate()));
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function) {
|
||||
Handle<String> prefix = isolate->factory()->bound__string();
|
||||
Handle<String> target_name = prefix;
|
||||
Factory* factory = isolate->factory();
|
||||
// Concatenate the "bound " up to the last non-bound target.
|
||||
while (function->bound_target_function().IsJSBoundFunction()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
|
||||
factory->NewConsString(prefix, target_name),
|
||||
String);
|
||||
function = handle(JSBoundFunction::cast(function->bound_target_function()),
|
||||
isolate);
|
||||
}
|
||||
if (function->bound_target_function().IsJSFunction()) {
|
||||
Handle<JSFunction> target(
|
||||
JSFunction::cast(function->bound_target_function()), isolate);
|
||||
Handle<Object> name = JSFunction::GetName(isolate, target);
|
||||
if (!name->IsString()) return target_name;
|
||||
return factory->NewConsString(target_name, Handle<String>::cast(name));
|
||||
}
|
||||
// This will omit the proper target name for bound JSProxies.
|
||||
return target_name;
|
||||
}
|
||||
|
||||
// static
|
||||
Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function) {
|
||||
int nof_bound_arguments = function->bound_arguments().length();
|
||||
while (function->bound_target_function().IsJSBoundFunction()) {
|
||||
function = handle(JSBoundFunction::cast(function->bound_target_function()),
|
||||
isolate);
|
||||
// Make sure we never overflow {nof_bound_arguments}, the number of
|
||||
// arguments of a function is strictly limited by the max length of an
|
||||
// JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
|
||||
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;
|
||||
}
|
||||
}
|
||||
// All non JSFunction targets get a direct property and don't use this
|
||||
// accessor.
|
||||
Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
|
||||
isolate);
|
||||
int target_length = target->length();
|
||||
|
||||
int length = Max(0, target_length - nof_bound_arguments);
|
||||
return Just(length);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
return isolate->factory()->function_native_code_string();
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<Object> JSFunction::GetName(Isolate* isolate,
|
||||
Handle<JSFunction> function) {
|
||||
if (function->shared().name_should_print_as_anonymous()) {
|
||||
return isolate->factory()->anonymous_string();
|
||||
}
|
||||
return handle(function->shared().Name(), isolate);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<NativeContext> JSFunction::GetFunctionRealm(
|
||||
Handle<JSFunction> function) {
|
||||
DCHECK(function->map().is_constructor());
|
||||
return handle(function->context().native_context(), function->GetIsolate());
|
||||
}
|
||||
|
||||
void JSFunction::MarkForOptimization(ConcurrencyMode mode) {
|
||||
Isolate* isolate = GetIsolate();
|
||||
if (!isolate->concurrent_recompilation_enabled() ||
|
||||
isolate->bootstrapper()->IsActive()) {
|
||||
mode = ConcurrencyMode::kNotConcurrent;
|
||||
}
|
||||
|
||||
DCHECK(!is_compiled() || IsInterpreted());
|
||||
DCHECK(shared().IsInterpreted());
|
||||
DCHECK(!IsOptimized());
|
||||
DCHECK(!HasOptimizedCode());
|
||||
DCHECK(shared().allows_lazy_compilation() ||
|
||||
!shared().optimization_disabled());
|
||||
|
||||
if (mode == ConcurrencyMode::kConcurrent) {
|
||||
if (IsInOptimizationQueue()) {
|
||||
if (FLAG_trace_concurrent_recompilation) {
|
||||
PrintF(" ** Not marking ");
|
||||
ShortPrint();
|
||||
PrintF(" -- already in optimization queue.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (FLAG_trace_concurrent_recompilation) {
|
||||
PrintF(" ** Marking ");
|
||||
ShortPrint();
|
||||
PrintF(" for concurrent recompilation.\n");
|
||||
}
|
||||
}
|
||||
|
||||
SetOptimizationMarker(mode == ConcurrencyMode::kConcurrent
|
||||
? OptimizationMarker::kCompileOptimizedConcurrent
|
||||
: OptimizationMarker::kCompileOptimized);
|
||||
}
|
||||
|
||||
// static
|
||||
void JSFunction::EnsureClosureFeedbackCellArray(Handle<JSFunction> function) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
DCHECK(function->shared().is_compiled());
|
||||
DCHECK(function->shared().HasFeedbackMetadata());
|
||||
if (function->has_closure_feedback_cell_array() ||
|
||||
function->has_feedback_vector()) {
|
||||
return;
|
||||
}
|
||||
if (function->shared().HasAsmWasmData()) return;
|
||||
|
||||
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
|
||||
DCHECK(function->shared().HasBytecodeArray());
|
||||
Handle<HeapObject> feedback_cell_array =
|
||||
ClosureFeedbackCellArray::New(isolate, shared);
|
||||
// Many closure cell is used as a way to specify that there is no
|
||||
// feedback cell for this function and a new feedback cell has to be
|
||||
// allocated for this funciton. For ex: for eval functions, we have to create
|
||||
// a feedback cell and cache it along with the code. It is safe to use
|
||||
// many_closure_cell to indicate this because in regular cases, it should
|
||||
// already have a feedback_vector / feedback cell array allocated.
|
||||
if (function->raw_feedback_cell() == isolate->heap()->many_closures_cell()) {
|
||||
Handle<FeedbackCell> feedback_cell =
|
||||
isolate->factory()->NewOneClosureCell(feedback_cell_array);
|
||||
function->set_raw_feedback_cell(*feedback_cell);
|
||||
} else {
|
||||
function->raw_feedback_cell().set_value(*feedback_cell_array);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function,
|
||||
IsCompiledScope* is_compiled_scope) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
DCHECK(is_compiled_scope->is_compiled());
|
||||
DCHECK(function->shared().HasFeedbackMetadata());
|
||||
if (function->has_feedback_vector()) return;
|
||||
if (function->shared().HasAsmWasmData()) return;
|
||||
|
||||
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
|
||||
DCHECK(function->shared().HasBytecodeArray());
|
||||
|
||||
EnsureClosureFeedbackCellArray(function);
|
||||
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
|
||||
handle(function->closure_feedback_cell_array(), isolate);
|
||||
Handle<HeapObject> feedback_vector = FeedbackVector::New(
|
||||
isolate, shared, closure_feedback_cell_array, is_compiled_scope);
|
||||
// EnsureClosureFeedbackCellArray should handle the special case where we need
|
||||
// to allocate a new feedback cell. Please look at comment in that function
|
||||
// for more details.
|
||||
DCHECK(function->raw_feedback_cell() !=
|
||||
isolate->heap()->many_closures_cell());
|
||||
function->raw_feedback_cell().set_value(*feedback_vector);
|
||||
function->raw_feedback_cell().SetInterruptBudget();
|
||||
}
|
||||
|
||||
// static
|
||||
void JSFunction::InitializeFeedbackCell(Handle<JSFunction> function,
|
||||
IsCompiledScope* is_compiled_scope) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
|
||||
if (function->has_feedback_vector()) {
|
||||
CHECK_EQ(function->feedback_vector().length(),
|
||||
function->feedback_vector().metadata().slot_count());
|
||||
return;
|
||||
}
|
||||
|
||||
const bool needs_feedback_vector =
|
||||
!FLAG_lazy_feedback_allocation || FLAG_always_opt ||
|
||||
function->shared().may_have_cached_code() ||
|
||||
// We also need a feedback vector for certain log events, collecting type
|
||||
// profile and more precise code coverage.
|
||||
FLAG_log_function_events || !isolate->is_best_effort_code_coverage() ||
|
||||
isolate->is_collecting_type_profile();
|
||||
|
||||
if (needs_feedback_vector) {
|
||||
EnsureFeedbackVector(function, is_compiled_scope);
|
||||
} else {
|
||||
EnsureClosureFeedbackCellArray(function);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
|
||||
Handle<JSReceiver> value) {
|
||||
// Now some logic for the maps of the objects that are created by using this
|
||||
// function as a constructor.
|
||||
if (function->has_initial_map()) {
|
||||
// If the function has allocated the initial map replace it with a
|
||||
// copy containing the new prototype. Also complete any in-object
|
||||
// slack tracking that is in progress at this point because it is
|
||||
// still tracking the old copy.
|
||||
function->CompleteInobjectSlackTrackingIfActive();
|
||||
|
||||
Handle<Map> initial_map(function->initial_map(), isolate);
|
||||
|
||||
if (!isolate->bootstrapper()->IsActive() &&
|
||||
initial_map->instance_type() == JS_OBJECT_TYPE) {
|
||||
// Put the value in the initial map field until an initial map is needed.
|
||||
// At that point, a new initial map is created and the prototype is put
|
||||
// into the initial map where it belongs.
|
||||
function->set_prototype_or_initial_map(*value);
|
||||
} else {
|
||||
Handle<Map> new_map =
|
||||
Map::Copy(isolate, initial_map, "SetInstancePrototype");
|
||||
JSFunction::SetInitialMap(function, new_map, value);
|
||||
|
||||
// If the function is used as the global Array function, cache the
|
||||
// updated initial maps (and transitioned versions) in the native context.
|
||||
Handle<Context> native_context(function->context().native_context(),
|
||||
isolate);
|
||||
Handle<Object> array_function(
|
||||
native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
|
||||
if (array_function->IsJSFunction() &&
|
||||
*function == JSFunction::cast(*array_function)) {
|
||||
CacheInitialJSArrayMaps(isolate, native_context, new_map);
|
||||
}
|
||||
}
|
||||
|
||||
// Deoptimize all code that embeds the previous initial map.
|
||||
initial_map->dependent_code().DeoptimizeDependentCodeGroup(
|
||||
DependentCode::kInitialMapChangedGroup);
|
||||
} else {
|
||||
// Put the value in the initial map field until an initial map is
|
||||
// needed. At that point, a new initial map is created and the
|
||||
// prototype is put into the initial map where it belongs.
|
||||
function->set_prototype_or_initial_map(*value);
|
||||
if (value->IsJSObject()) {
|
||||
// Optimize as prototype to detach it from its transition tree.
|
||||
JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void JSFunction::SetPrototype(Handle<JSFunction> function,
|
||||
Handle<Object> value) {
|
||||
DCHECK(function->IsConstructor() ||
|
||||
IsGeneratorFunction(function->shared().kind()));
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<JSReceiver> construct_prototype;
|
||||
|
||||
// If the value is not a JSReceiver, store the value in the map's
|
||||
// constructor field so it can be accessed. Also, set the prototype
|
||||
// used for constructing objects to the original object prototype.
|
||||
// See ECMA-262 13.2.2.
|
||||
if (!value->IsJSReceiver()) {
|
||||
// Copy the map so this does not affect unrelated functions.
|
||||
// Remove map transitions because they point to maps with a
|
||||
// different prototype.
|
||||
Handle<Map> new_map =
|
||||
Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
|
||||
|
||||
JSObject::MigrateToMap(isolate, function, new_map);
|
||||
new_map->SetConstructor(*value);
|
||||
new_map->set_has_non_instance_prototype(true);
|
||||
|
||||
FunctionKind kind = function->shared().kind();
|
||||
Handle<Context> native_context(function->context().native_context(),
|
||||
isolate);
|
||||
|
||||
construct_prototype = Handle<JSReceiver>(
|
||||
IsGeneratorFunction(kind)
|
||||
? IsAsyncFunction(kind)
|
||||
? native_context->initial_async_generator_prototype()
|
||||
: native_context->initial_generator_prototype()
|
||||
: native_context->initial_object_prototype(),
|
||||
isolate);
|
||||
} else {
|
||||
construct_prototype = Handle<JSReceiver>::cast(value);
|
||||
function->map().set_has_non_instance_prototype(false);
|
||||
}
|
||||
|
||||
SetInstancePrototype(isolate, function, construct_prototype);
|
||||
}
|
||||
|
||||
void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
|
||||
Handle<HeapObject> prototype) {
|
||||
if (map->prototype() != *prototype)
|
||||
Map::SetPrototype(function->GetIsolate(), map, prototype);
|
||||
function->set_prototype_or_initial_map(*map);
|
||||
map->SetConstructor(*function);
|
||||
if (FLAG_trace_maps) {
|
||||
LOG(function->GetIsolate(), MapEvent("InitialMap", Handle<Map>(), map, "",
|
||||
handle(function->shared().DebugName(),
|
||||
function->GetIsolate())));
|
||||
}
|
||||
}
|
||||
|
||||
void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
||||
DCHECK(function->has_prototype_slot());
|
||||
DCHECK(function->IsConstructor() ||
|
||||
IsResumableFunction(function->shared().kind()));
|
||||
if (function->has_initial_map()) return;
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
|
||||
int expected_nof_properties =
|
||||
CalculateExpectedNofProperties(isolate, function);
|
||||
|
||||
// {CalculateExpectedNofProperties} can have had the side effect of creating
|
||||
// the initial map (e.g. it could have triggered an optimized compilation
|
||||
// whose dependency installation reentered {EnsureHasInitialMap}).
|
||||
if (function->has_initial_map()) return;
|
||||
|
||||
// Create a new map with the size and number of in-object properties suggested
|
||||
// by the function.
|
||||
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);
|
||||
|
||||
Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
|
||||
TERMINAL_FAST_ELEMENTS_KIND,
|
||||
inobject_properties);
|
||||
|
||||
// Fetch or allocate prototype.
|
||||
Handle<HeapObject> prototype;
|
||||
if (function->has_instance_prototype()) {
|
||||
prototype = handle(function->instance_prototype(), isolate);
|
||||
} else {
|
||||
prototype = isolate->factory()->NewFunctionPrototype(function);
|
||||
}
|
||||
DCHECK(map->has_fast_object_elements());
|
||||
|
||||
// Finally link initial map and constructor function.
|
||||
DCHECK(prototype->IsJSReceiver());
|
||||
JSFunction::SetInitialMap(function, map, prototype);
|
||||
map->StartInobjectSlackTracking();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
namespace {
|
||||
|
||||
bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
|
||||
switch (instance_type) {
|
||||
case JS_API_OBJECT_TYPE:
|
||||
case JS_ARRAY_BUFFER_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_DATE_TYPE:
|
||||
case JS_FUNCTION_TYPE:
|
||||
case JS_GENERATOR_OBJECT_TYPE:
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
case JS_COLLATOR_TYPE:
|
||||
case JS_DATE_TIME_FORMAT_TYPE:
|
||||
case JS_DISPLAY_NAMES_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_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_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_TYPED_ARRAY_TYPE:
|
||||
case JS_PRIMITIVE_WRAPPER_TYPE:
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
case JS_WEAK_REF_TYPE:
|
||||
case JS_WEAK_SET_TYPE:
|
||||
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:
|
||||
return true;
|
||||
|
||||
case BIGINT_TYPE:
|
||||
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
|
||||
case BYTECODE_ARRAY_TYPE:
|
||||
case BYTE_ARRAY_TYPE:
|
||||
case CELL_TYPE:
|
||||
case CODE_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 STRING_TABLE_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 MAP_TYPE:
|
||||
case ODDBALL_TYPE:
|
||||
case PROPERTY_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
|
||||
// We must not end up here for these instance types at all.
|
||||
UNREACHABLE();
|
||||
// Fall through.
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
|
||||
Handle<JSFunction> constructor,
|
||||
Handle<Map> constructor_initial_map) {
|
||||
// Use the default intrinsic prototype instead.
|
||||
if (!new_target->has_prototype_slot()) return false;
|
||||
// Check that |function|'s initial map still in sync with the |constructor|,
|
||||
// otherwise we must create a new initial map for |function|.
|
||||
if (new_target->has_initial_map() &&
|
||||
new_target->initial_map().GetConstructor() == *constructor) {
|
||||
DCHECK(new_target->instance_prototype().IsJSReceiver());
|
||||
return true;
|
||||
}
|
||||
InstanceType instance_type = constructor_initial_map->instance_type();
|
||||
DCHECK(CanSubclassHaveInobjectProperties(instance_type));
|
||||
// Create a new map with the size and number of in-object properties
|
||||
// suggested by |function|.
|
||||
|
||||
// Link initial map and constructor function if the new.target is actually a
|
||||
// subclass constructor.
|
||||
if (!IsDerivedConstructor(new_target->shared().kind())) return false;
|
||||
|
||||
int instance_size;
|
||||
int in_object_properties;
|
||||
int embedder_fields =
|
||||
JSObject::GetEmbedderFieldCount(*constructor_initial_map);
|
||||
// Constructor expects certain number of in-object properties to be in the
|
||||
// object. However, CalculateExpectedNofProperties() may return smaller value
|
||||
// if 1) the constructor is not in the prototype chain of new_target, or
|
||||
// 2) the prototype chain is modified during iteration, or 3) compilation
|
||||
// failure occur during prototype chain iteration.
|
||||
// So we take the maximum of two values.
|
||||
int expected_nof_properties =
|
||||
Max(static_cast<int>(constructor->shared().expected_nof_properties()),
|
||||
JSFunction::CalculateExpectedNofProperties(isolate, new_target));
|
||||
JSFunction::CalculateInstanceSizeHelper(
|
||||
instance_type, true, 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;
|
||||
Handle<Map> map =
|
||||
Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
|
||||
in_object_properties, unused_property_fields);
|
||||
map->set_new_target_is_base(false);
|
||||
Handle<HeapObject> prototype(new_target->instance_prototype(), isolate);
|
||||
JSFunction::SetInitialMap(new_target, map, prototype);
|
||||
DCHECK(new_target->instance_prototype().IsJSReceiver());
|
||||
map->SetConstructor(*constructor);
|
||||
map->set_construction_counter(Map::kNoSlackTracking);
|
||||
map->StartInobjectSlackTracking();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
|
||||
Handle<JSFunction> constructor,
|
||||
Handle<JSReceiver> new_target) {
|
||||
EnsureHasInitialMap(constructor);
|
||||
|
||||
Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
|
||||
if (*new_target == *constructor) return constructor_initial_map;
|
||||
|
||||
Handle<Map> result_map;
|
||||
// Fast case, new.target is a subclass of constructor. The map is cacheable
|
||||
// (and may already have been cached). new.target.prototype is guaranteed to
|
||||
// be a JSReceiver.
|
||||
if (new_target->IsJSFunction()) {
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
|
||||
if (FastInitializeDerivedMap(isolate, function, constructor,
|
||||
constructor_initial_map)) {
|
||||
return handle(function->initial_map(), isolate);
|
||||
}
|
||||
}
|
||||
|
||||
// Slow path, new.target is either a proxy or can't cache the map.
|
||||
// new.target.prototype is not guaranteed to be a JSReceiver, and may need to
|
||||
// fall back to the intrinsicDefaultProto.
|
||||
Handle<Object> prototype;
|
||||
if (new_target->IsJSFunction()) {
|
||||
Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
|
||||
if (function->has_prototype_slot()) {
|
||||
// Make sure the new.target.prototype is cached.
|
||||
EnsureHasInitialMap(function);
|
||||
prototype = handle(function->prototype(), isolate);
|
||||
} else {
|
||||
// No prototype property, use the intrinsict default proto further down.
|
||||
prototype = isolate->factory()->undefined_value();
|
||||
}
|
||||
} else {
|
||||
Handle<String> prototype_string = isolate->factory()->prototype_string();
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, prototype,
|
||||
JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
|
||||
// The above prototype lookup might change the constructor and its
|
||||
// prototype, hence we have to reload the initial map.
|
||||
EnsureHasInitialMap(constructor);
|
||||
constructor_initial_map = handle(constructor->initial_map(), isolate);
|
||||
}
|
||||
|
||||
// If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
|
||||
// correct realm. Rather than directly fetching the .prototype, we fetch the
|
||||
// constructor that points to the .prototype. This relies on
|
||||
// constructor.prototype being FROZEN for those constructors.
|
||||
if (!prototype->IsJSReceiver()) {
|
||||
Handle<Context> context;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
|
||||
JSReceiver::GetFunctionRealm(new_target), Map);
|
||||
DCHECK(context->IsNativeContext());
|
||||
Handle<Object> maybe_index = JSReceiver::GetDataProperty(
|
||||
constructor, isolate->factory()->native_context_index_symbol());
|
||||
int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
|
||||
: Context::OBJECT_FUNCTION_INDEX;
|
||||
Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
|
||||
isolate);
|
||||
prototype = handle(realm_constructor->prototype(), isolate);
|
||||
}
|
||||
|
||||
Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
|
||||
map->set_new_target_is_base(false);
|
||||
CHECK(prototype->IsJSReceiver());
|
||||
if (map->prototype() != *prototype)
|
||||
Map::SetPrototype(isolate, map, Handle<HeapObject>::cast(prototype));
|
||||
map->SetConstructor(*constructor);
|
||||
return 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();
|
||||
}
|
||||
|
||||
void JSFunction::PrintName(FILE* out) {
|
||||
std::unique_ptr<char[]> name = shared().DebugName().ToCString();
|
||||
PrintF(out, "%s", name.get());
|
||||
}
|
||||
|
||||
Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<Object> name =
|
||||
JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
|
||||
if (name->IsString()) return Handle<String>::cast(name);
|
||||
return handle(function->shared().DebugName(), isolate);
|
||||
}
|
||||
|
||||
Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<Object> name = JSReceiver::GetDataProperty(
|
||||
function, isolate->factory()->display_name_string());
|
||||
if (name->IsString()) return Handle<String>::cast(name);
|
||||
return JSFunction::GetName(function);
|
||||
}
|
||||
|
||||
bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
|
||||
Handle<String> prefix) {
|
||||
Isolate* isolate = function->GetIsolate();
|
||||
Handle<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 {
|
||||
|
||||
Handle<String> NativeCodeFunctionSourceString(
|
||||
Handle<SharedFunctionInfo> shared_info) {
|
||||
Isolate* const isolate = shared_info->GetIsolate();
|
||||
IncrementalStringBuilder builder(isolate);
|
||||
builder.AppendCString("function ");
|
||||
builder.AppendString(handle(shared_info->Name(), isolate));
|
||||
builder.AppendCString("() { [native code] }");
|
||||
return builder.Finish().ToHandleChecked();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
|
||||
Isolate* const isolate = function->GetIsolate();
|
||||
Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
|
||||
|
||||
// Check if {function} should hide its source code.
|
||||
if (!shared_info->IsUserJavaScript()) {
|
||||
return NativeCodeFunctionSourceString(shared_info);
|
||||
}
|
||||
|
||||
// Check if we should print {function} as a class.
|
||||
Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
|
||||
function, isolate->factory()->class_positions_symbol());
|
||||
if (maybe_class_positions->IsClassPositions()) {
|
||||
ClassPositions class_positions =
|
||||
ClassPositions::cast(*maybe_class_positions);
|
||||
int start_position = class_positions.start();
|
||||
int end_position = class_positions.end();
|
||||
Handle<String> script_source(
|
||||
String::cast(Script::cast(shared_info->script()).source()), isolate);
|
||||
return isolate->factory()->NewSubString(script_source, start_position,
|
||||
end_position);
|
||||
}
|
||||
|
||||
// Check if we have source code for the {function}.
|
||||
if (!shared_info->HasSourceCode()) {
|
||||
return NativeCodeFunctionSourceString(shared_info);
|
||||
}
|
||||
|
||||
// If this function was compiled from asm.js, use the recorded offset
|
||||
// information.
|
||||
if (shared_info->HasWasmExportedFunctionData()) {
|
||||
Handle<WasmExportedFunctionData> function_data(
|
||||
shared_info->wasm_exported_function_data(), isolate);
|
||||
const wasm::WasmModule* module = function_data->instance().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(
|
||||
String::cast(Script::cast(shared_info->script()).source()), isolate);
|
||||
return isolate->factory()->NewSubString(source, offsets.first,
|
||||
offsets.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (shared_info->function_token_position() == kNoSourcePosition) {
|
||||
// If the function token position isn't valid, return [native code] to
|
||||
// ensure calling eval on the returned source code throws rather than
|
||||
// giving inconsistent call behaviour.
|
||||
isolate->CountUsage(
|
||||
v8::Isolate::UseCounterFeature::kFunctionTokenOffsetTooLongForToString);
|
||||
return NativeCodeFunctionSourceString(shared_info);
|
||||
}
|
||||
return Handle<String>::cast(
|
||||
SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
|
||||
}
|
||||
|
||||
// static
|
||||
int JSFunction::CalculateExpectedNofProperties(Isolate* isolate,
|
||||
Handle<JSFunction> function) {
|
||||
int expected_nof_properties = 0;
|
||||
for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
|
||||
!iter.IsAtEnd(); iter.Advance()) {
|
||||
Handle<JSReceiver> current =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(iter);
|
||||
if (!current->IsJSFunction()) break;
|
||||
Handle<JSFunction> func = Handle<JSFunction>::cast(current);
|
||||
// The super constructor should be compiled for the number of expected
|
||||
// properties to be available.
|
||||
Handle<SharedFunctionInfo> shared(func->shared(), isolate);
|
||||
IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
|
||||
if (is_compiled_scope.is_compiled() ||
|
||||
Compiler::Compile(func, Compiler::CLEAR_EXCEPTION,
|
||||
&is_compiled_scope)) {
|
||||
DCHECK(shared->is_compiled());
|
||||
int count = shared->expected_nof_properties();
|
||||
// Check that the estimate is sensible.
|
||||
if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
|
||||
expected_nof_properties += count;
|
||||
} else {
|
||||
return JSObject::kMaxInObjectProperties;
|
||||
}
|
||||
} else {
|
||||
// In case there was a compilation error proceed iterating in case there
|
||||
// will be a builtin function in the prototype chain that requires
|
||||
// certain number of in-object properties.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Inobject slack tracking will reclaim redundant inobject space
|
||||
// later, so we can afford to adjust the estimate generously,
|
||||
// meaning we over-allocate by at least 8 slots in the beginning.
|
||||
if (expected_nof_properties > 0) {
|
||||
expected_nof_properties += 8;
|
||||
if (expected_nof_properties > JSObject::kMaxInObjectProperties) {
|
||||
expected_nof_properties = JSObject::kMaxInObjectProperties;
|
||||
}
|
||||
}
|
||||
return expected_nof_properties;
|
||||
}
|
||||
|
||||
// static
|
||||
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);
|
||||
if (requested_embedder_fields) {
|
||||
// If there are embedder fields, then the embedder fields start offset must
|
||||
// be properly aligned (embedder fields are located between object header
|
||||
// and inobject fields).
|
||||
header_size = RoundUp<kSystemPointerSize>(header_size);
|
||||
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 = 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::ClearTypeFeedbackInfo() {
|
||||
ResetIfBytecodeFlushed();
|
||||
if (has_feedback_vector()) {
|
||||
FeedbackVector vector = feedback_vector();
|
||||
Isolate* isolate = GetIsolate();
|
||||
if (vector.ClearSlots(isolate)) {
|
||||
IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(),
|
||||
"ClearTypeFeedbackInfo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
|
||||
Handle<Name> name) {
|
||||
// Regardless of whether the property is there or not invalidate
|
||||
|
@ -926,275 +926,6 @@ class JSIteratorResult : public JSObject {
|
||||
OBJECT_CONSTRUCTORS(JSIteratorResult, JSObject);
|
||||
};
|
||||
|
||||
// An abstract superclass for classes representing JavaScript function values.
|
||||
// It doesn't carry any functionality but allows function classes to be
|
||||
// identified in the type system.
|
||||
class JSFunctionOrBoundFunction
|
||||
: public TorqueGeneratedJSFunctionOrBoundFunction<JSFunctionOrBoundFunction,
|
||||
JSObject> {
|
||||
public:
|
||||
STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize);
|
||||
TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction)
|
||||
};
|
||||
|
||||
// JSBoundFunction describes a bound function exotic object.
|
||||
class JSBoundFunction
|
||||
: public TorqueGeneratedJSBoundFunction<JSBoundFunction,
|
||||
JSFunctionOrBoundFunction> {
|
||||
public:
|
||||
static MaybeHandle<String> GetName(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function);
|
||||
static Maybe<int> GetLength(Isolate* isolate,
|
||||
Handle<JSBoundFunction> function);
|
||||
static MaybeHandle<NativeContext> GetFunctionRealm(
|
||||
Handle<JSBoundFunction> function);
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_PRINTER(JSBoundFunction)
|
||||
DECL_VERIFIER(JSBoundFunction)
|
||||
|
||||
// The bound function's string representation implemented according
|
||||
// to ES6 section 19.2.3.5 Function.prototype.toString ( ).
|
||||
static Handle<String> ToString(Handle<JSBoundFunction> function);
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(JSBoundFunction)
|
||||
};
|
||||
|
||||
// JSFunction describes JavaScript functions.
|
||||
class JSFunction : public JSFunctionOrBoundFunction {
|
||||
public:
|
||||
// [prototype_or_initial_map]:
|
||||
DECL_ACCESSORS(prototype_or_initial_map, HeapObject)
|
||||
|
||||
// [shared]: The information about the function that
|
||||
// can be shared by instances.
|
||||
DECL_ACCESSORS(shared, SharedFunctionInfo)
|
||||
|
||||
static const int kLengthDescriptorIndex = 0;
|
||||
static const int kNameDescriptorIndex = 1;
|
||||
// Home object descriptor index when function has a [[HomeObject]] slot.
|
||||
static const int kMaybeHomeObjectDescriptorIndex = 2;
|
||||
// Fast binding requires length and name accessors.
|
||||
static const int kMinDescriptorsForFastBind = 2;
|
||||
|
||||
// [context]: The context for this function.
|
||||
inline Context context();
|
||||
inline bool has_context() const;
|
||||
inline void set_context(HeapObject context);
|
||||
inline JSGlobalProxy global_proxy();
|
||||
inline NativeContext native_context();
|
||||
inline int length();
|
||||
|
||||
static Handle<Object> GetName(Isolate* isolate, Handle<JSFunction> function);
|
||||
static Handle<NativeContext> GetFunctionRealm(Handle<JSFunction> function);
|
||||
|
||||
// [code]: The generated code object for this function. Executed
|
||||
// when the function is invoked, e.g. foo() or new foo(). See
|
||||
// [[Call]] and [[Construct]] description in ECMA-262, section
|
||||
// 8.6.2, page 27.
|
||||
inline Code code() const;
|
||||
inline void set_code(Code code);
|
||||
inline void set_code_no_write_barrier(Code code);
|
||||
|
||||
// Get the abstract code associated with the function, which will either be
|
||||
// a Code object or a BytecodeArray.
|
||||
inline AbstractCode abstract_code();
|
||||
|
||||
// Tells whether or not this function is interpreted.
|
||||
//
|
||||
// Note: function->IsInterpreted() does not necessarily return the same value
|
||||
// as function->shared()->IsInterpreted() because the closure might have been
|
||||
// optimized.
|
||||
inline bool IsInterpreted();
|
||||
|
||||
// Tells whether or not this function checks its optimization marker in its
|
||||
// feedback vector.
|
||||
inline bool ChecksOptimizationMarker();
|
||||
|
||||
// Tells whether or not this function holds optimized code.
|
||||
//
|
||||
// Note: Returning false does not necessarily mean that this function hasn't
|
||||
// been optimized, as it may have optimized code on its feedback vector.
|
||||
inline bool IsOptimized();
|
||||
|
||||
// Tells whether or not this function has optimized code available to it,
|
||||
// either because it is optimized or because it has optimized code in its
|
||||
// feedback vector.
|
||||
inline bool HasOptimizedCode();
|
||||
|
||||
// Tells whether or not this function has a (non-zero) optimization marker.
|
||||
inline bool HasOptimizationMarker();
|
||||
|
||||
// Mark this function for lazy recompilation. The function will be recompiled
|
||||
// the next time it is executed.
|
||||
void MarkForOptimization(ConcurrencyMode mode);
|
||||
|
||||
// Tells whether or not the function is already marked for lazy recompilation.
|
||||
inline bool IsMarkedForOptimization();
|
||||
inline bool IsMarkedForConcurrentOptimization();
|
||||
|
||||
// Tells whether or not the function is on the concurrent recompilation queue.
|
||||
inline bool IsInOptimizationQueue();
|
||||
|
||||
// Clears the optimized code slot in the function's feedback vector.
|
||||
inline void ClearOptimizedCodeSlot(const char* reason);
|
||||
|
||||
// Sets the optimization marker in the function's feedback vector.
|
||||
inline void SetOptimizationMarker(OptimizationMarker marker);
|
||||
|
||||
// Clears the optimization marker in the function's feedback vector.
|
||||
inline void ClearOptimizationMarker();
|
||||
|
||||
// If slack tracking is active, it computes instance size of the initial map
|
||||
// with minimum permissible object slack. If it is not active, it simply
|
||||
// returns the initial map's instance size.
|
||||
int ComputeInstanceSizeWithMinSlack(Isolate* isolate);
|
||||
|
||||
// Completes inobject slack tracking on initial map if it is active.
|
||||
inline void CompleteInobjectSlackTrackingIfActive();
|
||||
|
||||
// [raw_feedback_cell]: Gives raw access to the FeedbackCell used to hold the
|
||||
/// FeedbackVector eventually. Generally this shouldn't be used to get the
|
||||
// feedback_vector, instead use feedback_vector() which correctly deals with
|
||||
// the JSFunction's bytecode being flushed.
|
||||
DECL_ACCESSORS(raw_feedback_cell, FeedbackCell)
|
||||
|
||||
// Functions related to feedback vector. feedback_vector() can be used once
|
||||
// the function has feedback vectors allocated. feedback vectors may not be
|
||||
// available after compile when lazily allocating feedback vectors.
|
||||
inline FeedbackVector feedback_vector() const;
|
||||
inline bool has_feedback_vector() const;
|
||||
V8_EXPORT_PRIVATE static void EnsureFeedbackVector(
|
||||
Handle<JSFunction> function, IsCompiledScope* compiled_scope);
|
||||
|
||||
// Functions related to clousre feedback cell array that holds feedback cells
|
||||
// used to create closures from this function. We allocate closure feedback
|
||||
// cell arrays after compile, when we want to allocate feedback vectors
|
||||
// lazily.
|
||||
inline bool has_closure_feedback_cell_array() const;
|
||||
inline ClosureFeedbackCellArray closure_feedback_cell_array() const;
|
||||
static void EnsureClosureFeedbackCellArray(Handle<JSFunction> function);
|
||||
|
||||
// Initializes the feedback cell of |function|. In lite mode, this would be
|
||||
// initialized to the closure feedback cell array that holds the feedback
|
||||
// cells for create closure calls from this function. In the regular mode,
|
||||
// this allocates feedback vector.
|
||||
static void InitializeFeedbackCell(Handle<JSFunction> function,
|
||||
IsCompiledScope* compiled_scope);
|
||||
|
||||
// Unconditionally clear the type feedback vector.
|
||||
void ClearTypeFeedbackInfo();
|
||||
|
||||
// Resets function to clear compiled data after bytecode has been flushed.
|
||||
inline bool NeedsResetDueToFlushedBytecode();
|
||||
inline void ResetIfBytecodeFlushed(
|
||||
base::Optional<std::function<void(HeapObject object, ObjectSlot slot,
|
||||
HeapObject target)>>
|
||||
gc_notify_updated_slot = base::nullopt);
|
||||
|
||||
DECL_GETTER(has_prototype_slot, bool)
|
||||
|
||||
// The initial map for an object created by this constructor.
|
||||
DECL_GETTER(initial_map, Map)
|
||||
|
||||
static void SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
|
||||
Handle<HeapObject> prototype);
|
||||
DECL_GETTER(has_initial_map, bool)
|
||||
V8_EXPORT_PRIVATE static void EnsureHasInitialMap(
|
||||
Handle<JSFunction> function);
|
||||
|
||||
// Creates a map that matches the constructor's initial map, but with
|
||||
// [[prototype]] being new.target.prototype. Because new.target can be a
|
||||
// JSProxy, this can call back into JavaScript.
|
||||
static V8_WARN_UNUSED_RESULT MaybeHandle<Map> GetDerivedMap(
|
||||
Isolate* isolate, Handle<JSFunction> constructor,
|
||||
Handle<JSReceiver> new_target);
|
||||
|
||||
// Get and set the prototype property on a JSFunction. If the
|
||||
// function has an initial map the prototype is set on the initial
|
||||
// map. Otherwise, the prototype is put in the initial map field
|
||||
// until an initial map is needed.
|
||||
DECL_GETTER(has_prototype, bool)
|
||||
DECL_GETTER(has_instance_prototype, bool)
|
||||
DECL_GETTER(prototype, Object)
|
||||
DECL_GETTER(instance_prototype, HeapObject)
|
||||
DECL_GETTER(has_prototype_property, bool)
|
||||
DECL_GETTER(PrototypeRequiresRuntimeLookup, bool)
|
||||
static void SetPrototype(Handle<JSFunction> function, Handle<Object> value);
|
||||
|
||||
// Returns if this function has been compiled to native code yet.
|
||||
inline bool is_compiled() const;
|
||||
|
||||
static int GetHeaderSize(bool function_has_prototype_slot) {
|
||||
return function_has_prototype_slot ? JSFunction::kSizeWithPrototype
|
||||
: JSFunction::kSizeWithoutPrototype;
|
||||
}
|
||||
|
||||
// Prints the name of the function using PrintF.
|
||||
void PrintName(FILE* out = stdout);
|
||||
|
||||
DECL_CAST(JSFunction)
|
||||
|
||||
// Calculate the instance size and in-object properties count.
|
||||
// {CalculateExpectedNofProperties} can trigger compilation.
|
||||
static V8_WARN_UNUSED_RESULT int CalculateExpectedNofProperties(
|
||||
Isolate* isolate, Handle<JSFunction> function);
|
||||
static void CalculateInstanceSizeHelper(InstanceType instance_type,
|
||||
bool has_prototype_slot,
|
||||
int requested_embedder_fields,
|
||||
int requested_in_object_properties,
|
||||
int* instance_size,
|
||||
int* in_object_properties);
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_PRINTER(JSFunction)
|
||||
DECL_VERIFIER(JSFunction)
|
||||
|
||||
// The function's name if it is configured, otherwise shared function info
|
||||
// debug name.
|
||||
static Handle<String> GetName(Handle<JSFunction> function);
|
||||
|
||||
// ES6 section 9.2.11 SetFunctionName
|
||||
// Because of the way this abstract operation is used in the spec,
|
||||
// it should never fail, but in practice it will fail if the generated
|
||||
// function name's length exceeds String::kMaxLength.
|
||||
static V8_WARN_UNUSED_RESULT bool SetName(Handle<JSFunction> function,
|
||||
Handle<Name> name,
|
||||
Handle<String> prefix);
|
||||
|
||||
// The function's displayName if it is set, otherwise name if it is
|
||||
// configured, otherwise shared function info
|
||||
// debug name.
|
||||
static Handle<String> GetDebugName(Handle<JSFunction> function);
|
||||
|
||||
// The function's string representation implemented according to
|
||||
// ES6 section 19.2.3.5 Function.prototype.toString ( ).
|
||||
static Handle<String> ToString(Handle<JSFunction> function);
|
||||
|
||||
struct FieldOffsets {
|
||||
DEFINE_FIELD_OFFSET_CONSTANTS(JSFunctionOrBoundFunction::kHeaderSize,
|
||||
TORQUE_GENERATED_JS_FUNCTION_FIELDS)
|
||||
};
|
||||
static constexpr int kSharedFunctionInfoOffset =
|
||||
FieldOffsets::kSharedFunctionInfoOffset;
|
||||
static constexpr int kContextOffset = FieldOffsets::kContextOffset;
|
||||
static constexpr int kFeedbackCellOffset = FieldOffsets::kFeedbackCellOffset;
|
||||
static constexpr int kCodeOffset = FieldOffsets::kCodeOffset;
|
||||
static constexpr int kPrototypeOrInitialMapOffset =
|
||||
FieldOffsets::kPrototypeOrInitialMapOffset;
|
||||
|
||||
private:
|
||||
// JSFunction doesn't have a fixed header size:
|
||||
// Hide JSFunctionOrBoundFunction::kHeaderSize to avoid confusion.
|
||||
static const int kHeaderSize;
|
||||
|
||||
public:
|
||||
static constexpr int kSizeWithoutPrototype = kPrototypeOrInitialMapOffset;
|
||||
static constexpr int kSizeWithPrototype = FieldOffsets::kHeaderSize;
|
||||
|
||||
OBJECT_CONSTRUCTORS(JSFunction, JSFunctionOrBoundFunction);
|
||||
};
|
||||
|
||||
// JSGlobalProxy's prototype must be a JSGlobalObject or null,
|
||||
// and the prototype is hidden. JSGlobalProxy always delegates
|
||||
// property accesses to its prototype if the prototype is not null.
|
||||
|
@ -4006,6 +4006,8 @@ void EmitClassDefinitionHeadersIncludes(const std::string& basename,
|
||||
header << "#include <type_traits>\n\n";
|
||||
|
||||
inline_header << "#include \"torque-generated/class-definitions-tq.h\"\n";
|
||||
inline_header << "#include \"src/objects/js-function.h\"\n";
|
||||
inline_header << "#include \"src/objects/js-objects.h\"\n";
|
||||
inline_header << "#include \"src/objects/js-promise.h\"\n";
|
||||
inline_header << "#include \"src/objects/js-weak-refs.h\"\n";
|
||||
inline_header << "#include \"src/objects/module.h\"\n";
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/common/globals.h"
|
||||
#include "src/objects/fixed-array.h"
|
||||
#include "src/objects/js-function.h"
|
||||
#include "src/objects/js-objects.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "src/codegen/signature.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/objects/js-function.h"
|
||||
#include "src/objects/objects.h"
|
||||
#include "src/wasm/struct-types.h"
|
||||
#include "src/wasm/value-type.h"
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "src/flags/flags.h"
|
||||
#include "src/heap/factory.h"
|
||||
#include "src/init/v8.h"
|
||||
#include "src/objects/js-function.h"
|
||||
#include "src/objects/objects.h"
|
||||
#include "src/zone/accounting-allocator.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user