diff --git a/BUILD.gn b/BUILD.gn index e3f9e5aab6..920ad3b810 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1063,6 +1063,7 @@ action("postmortem-metadata") { "src/objects/js-array-buffer-inl.h", "src/objects/js-array.h", "src/objects/js-array-inl.h", + "src/objects/js-function-inl.h", "src/objects/js-function.cc", "src/objects/js-function.h", "src/objects/js-objects.cc", @@ -2874,6 +2875,7 @@ 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", diff --git a/src/codegen/compiler.cc b/src/codegen/compiler.cc index d64cb50c0b..b894679b0b 100644 --- a/src/codegen/compiler.cc +++ b/src/codegen/compiler.cc @@ -40,6 +40,7 @@ #include "src/interpreter/interpreter.h" #include "src/logging/log-inl.h" #include "src/objects/feedback-cell-inl.h" +#include "src/objects/js-function-inl.h" #include "src/objects/map.h" #include "src/objects/object-list-macros.h" #include "src/objects/shared-function-info.h" diff --git a/src/compiler/compilation-dependencies.cc b/src/compiler/compilation-dependencies.cc index 5b78e33000..263a5a5f1e 100644 --- a/src/compiler/compilation-dependencies.cc +++ b/src/compiler/compilation-dependencies.cc @@ -8,6 +8,7 @@ #include "src/execution/protectors.h" #include "src/handles/handles-inl.h" #include "src/objects/allocation-site-inl.h" +#include "src/objects/js-function-inl.h" #include "src/objects/objects-inl.h" #include "src/zone/zone-handle-set.h" diff --git a/src/objects/contexts-inl.h b/src/objects/contexts-inl.h index aeff21427d..9bd30530c9 100644 --- a/src/objects/contexts-inl.h +++ b/src/objects/contexts-inl.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" diff --git a/src/objects/js-function-inl.h b/src/objects/js-function-inl.h new file mode 100644 index 0000000000..606deb290a --- /dev/null +++ b/src/objects/js-function-inl.h @@ -0,0 +1,304 @@ +// 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/codegen/compiler.h" +#include "src/diagnostics/code-tracer.h" +#include "src/heap/heap-inl.h" +#include "src/ic/ic.h" +#include "src/init/bootstrapper.h" +#include "src/objects/feedback-cell-inl.h" +#include "src/objects/js-function.h" +#include "src/strings/string-builder-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()); +} + +bool JSFunction::HasOptimizationMarker() { + return has_feedback_vector() && feedback_vector().has_optimization_marker(); +} + +void JSFunction::ClearOptimizationMarker() { + DCHECK(has_feedback_vector()); + feedback_vector().ClearOptimizationMarker(); +} + +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; +} + +void JSFunction::MarkForOptimization(ConcurrencyMode mode) { + Isolate* isolate = GetIsolate(); + if (!isolate->concurrent_recompilation_enabled() || + isolate->bootstrapper()->IsActive()) { + mode = ConcurrencyMode::kNotConcurrent; + } + + DCHECK(!is_compiled() || ActiveTierIsIgnition() || ActiveTierIsNCI()); + DCHECK(!ActiveTierIsTurbofan()); + DCHECK(shared().IsInterpreted()); + 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); +} + +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 (ActiveTierIsIgnition()) { + 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(!ActiveTierIsTurbofan()); + + 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::load(*this); +} + +bool JSFunction::has_context() const { + return TaggedField::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> + 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_ diff --git a/src/objects/js-function.cc b/src/objects/js-function.cc index 5b05a5f945..6e83273e8f 100644 --- a/src/objects/js-function.cc +++ b/src/objects/js-function.cc @@ -18,24 +18,6 @@ namespace v8 { namespace internal { -TQ_OBJECT_CONSTRUCTORS_IMPL_NONINLINE(JSFunctionOrBoundFunction) -TQ_OBJECT_CONSTRUCTORS_IMPL_NONINLINE(JSBoundFunction) -OBJECT_CONSTRUCTORS_IMPL_NONINLINE(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()); -} - CodeKinds JSFunction::GetAttachedCodeKinds() const { CodeKinds result; @@ -167,230 +149,6 @@ bool JSFunction::CanDiscardCompiled() const { return (result & kJSFunctionCodeKindsMask) != 0; } -bool JSFunction::HasOptimizationMarker() { - return has_feedback_vector() && feedback_vector().has_optimization_marker(); -} - -void JSFunction::ClearOptimizationMarker() { - DCHECK(has_feedback_vector()); - feedback_vector().ClearOptimizationMarker(); -} - -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 (ActiveTierIsIgnition()) { - 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(!ActiveTierIsTurbofan()); - - 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::load(*this); -} - -bool JSFunction::has_context() const { - return TaggedField::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> - 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); - } -} - // static MaybeHandle JSBoundFunction::GetFunctionRealm( Handle function) { @@ -473,40 +231,6 @@ Handle JSFunction::GetFunctionRealm( 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() || ActiveTierIsIgnition() || ActiveTierIsNCI()); - DCHECK(!ActiveTierIsTurbofan()); - DCHECK(shared().IsInterpreted()); - 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 function) { Isolate* const isolate = function->GetIsolate(); diff --git a/src/objects/js-function.h b/src/objects/js-function.h index 06b611ece4..917d5a6d0a 100644 --- a/src/objects/js-function.h +++ b/src/objects/js-function.h @@ -24,7 +24,7 @@ class JSFunctionOrBoundFunction JSObject> { public: STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize); - TQ_OBJECT_CONSTRUCTORS_NONINLINE(JSFunctionOrBoundFunction) + TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction) }; // JSBoundFunction describes a bound function exotic object. @@ -47,18 +47,18 @@ class JSBoundFunction // to ES6 section 19.2.3.5 Function.prototype.toString ( ). static Handle ToString(Handle function); - TQ_OBJECT_CONSTRUCTORS_NONINLINE(JSBoundFunction) + TQ_OBJECT_CONSTRUCTORS(JSBoundFunction) }; // JSFunction describes JavaScript functions. class JSFunction : public JSFunctionOrBoundFunction { public: // [prototype_or_initial_map]: - DECL_ACCESSORS_NONINLINE(prototype_or_initial_map, HeapObject) + DECL_ACCESSORS(prototype_or_initial_map, HeapObject) // [shared]: The information about the function that // can be shared by instances. - DECL_ACCESSORS_NONINLINE(shared, SharedFunctionInfo) + DECL_ACCESSORS(shared, SharedFunctionInfo) static const int kLengthDescriptorIndex = 0; static const int kNameDescriptorIndex = 1; @@ -68,12 +68,12 @@ class JSFunction : public JSFunctionOrBoundFunction { static const int kMinDescriptorsForFastBind = 2; // [context]: The context for this function. - V8_EXPORT_PRIVATE Context context(); - bool has_context() const; - void set_context(HeapObject context); - JSGlobalProxy global_proxy(); - V8_EXPORT_PRIVATE NativeContext native_context(); - int length(); + 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 GetName(Isolate* isolate, Handle function); static Handle GetFunctionRealm(Handle function); @@ -82,13 +82,13 @@ class JSFunction : public JSFunctionOrBoundFunction { // 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. - V8_EXPORT_PRIVATE Code code() const; - V8_EXPORT_PRIVATE void set_code(Code code); - void set_code_no_write_barrier(Code code); + 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. - V8_EXPORT_PRIVATE AbstractCode abstract_code(); + inline AbstractCode abstract_code(); // The predicates for querying code kinds related to this function have // specific terminology: @@ -125,30 +125,30 @@ class JSFunction : public JSFunctionOrBoundFunction { // Tells whether or not this function checks its optimization marker in its // feedback vector. - bool ChecksOptimizationMarker(); + inline bool ChecksOptimizationMarker(); // Tells whether or not this function has a (non-zero) optimization marker. - bool HasOptimizationMarker(); + inline bool HasOptimizationMarker(); // Mark this function for lazy recompilation. The function will be recompiled // the next time it is executed. - void MarkForOptimization(ConcurrencyMode mode); + inline void MarkForOptimization(ConcurrencyMode mode); // Tells whether or not the function is already marked for lazy recompilation. - bool IsMarkedForOptimization(); - bool IsMarkedForConcurrentOptimization(); + inline bool IsMarkedForOptimization(); + inline bool IsMarkedForConcurrentOptimization(); // Tells whether or not the function is on the concurrent recompilation queue. - bool IsInOptimizationQueue(); + inline bool IsInOptimizationQueue(); // Clears the optimized code slot in the function's feedback vector. - void ClearOptimizedCodeSlot(const char* reason); + inline void ClearOptimizedCodeSlot(const char* reason); // Sets the optimization marker in the function's feedback vector. - void SetOptimizationMarker(OptimizationMarker marker); + inline void SetOptimizationMarker(OptimizationMarker marker); // Clears the optimization marker in the function's feedback vector. - void ClearOptimizationMarker(); + 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 @@ -156,28 +156,28 @@ class JSFunction : public JSFunctionOrBoundFunction { int ComputeInstanceSizeWithMinSlack(Isolate* isolate); // Completes inobject slack tracking on initial map if it is active. - void CompleteInobjectSlackTrackingIfActive(); + 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_NONINLINE(raw_feedback_cell, FeedbackCell) + 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. - V8_EXPORT_PRIVATE FeedbackVector feedback_vector() const; - V8_EXPORT_PRIVATE bool has_feedback_vector() const; + inline FeedbackVector feedback_vector() const; + inline bool has_feedback_vector() const; V8_EXPORT_PRIVATE static void EnsureFeedbackVector( Handle function, IsCompiledScope* compiled_scope); - // Functions related to clousre feedback cell array that holds feedback cells + // Functions related to closure 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. - V8_EXPORT_PRIVATE bool has_closure_feedback_cell_array() const; - ClosureFeedbackCellArray closure_feedback_cell_array() const; + inline bool has_closure_feedback_cell_array() const; + inline ClosureFeedbackCellArray closure_feedback_cell_array() const; static void EnsureClosureFeedbackCellArray(Handle function); // Initializes the feedback cell of |function|. In lite mode, this would be @@ -191,20 +191,20 @@ class JSFunction : public JSFunctionOrBoundFunction { void ClearTypeFeedbackInfo(); // Resets function to clear compiled data after bytecode has been flushed. - bool NeedsResetDueToFlushedBytecode(); - void ResetIfBytecodeFlushed( + inline bool NeedsResetDueToFlushedBytecode(); + inline void ResetIfBytecodeFlushed( base::Optional> gc_notify_updated_slot = base::nullopt); - DECL_GETTER_NONINLINE(has_prototype_slot, bool) + DECL_GETTER(has_prototype_slot, bool) // The initial map for an object created by this constructor. - DECL_GETTER_NONINLINE(initial_map, Map) + DECL_GETTER(initial_map, Map) static void SetInitialMap(Handle function, Handle map, Handle prototype); - DECL_GETTER_NONINLINE(has_initial_map, bool) + DECL_GETTER(has_initial_map, bool) V8_EXPORT_PRIVATE static void EnsureHasInitialMap( Handle function); @@ -219,16 +219,16 @@ class JSFunction : public JSFunctionOrBoundFunction { // 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_NONINLINE(has_prototype, bool) - DECL_GETTER_NONINLINE(has_instance_prototype, bool) - DECL_GETTER_NONINLINE(prototype, Object) - DECL_GETTER_NONINLINE(instance_prototype, HeapObject) - DECL_GETTER_NONINLINE(has_prototype_property, bool) - DECL_GETTER_NONINLINE(PrototypeRequiresRuntimeLookup, bool) + 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 function, Handle value); // Returns if this function has been compiled to native code yet. - V8_EXPORT_PRIVATE bool is_compiled() const; + inline bool is_compiled() const; static int GetHeaderSize(bool function_has_prototype_slot) { return function_has_prototype_slot ? JSFunction::kSizeWithPrototype @@ -238,7 +238,7 @@ class JSFunction : public JSFunctionOrBoundFunction { // Prints the name of the function using PrintF. void PrintName(FILE* out = stdout); - DECL_CAST_NONINLINE(JSFunction) + DECL_CAST(JSFunction) // Calculate the instance size and in-object properties count. // {CalculateExpectedNofProperties} can trigger compilation. @@ -311,7 +311,7 @@ class JSFunction : public JSFunctionOrBoundFunction { static constexpr int kSizeWithoutPrototype = kPrototypeOrInitialMapOffset; static constexpr int kSizeWithPrototype = FieldOffsets::kHeaderSize; - OBJECT_CONSTRUCTORS_NONINLINE(JSFunction, JSFunctionOrBoundFunction); + OBJECT_CONSTRUCTORS(JSFunction, JSFunctionOrBoundFunction); }; } // namespace internal diff --git a/src/objects/map-inl.h b/src/objects/map-inl.h index 0e0adc2092..7a4971896d 100644 --- a/src/objects/map-inl.h +++ b/src/objects/map-inl.h @@ -11,6 +11,7 @@ #include "src/objects/descriptor-array-inl.h" #include "src/objects/field-type.h" #include "src/objects/instance-type-inl.h" +#include "src/objects/js-function-inl.h" #include "src/objects/layout-descriptor-inl.h" #include "src/objects/map.h" #include "src/objects/objects-inl.h" diff --git a/src/objects/object-macros-undef.h b/src/objects/object-macros-undef.h index 508797ce9b..b96c03c00f 100644 --- a/src/objects/object-macros-undef.h +++ b/src/objects/object-macros-undef.h @@ -81,10 +81,3 @@ #undef DEFINE_DEOPT_ENTRY_ACCESSORS #undef TQ_OBJECT_CONSTRUCTORS #undef TQ_OBJECT_CONSTRUCTORS_IMPL -#undef OBJECT_CONSTRUCTORS_NONINLINE -#undef OBJECT_CONSTRUCTORS_IMPL_NONINLINE -#undef DECL_GETTER_NONINLINE -#undef DECL_ACCESSORS_NONINLINE -#undef DECL_CAST_NONINLINE -#undef TQ_OBJECT_CONSTRUCTORS_NONINLINE -#undef TQ_OBJECT_CONSTRUCTORS_IMPL_NONINLINE diff --git a/src/objects/object-macros.h b/src/objects/object-macros.h index c4446f5ac4..b4fc7717fe 100644 --- a/src/objects/object-macros.h +++ b/src/objects/object-macros.h @@ -16,19 +16,6 @@ #include "src/base/memory.h" -// TODO(v8:10749): When we've had a chance to collect performance impact, -// either move towards using _NONINLINE versions everywhere, or revert back to -// inline use and remove _NONINLINE macros. -#define OBJECT_CONSTRUCTORS_NONINLINE(Type, ...) \ - public: \ - constexpr Type() : __VA_ARGS__() {} \ - \ - protected: \ - template \ - friend class TaggedField; \ - \ - V8_EXPORT_PRIVATE explicit Type(Address ptr) - // Since this changes visibility, it should always be last in a class // definition. #define OBJECT_CONSTRUCTORS(Type, ...) \ @@ -41,9 +28,6 @@ \ explicit inline Type(Address ptr) -#define OBJECT_CONSTRUCTORS_IMPL_NONINLINE(Type, Super) \ - Type::Type(Address ptr) : Super(ptr) { SLOW_DCHECK(Is##Type()); } - #define OBJECT_CONSTRUCTORS_IMPL(Type, Super) \ inline Type::Type(Address ptr) : Super(ptr) { SLOW_DCHECK(Is##Type()); } // In these cases, we don't have our own instance type to check, so check the @@ -100,10 +84,6 @@ inline type name() const; \ inline type name(const Isolate* isolate) const; -#define DECL_GETTER_NONINLINE(name, type) \ - V8_EXPORT_PRIVATE type name() const; \ - V8_EXPORT_PRIVATE type name(const Isolate* isolate) const; - #define DEF_GETTER(holder, name, type) \ type holder::name() const { \ const Isolate* isolate = GetIsolateForPtrCompr(*this); \ @@ -116,23 +96,12 @@ inline void set_##name(type value, \ WriteBarrierMode mode = UPDATE_WRITE_BARRIER); -#define DECL_ACCESSORS_NONINLINE(name, type) \ - DECL_GETTER_NONINLINE(name, type) \ - V8_EXPORT_PRIVATE void set_##name( \ - type value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - // TODO(solanes, neis): Unify naming for synchronized accessor uses. #define DECL_SYNCHRONIZED_ACCESSORS(name, type) \ DECL_GETTER(synchronized_##name, type) \ inline void set_synchronized_##name( \ type value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); -#define DECL_CAST_NONINLINE(Type) \ - V8_EXPORT_PRIVATE static Type cast(Object object); \ - inline static Type unchecked_cast(Object object) { \ - return bit_cast(object); \ - } - #define DECL_CAST(Type) \ V8_INLINE static Type cast(Object object); \ V8_INLINE static Type unchecked_cast(Object object) { \ @@ -519,20 +488,6 @@ set(IndexForEntry(i) + k##name##Offset, value); \ } -#define TQ_OBJECT_CONSTRUCTORS_NONINLINE(Type) \ - public: \ - constexpr Type() = default; \ - \ - protected: \ - template \ - friend class TaggedField; \ - \ - V8_EXPORT_PRIVATE explicit Type(Address ptr); \ - friend class TorqueGenerated##Type; - -#define TQ_OBJECT_CONSTRUCTORS_IMPL_NONINLINE(Type) \ - Type::Type(Address ptr) : TorqueGenerated##Type(ptr) {} - #define TQ_OBJECT_CONSTRUCTORS(Type) \ public: \ constexpr Type() = default; \ diff --git a/src/runtime/runtime-test.cc b/src/runtime/runtime-test.cc index 9dc87c4b5c..66e522e72e 100644 --- a/src/runtime/runtime-test.cc +++ b/src/runtime/runtime-test.cc @@ -26,6 +26,7 @@ #include "src/logging/counters.h" #include "src/objects/heap-object-inl.h" #include "src/objects/js-array-inl.h" +#include "src/objects/js-function-inl.h" #include "src/objects/js-regexp-inl.h" #include "src/objects/smi.h" #include "src/snapshot/snapshot.h" diff --git a/src/wasm/wasm-objects-inl.h b/src/wasm/wasm-objects-inl.h index 4ea708dc21..8a8d47cb82 100644 --- a/src/wasm/wasm-objects-inl.h +++ b/src/wasm/wasm-objects-inl.h @@ -13,6 +13,7 @@ #include "src/objects/foreign-inl.h" #include "src/objects/heap-number-inl.h" #include "src/objects/js-array-buffer-inl.h" +#include "src/objects/js-function-inl.h" #include "src/objects/js-objects-inl.h" #include "src/objects/managed.h" #include "src/objects/oddball-inl.h"