11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_OBJECTS_JS_FUNCTION_INL_H_ 61cb0ef41Sopenharmony_ci#define V8_OBJECTS_JS_FUNCTION_INL_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "src/objects/js-function.h" 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci// Include other inline headers *after* including js-function.h, such that e.g. 111cb0ef41Sopenharmony_ci// the definition of JSFunction is available (and this comment prevents 121cb0ef41Sopenharmony_ci// clang-format from merging that include into the following ones). 131cb0ef41Sopenharmony_ci#include "src/diagnostics/code-tracer.h" 141cb0ef41Sopenharmony_ci#include "src/ic/ic.h" 151cb0ef41Sopenharmony_ci#include "src/init/bootstrapper.h" 161cb0ef41Sopenharmony_ci#include "src/objects/feedback-cell-inl.h" 171cb0ef41Sopenharmony_ci#include "src/objects/map-updater.h" 181cb0ef41Sopenharmony_ci#include "src/objects/shared-function-info-inl.h" 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci// Has to be the last include (doesn't have include guards): 211cb0ef41Sopenharmony_ci#include "src/objects/object-macros.h" 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_cinamespace v8 { 241cb0ef41Sopenharmony_cinamespace internal { 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci#include "torque-generated/src/objects/js-function-tq-inl.inc" 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ciTQ_OBJECT_CONSTRUCTORS_IMPL(JSFunctionOrBoundFunctionOrWrappedFunction) 291cb0ef41Sopenharmony_ciTQ_OBJECT_CONSTRUCTORS_IMPL(JSBoundFunction) 301cb0ef41Sopenharmony_ciTQ_OBJECT_CONSTRUCTORS_IMPL(JSWrappedFunction) 311cb0ef41Sopenharmony_ciTQ_OBJECT_CONSTRUCTORS_IMPL(JSFunction) 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset) 341cb0ef41Sopenharmony_ciRELEASE_ACQUIRE_ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, 351cb0ef41Sopenharmony_ci kFeedbackCellOffset) 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciFeedbackVector JSFunction::feedback_vector() const { 381cb0ef41Sopenharmony_ci DCHECK(has_feedback_vector()); 391cb0ef41Sopenharmony_ci return FeedbackVector::cast(raw_feedback_cell().value()); 401cb0ef41Sopenharmony_ci} 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciClosureFeedbackCellArray JSFunction::closure_feedback_cell_array() const { 431cb0ef41Sopenharmony_ci DCHECK(has_closure_feedback_cell_array()); 441cb0ef41Sopenharmony_ci return ClosureFeedbackCellArray::cast(raw_feedback_cell().value()); 451cb0ef41Sopenharmony_ci} 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_civoid JSFunction::reset_tiering_state() { 481cb0ef41Sopenharmony_ci DCHECK(has_feedback_vector()); 491cb0ef41Sopenharmony_ci feedback_vector().reset_tiering_state(); 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_cibool JSFunction::ChecksTieringState() { return code().checks_tiering_state(); } 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_civoid JSFunction::CompleteInobjectSlackTrackingIfActive() { 551cb0ef41Sopenharmony_ci if (!has_prototype_slot()) return; 561cb0ef41Sopenharmony_ci if (has_initial_map() && initial_map().IsInobjectSlackTrackingInProgress()) { 571cb0ef41Sopenharmony_ci MapUpdater::CompleteInobjectSlackTracking(GetIsolate(), initial_map()); 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci} 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_citemplate <typename IsolateT> 621cb0ef41Sopenharmony_ciAbstractCode JSFunction::abstract_code(IsolateT* isolate) { 631cb0ef41Sopenharmony_ci if (ActiveTierIsIgnition()) { 641cb0ef41Sopenharmony_ci return AbstractCode::cast(shared().GetBytecodeArray(isolate)); 651cb0ef41Sopenharmony_ci } else { 661cb0ef41Sopenharmony_ci return AbstractCode::cast(FromCodeT(code(kAcquireLoad))); 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ciint JSFunction::length() { return shared().length(); } 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ciACCESSORS_RELAXED(JSFunction, code, CodeT, kCodeOffset) 731cb0ef41Sopenharmony_ciRELEASE_ACQUIRE_ACCESSORS(JSFunction, code, CodeT, kCodeOffset) 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci#ifdef V8_EXTERNAL_CODE_SPACE 761cb0ef41Sopenharmony_civoid JSFunction::set_code(Code code, ReleaseStoreTag, WriteBarrierMode mode) { 771cb0ef41Sopenharmony_ci set_code(ToCodeT(code), kReleaseStore, mode); 781cb0ef41Sopenharmony_ci} 791cb0ef41Sopenharmony_ci#endif 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ciAddress JSFunction::code_entry_point() const { 821cb0ef41Sopenharmony_ci if (V8_EXTERNAL_CODE_SPACE_BOOL) { 831cb0ef41Sopenharmony_ci return CodeDataContainer::cast(code()).code_entry_point(); 841cb0ef41Sopenharmony_ci } else { 851cb0ef41Sopenharmony_ci return code().InstructionStart(); 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci// TODO(ishell): Why relaxed read but release store? 901cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, shared, SharedFunctionInfo) { 911cb0ef41Sopenharmony_ci return shared(cage_base, kRelaxedLoad); 921cb0ef41Sopenharmony_ci} 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ciDEF_RELAXED_GETTER(JSFunction, shared, SharedFunctionInfo) { 951cb0ef41Sopenharmony_ci return TaggedField<SharedFunctionInfo, 961cb0ef41Sopenharmony_ci kSharedFunctionInfoOffset>::Relaxed_Load(cage_base, *this); 971cb0ef41Sopenharmony_ci} 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_civoid JSFunction::set_shared(SharedFunctionInfo value, WriteBarrierMode mode) { 1001cb0ef41Sopenharmony_ci // Release semantics to support acquire read in NeedsResetDueToFlushedBytecode 1011cb0ef41Sopenharmony_ci RELEASE_WRITE_FIELD(*this, kSharedFunctionInfoOffset, value); 1021cb0ef41Sopenharmony_ci CONDITIONAL_WRITE_BARRIER(*this, kSharedFunctionInfoOffset, value, mode); 1031cb0ef41Sopenharmony_ci} 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ciTieringState JSFunction::tiering_state() const { 1061cb0ef41Sopenharmony_ci if (!has_feedback_vector()) return TieringState::kNone; 1071cb0ef41Sopenharmony_ci return feedback_vector().tiering_state(); 1081cb0ef41Sopenharmony_ci} 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_civoid JSFunction::set_tiering_state(TieringState state) { 1111cb0ef41Sopenharmony_ci DCHECK(has_feedback_vector()); 1121cb0ef41Sopenharmony_ci DCHECK(IsNone(state) || ChecksTieringState()); 1131cb0ef41Sopenharmony_ci feedback_vector().set_tiering_state(state); 1141cb0ef41Sopenharmony_ci} 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ciTieringState JSFunction::osr_tiering_state() { 1171cb0ef41Sopenharmony_ci DCHECK(has_feedback_vector()); 1181cb0ef41Sopenharmony_ci return feedback_vector().osr_tiering_state(); 1191cb0ef41Sopenharmony_ci} 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_civoid JSFunction::set_osr_tiering_state(TieringState marker) { 1221cb0ef41Sopenharmony_ci DCHECK(has_feedback_vector()); 1231cb0ef41Sopenharmony_ci feedback_vector().set_osr_tiering_state(marker); 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_cibool JSFunction::has_feedback_vector() const { 1271cb0ef41Sopenharmony_ci return shared().is_compiled() && 1281cb0ef41Sopenharmony_ci raw_feedback_cell().value().IsFeedbackVector(); 1291cb0ef41Sopenharmony_ci} 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_cibool JSFunction::has_closure_feedback_cell_array() const { 1321cb0ef41Sopenharmony_ci return shared().is_compiled() && 1331cb0ef41Sopenharmony_ci raw_feedback_cell().value().IsClosureFeedbackCellArray(); 1341cb0ef41Sopenharmony_ci} 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ciContext JSFunction::context() { 1371cb0ef41Sopenharmony_ci return TaggedField<Context, kContextOffset>::load(*this); 1381cb0ef41Sopenharmony_ci} 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ciDEF_RELAXED_GETTER(JSFunction, context, Context) { 1411cb0ef41Sopenharmony_ci return TaggedField<Context, kContextOffset>::Relaxed_Load(cage_base, *this); 1421cb0ef41Sopenharmony_ci} 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_cibool JSFunction::has_context() const { 1451cb0ef41Sopenharmony_ci return TaggedField<HeapObject, kContextOffset>::load(*this).IsContext(); 1461cb0ef41Sopenharmony_ci} 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ciJSGlobalProxy JSFunction::global_proxy() { return context().global_proxy(); } 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ciNativeContext JSFunction::native_context() { 1511cb0ef41Sopenharmony_ci return context().native_context(); 1521cb0ef41Sopenharmony_ci} 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ciRELEASE_ACQUIRE_ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, 1551cb0ef41Sopenharmony_ci HeapObject, kPrototypeOrInitialMapOffset, 1561cb0ef41Sopenharmony_ci map().has_prototype_slot()) 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, has_prototype_slot, bool) { 1591cb0ef41Sopenharmony_ci return map(cage_base).has_prototype_slot(); 1601cb0ef41Sopenharmony_ci} 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, initial_map, Map) { 1631cb0ef41Sopenharmony_ci return Map::cast(prototype_or_initial_map(cage_base, kAcquireLoad)); 1641cb0ef41Sopenharmony_ci} 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, has_initial_map, bool) { 1671cb0ef41Sopenharmony_ci DCHECK(has_prototype_slot(cage_base)); 1681cb0ef41Sopenharmony_ci return prototype_or_initial_map(cage_base, kAcquireLoad).IsMap(cage_base); 1691cb0ef41Sopenharmony_ci} 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, has_instance_prototype, bool) { 1721cb0ef41Sopenharmony_ci DCHECK(has_prototype_slot(cage_base)); 1731cb0ef41Sopenharmony_ci return has_initial_map(cage_base) || 1741cb0ef41Sopenharmony_ci !prototype_or_initial_map(cage_base, kAcquireLoad) 1751cb0ef41Sopenharmony_ci .IsTheHole(GetReadOnlyRoots(cage_base)); 1761cb0ef41Sopenharmony_ci} 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, has_prototype, bool) { 1791cb0ef41Sopenharmony_ci DCHECK(has_prototype_slot(cage_base)); 1801cb0ef41Sopenharmony_ci return map(cage_base).has_non_instance_prototype() || 1811cb0ef41Sopenharmony_ci has_instance_prototype(cage_base); 1821cb0ef41Sopenharmony_ci} 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, has_prototype_property, bool) { 1851cb0ef41Sopenharmony_ci return (has_prototype_slot(cage_base) && IsConstructor(cage_base)) || 1861cb0ef41Sopenharmony_ci IsGeneratorFunction(shared(cage_base).kind()); 1871cb0ef41Sopenharmony_ci} 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, PrototypeRequiresRuntimeLookup, bool) { 1901cb0ef41Sopenharmony_ci return !has_prototype_property(cage_base) || 1911cb0ef41Sopenharmony_ci map(cage_base).has_non_instance_prototype(); 1921cb0ef41Sopenharmony_ci} 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, instance_prototype, HeapObject) { 1951cb0ef41Sopenharmony_ci DCHECK(has_instance_prototype(cage_base)); 1961cb0ef41Sopenharmony_ci if (has_initial_map(cage_base)) { 1971cb0ef41Sopenharmony_ci return initial_map(cage_base).prototype(cage_base); 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci // When there is no initial map and the prototype is a JSReceiver, the 2001cb0ef41Sopenharmony_ci // initial map field is used for the prototype field. 2011cb0ef41Sopenharmony_ci return HeapObject::cast(prototype_or_initial_map(cage_base, kAcquireLoad)); 2021cb0ef41Sopenharmony_ci} 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ciDEF_GETTER(JSFunction, prototype, Object) { 2051cb0ef41Sopenharmony_ci DCHECK(has_prototype(cage_base)); 2061cb0ef41Sopenharmony_ci // If the function's prototype property has been set to a non-JSReceiver 2071cb0ef41Sopenharmony_ci // value, that value is stored in the constructor field of the map. 2081cb0ef41Sopenharmony_ci if (map(cage_base).has_non_instance_prototype()) { 2091cb0ef41Sopenharmony_ci Object prototype = map(cage_base).GetConstructor(cage_base); 2101cb0ef41Sopenharmony_ci // The map must have a prototype in that field, not a back pointer. 2111cb0ef41Sopenharmony_ci DCHECK(!prototype.IsMap(cage_base)); 2121cb0ef41Sopenharmony_ci DCHECK(!prototype.IsFunctionTemplateInfo(cage_base)); 2131cb0ef41Sopenharmony_ci return prototype; 2141cb0ef41Sopenharmony_ci } 2151cb0ef41Sopenharmony_ci return instance_prototype(cage_base); 2161cb0ef41Sopenharmony_ci} 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_cibool JSFunction::is_compiled() const { 2191cb0ef41Sopenharmony_ci return code(kAcquireLoad).builtin_id() != Builtin::kCompileLazy && 2201cb0ef41Sopenharmony_ci shared().is_compiled(); 2211cb0ef41Sopenharmony_ci} 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_cibool JSFunction::ShouldFlushBaselineCode( 2241cb0ef41Sopenharmony_ci base::EnumSet<CodeFlushMode> code_flush_mode) { 2251cb0ef41Sopenharmony_ci if (!IsBaselineCodeFlushingEnabled(code_flush_mode)) return false; 2261cb0ef41Sopenharmony_ci // Do a raw read for shared and code fields here since this function may be 2271cb0ef41Sopenharmony_ci // called on a concurrent thread. JSFunction itself should be fully 2281cb0ef41Sopenharmony_ci // initialized here but the SharedFunctionInfo, Code objects may not be 2291cb0ef41Sopenharmony_ci // initialized. We read using acquire loads to defend against that. 2301cb0ef41Sopenharmony_ci Object maybe_shared = ACQUIRE_READ_FIELD(*this, kSharedFunctionInfoOffset); 2311cb0ef41Sopenharmony_ci if (!maybe_shared.IsSharedFunctionInfo()) return false; 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci // See crbug.com/v8/11972 for more details on acquire / release semantics for 2341cb0ef41Sopenharmony_ci // code field. We don't use release stores when copying code pointers from 2351cb0ef41Sopenharmony_ci // SFI / FV to JSFunction but it is safe in practice. 2361cb0ef41Sopenharmony_ci Object maybe_code = ACQUIRE_READ_FIELD(*this, kCodeOffset); 2371cb0ef41Sopenharmony_ci if (!maybe_code.IsCodeT()) return false; 2381cb0ef41Sopenharmony_ci CodeT code = CodeT::cast(maybe_code); 2391cb0ef41Sopenharmony_ci if (code.kind() != CodeKind::BASELINE) return false; 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci SharedFunctionInfo shared = SharedFunctionInfo::cast(maybe_shared); 2421cb0ef41Sopenharmony_ci return shared.ShouldFlushCode(code_flush_mode); 2431cb0ef41Sopenharmony_ci} 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_cibool JSFunction::NeedsResetDueToFlushedBytecode() { 2461cb0ef41Sopenharmony_ci // Do a raw read for shared and code fields here since this function may be 2471cb0ef41Sopenharmony_ci // called on a concurrent thread. JSFunction itself should be fully 2481cb0ef41Sopenharmony_ci // initialized here but the SharedFunctionInfo, Code objects may not be 2491cb0ef41Sopenharmony_ci // initialized. We read using acquire loads to defend against that. 2501cb0ef41Sopenharmony_ci Object maybe_shared = ACQUIRE_READ_FIELD(*this, kSharedFunctionInfoOffset); 2511cb0ef41Sopenharmony_ci if (!maybe_shared.IsSharedFunctionInfo()) return false; 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci Object maybe_code = ACQUIRE_READ_FIELD(*this, kCodeOffset); 2541cb0ef41Sopenharmony_ci if (!maybe_code.IsCodeT()) return false; 2551cb0ef41Sopenharmony_ci CodeT code = CodeT::cast(maybe_code); 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci SharedFunctionInfo shared = SharedFunctionInfo::cast(maybe_shared); 2581cb0ef41Sopenharmony_ci return !shared.is_compiled() && code.builtin_id() != Builtin::kCompileLazy; 2591cb0ef41Sopenharmony_ci} 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_cibool JSFunction::NeedsResetDueToFlushedBaselineCode() { 2621cb0ef41Sopenharmony_ci return code().kind() == CodeKind::BASELINE && !shared().HasBaselineCode(); 2631cb0ef41Sopenharmony_ci} 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_civoid JSFunction::ResetIfCodeFlushed( 2661cb0ef41Sopenharmony_ci base::Optional<std::function<void(HeapObject object, ObjectSlot slot, 2671cb0ef41Sopenharmony_ci HeapObject target)>> 2681cb0ef41Sopenharmony_ci gc_notify_updated_slot) { 2691cb0ef41Sopenharmony_ci const bool kBytecodeCanFlush = FLAG_flush_bytecode || FLAG_stress_snapshot; 2701cb0ef41Sopenharmony_ci const bool kBaselineCodeCanFlush = 2711cb0ef41Sopenharmony_ci FLAG_flush_baseline_code || FLAG_stress_snapshot; 2721cb0ef41Sopenharmony_ci if (!kBytecodeCanFlush && !kBaselineCodeCanFlush) return; 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci DCHECK_IMPLIES(NeedsResetDueToFlushedBytecode(), kBytecodeCanFlush); 2751cb0ef41Sopenharmony_ci if (kBytecodeCanFlush && NeedsResetDueToFlushedBytecode()) { 2761cb0ef41Sopenharmony_ci // Bytecode was flushed and function is now uncompiled, reset JSFunction 2771cb0ef41Sopenharmony_ci // by setting code to CompileLazy and clearing the feedback vector. 2781cb0ef41Sopenharmony_ci set_code(*BUILTIN_CODE(GetIsolate(), CompileLazy)); 2791cb0ef41Sopenharmony_ci raw_feedback_cell().reset_feedback_vector(gc_notify_updated_slot); 2801cb0ef41Sopenharmony_ci return; 2811cb0ef41Sopenharmony_ci } 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci DCHECK_IMPLIES(NeedsResetDueToFlushedBaselineCode(), kBaselineCodeCanFlush); 2841cb0ef41Sopenharmony_ci if (kBaselineCodeCanFlush && NeedsResetDueToFlushedBaselineCode()) { 2851cb0ef41Sopenharmony_ci // Flush baseline code from the closure if required 2861cb0ef41Sopenharmony_ci set_code(*BUILTIN_CODE(GetIsolate(), InterpreterEntryTrampoline)); 2871cb0ef41Sopenharmony_ci } 2881cb0ef41Sopenharmony_ci} 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci} // namespace internal 2911cb0ef41Sopenharmony_ci} // namespace v8 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci#include "src/objects/object-macros-undef.h" 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci#endif // V8_OBJECTS_JS_FUNCTION_INL_H_ 296