1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_OBJECTS_JS_FUNCTION_H_ 6 #define V8_OBJECTS_JS_FUNCTION_H_ 7 8 #include "src/objects/code-kind.h" 9 #include "src/objects/js-objects.h" 10 11 // Has to be the last include (doesn't have include guards): 12 #include "src/objects/object-macros.h" 13 14 namespace v8 { 15 namespace internal { 16 17 #include "torque-generated/src/objects/js-function-tq.inc" 18 19 // An abstract superclass for classes representing JavaScript function values. 20 // It doesn't carry any functionality but allows function classes to be 21 // identified in the type system. 22 class JSFunctionOrBoundFunctionOrWrappedFunction 23 : public TorqueGeneratedJSFunctionOrBoundFunctionOrWrappedFunction< 24 JSFunctionOrBoundFunctionOrWrappedFunction, JSObject> { 25 public: 26 static const int kLengthDescriptorIndex = 0; 27 static const int kNameDescriptorIndex = 1; 28 29 // https://tc39.es/proposal-shadowrealm/#sec-copynameandlength 30 static Maybe<bool> CopyNameAndLength( 31 Isolate* isolate, 32 Handle<JSFunctionOrBoundFunctionOrWrappedFunction> function, 33 Handle<JSReceiver> target, Handle<String> prefix, int arg_count); 34 35 STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize); 36 TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunctionOrWrappedFunction) 37 }; 38 39 // JSBoundFunction describes a bound function exotic object. 40 class JSBoundFunction 41 : public TorqueGeneratedJSBoundFunction< 42 JSBoundFunction, JSFunctionOrBoundFunctionOrWrappedFunction> { 43 public: 44 static MaybeHandle<String> GetName(Isolate* isolate, 45 Handle<JSBoundFunction> function); 46 static Maybe<int> GetLength(Isolate* isolate, 47 Handle<JSBoundFunction> function); 48 49 // Dispatched behavior. 50 DECL_PRINTER(JSBoundFunction) 51 DECL_VERIFIER(JSBoundFunction) 52 53 // The bound function's string representation implemented according 54 // to ES6 section 19.2.3.5 Function.prototype.toString ( ). 55 static Handle<String> ToString(Handle<JSBoundFunction> function); 56 57 TQ_OBJECT_CONSTRUCTORS(JSBoundFunction) 58 }; 59 60 // JSWrappedFunction describes a wrapped function exotic object. 61 class JSWrappedFunction 62 : public TorqueGeneratedJSWrappedFunction< 63 JSWrappedFunction, JSFunctionOrBoundFunctionOrWrappedFunction> { 64 public: 65 static MaybeHandle<String> GetName(Isolate* isolate, 66 Handle<JSWrappedFunction> function); 67 static Maybe<int> GetLength(Isolate* isolate, 68 Handle<JSWrappedFunction> function); 69 // https://tc39.es/proposal-shadowrealm/#sec-wrappedfunctioncreate 70 static MaybeHandle<Object> Create(Isolate* isolate, 71 Handle<NativeContext> creation_context, 72 Handle<JSReceiver> value); 73 74 // Dispatched behavior. 75 DECL_PRINTER(JSWrappedFunction) 76 DECL_VERIFIER(JSWrappedFunction) 77 78 // The wrapped function's string representation implemented according 79 // to ES6 section 19.2.3.5 Function.prototype.toString ( ). 80 static Handle<String> ToString(Handle<JSWrappedFunction> function); 81 82 TQ_OBJECT_CONSTRUCTORS(JSWrappedFunction) 83 }; 84 85 // JSFunction describes JavaScript functions. 86 class JSFunction : public TorqueGeneratedJSFunction< 87 JSFunction, JSFunctionOrBoundFunctionOrWrappedFunction> { 88 public: 89 // [prototype_or_initial_map]: 90 DECL_RELEASE_ACQUIRE_ACCESSORS(prototype_or_initial_map, HeapObject) 91 92 // [shared]: The information about the function that can be shared by 93 // instances. 94 DECL_ACCESSORS(shared, SharedFunctionInfo) 95 DECL_RELAXED_GETTER(shared, SharedFunctionInfo) 96 97 // Fast binding requires length and name accessors. 98 static const int kMinDescriptorsForFastBindAndWrap = 2; 99 100 // [context]: The context for this function. 101 inline Context context(); 102 DECL_RELAXED_GETTER(context, Context) 103 inline bool has_context() const; 104 inline JSGlobalProxy global_proxy(); 105 inline NativeContext native_context(); 106 inline int length(); 107 108 static Handle<String> GetName(Isolate* isolate, Handle<JSFunction> function); 109 110 // [code]: The generated code object for this function. Executed 111 // when the function is invoked, e.g. foo() or new foo(). See 112 // [[Call]] and [[Construct]] description in ECMA-262, section 113 // 8.6.2, page 27. 114 // Release/Acquire accessors are used when storing a newly-created 115 // optimized code object, or when reading from the background thread. 116 // Storing a builtin doesn't require release semantics because these objects 117 // are fully initialized. 118 DECL_ACCESSORS(code, CodeT) 119 DECL_RELEASE_ACQUIRE_ACCESSORS(code, CodeT) 120 #ifdef V8_EXTERNAL_CODE_SPACE 121 // Convenient overloads to avoid unnecessary Code <-> CodeT conversions. 122 // TODO(v8:11880): remove once |code| accessors are migrated to CodeT. 123 inline void set_code(Code code, ReleaseStoreTag, 124 WriteBarrierMode mode = UPDATE_WRITE_BARRIER); 125 #endif 126 127 // Returns the address of the function code's instruction start. 128 inline Address code_entry_point() const; 129 130 // Get the abstract code associated with the function, which will either be 131 // a Code object or a BytecodeArray. 132 template <typename IsolateT> 133 inline AbstractCode abstract_code(IsolateT* isolate); 134 135 // The predicates for querying code kinds related to this function have 136 // specific terminology: 137 // 138 // - Attached: all code kinds that are directly attached to this JSFunction 139 // object. 140 // - Available: all code kinds that are either attached or available through 141 // indirect means such as the feedback vector's optimized code cache. 142 // - Active: the single code kind that would be executed if this function 143 // were called in its current state. Note that there may not be an active 144 // code kind if the function is not compiled. Also, asm/wasm functions are 145 // currently not supported. 146 // 147 // Note: code objects that are marked_for_deoptimization are not part of the 148 // attached/available/active sets. This is because the JSFunction might have 149 // been already deoptimized but its code() still needs to be unlinked, which 150 // will happen on its next activation. 151 152 // True, iff any generated code kind is attached/available to this function. 153 V8_EXPORT_PRIVATE bool HasAttachedOptimizedCode() const; 154 bool HasAvailableOptimizedCode() const; 155 156 bool HasAttachedCodeKind(CodeKind kind) const; 157 bool HasAvailableCodeKind(CodeKind kind) const; 158 159 base::Optional<CodeKind> GetActiveTier() const; 160 V8_EXPORT_PRIVATE bool ActiveTierIsIgnition() const; 161 bool ActiveTierIsBaseline() const; 162 bool ActiveTierIsMaglev() const; 163 bool ActiveTierIsTurbofan() const; 164 165 // Similar to SharedFunctionInfo::CanDiscardCompiled. Returns true, if the 166 // attached code can be recreated at a later point by replacing it with 167 // CompileLazy. 168 bool CanDiscardCompiled() const; 169 170 // Tells whether function's code object checks its tiering state (some code 171 // kinds, e.g. TURBOFAN, ignore the tiering state). 172 inline bool ChecksTieringState(); 173 174 inline TieringState tiering_state() const; 175 inline void set_tiering_state(TieringState state); 176 inline void reset_tiering_state(); 177 178 // Mark this function for lazy recompilation. The function will be recompiled 179 // the next time it is executed. 180 void MarkForOptimization(Isolate* isolate, CodeKind target_kind, 181 ConcurrencyMode mode); 182 183 inline TieringState osr_tiering_state(); 184 inline void set_osr_tiering_state(TieringState marker); 185 186 // Sets the interrupt budget based on whether the function has a feedback 187 // vector and any optimized code. 188 void SetInterruptBudget(Isolate* isolate); 189 190 // If slack tracking is active, it computes instance size of the initial map 191 // with minimum permissible object slack. If it is not active, it simply 192 // returns the initial map's instance size. 193 int ComputeInstanceSizeWithMinSlack(Isolate* isolate); 194 195 // Completes inobject slack tracking on initial map if it is active. 196 inline void CompleteInobjectSlackTrackingIfActive(); 197 198 // [raw_feedback_cell]: Gives raw access to the FeedbackCell used to hold the 199 /// FeedbackVector eventually. Generally this shouldn't be used to get the 200 // feedback_vector, instead use feedback_vector() which correctly deals with 201 // the JSFunction's bytecode being flushed. 202 DECL_ACCESSORS(raw_feedback_cell, FeedbackCell) 203 204 // [raw_feedback_cell] (synchronized version) When this is initialized from a 205 // newly allocated object (instead of a root sentinel), it should 206 // be written with release store semantics. 207 DECL_RELEASE_ACQUIRE_ACCESSORS(raw_feedback_cell, FeedbackCell) 208 209 // Functions related to feedback vector. feedback_vector() can be used once 210 // the function has feedback vectors allocated. feedback vectors may not be 211 // available after compile when lazily allocating feedback vectors. 212 inline FeedbackVector feedback_vector() const; 213 inline bool has_feedback_vector() const; 214 V8_EXPORT_PRIVATE static void EnsureFeedbackVector( 215 Isolate* isolate, Handle<JSFunction> function, 216 IsCompiledScope* compiled_scope); 217 static void CreateAndAttachFeedbackVector(Isolate* isolate, 218 Handle<JSFunction> function, 219 IsCompiledScope* compiled_scope); 220 221 // Functions related to closure feedback cell array that holds feedback cells 222 // used to create closures from this function. We allocate closure feedback 223 // cell arrays after compile, when we want to allocate feedback vectors 224 // lazily. 225 inline bool has_closure_feedback_cell_array() const; 226 inline ClosureFeedbackCellArray closure_feedback_cell_array() const; 227 static void EnsureClosureFeedbackCellArray( 228 Handle<JSFunction> function, bool reset_budget_for_feedback_allocation); 229 230 // Initializes the feedback cell of |function|. In lite mode, this would be 231 // initialized to the closure feedback cell array that holds the feedback 232 // cells for create closure calls from this function. In the regular mode, 233 // this allocates feedback vector. 234 static void InitializeFeedbackCell(Handle<JSFunction> function, 235 IsCompiledScope* compiled_scope, 236 bool reset_budget_for_feedback_allocation); 237 238 // Unconditionally clear the type feedback vector. 239 void ClearTypeFeedbackInfo(); 240 241 // Resets function to clear compiled data after bytecode has been flushed. 242 inline bool NeedsResetDueToFlushedBytecode(); 243 inline void ResetIfCodeFlushed( 244 base::Optional<std::function<void(HeapObject object, ObjectSlot slot, 245 HeapObject target)>> 246 gc_notify_updated_slot = base::nullopt); 247 248 // Returns if the closure's code field has to be updated because it has 249 // stale baseline code. 250 inline bool NeedsResetDueToFlushedBaselineCode(); 251 252 // Returns if baseline code is a candidate for flushing. This method is called 253 // from concurrent marking so we should be careful when accessing data fields. 254 inline bool ShouldFlushBaselineCode( 255 base::EnumSet<CodeFlushMode> code_flush_mode); 256 257 DECL_GETTER(has_prototype_slot, bool) 258 259 // The initial map for an object created by this constructor. 260 DECL_GETTER(initial_map, Map) 261 262 static void SetInitialMap(Isolate* isolate, Handle<JSFunction> function, 263 Handle<Map> map, Handle<HeapObject> prototype); 264 static void SetInitialMap(Isolate* isolate, Handle<JSFunction> function, 265 Handle<Map> map, Handle<HeapObject> prototype, 266 Handle<JSFunction> constructor); 267 DECL_GETTER(has_initial_map, bool) 268 V8_EXPORT_PRIVATE static void EnsureHasInitialMap( 269 Handle<JSFunction> function); 270 271 // Creates a map that matches the constructor's initial map, but with 272 // [[prototype]] being new.target.prototype. Because new.target can be a 273 // JSProxy, this can call back into JavaScript. 274 V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle<Map> GetDerivedMap( 275 Isolate* isolate, Handle<JSFunction> constructor, 276 Handle<JSReceiver> new_target); 277 278 // Like GetDerivedMap, but returns a map with a RAB / GSAB ElementsKind. 279 static V8_WARN_UNUSED_RESULT Handle<Map> GetDerivedRabGsabMap( 280 Isolate* isolate, Handle<JSFunction> constructor, 281 Handle<JSReceiver> new_target); 282 283 // Get and set the prototype property on a JSFunction. If the 284 // function has an initial map the prototype is set on the initial 285 // map. Otherwise, the prototype is put in the initial map field 286 // until an initial map is needed. 287 DECL_GETTER(has_prototype, bool) 288 DECL_GETTER(has_instance_prototype, bool) 289 DECL_GETTER(prototype, Object) 290 DECL_GETTER(instance_prototype, HeapObject) 291 DECL_GETTER(has_prototype_property, bool) 292 DECL_GETTER(PrototypeRequiresRuntimeLookup, bool) 293 static void SetPrototype(Handle<JSFunction> function, Handle<Object> value); 294 295 // Returns if this function has been compiled to native code yet. 296 inline bool is_compiled() const; 297 GetHeaderSize(bool function_has_prototype_slot)298 static int GetHeaderSize(bool function_has_prototype_slot) { 299 return function_has_prototype_slot ? JSFunction::kSizeWithPrototype 300 : JSFunction::kSizeWithoutPrototype; 301 } 302 303 std::unique_ptr<char[]> DebugNameCStr(); 304 void PrintName(FILE* out = stdout); 305 306 // Calculate the instance size and in-object properties count. 307 // {CalculateExpectedNofProperties} can trigger compilation. 308 static V8_WARN_UNUSED_RESULT int CalculateExpectedNofProperties( 309 Isolate* isolate, Handle<JSFunction> function); 310 static void CalculateInstanceSizeHelper(InstanceType instance_type, 311 bool has_prototype_slot, 312 int requested_embedder_fields, 313 int requested_in_object_properties, 314 int* instance_size, 315 int* in_object_properties); 316 317 // Dispatched behavior. 318 DECL_PRINTER(JSFunction) 319 DECL_VERIFIER(JSFunction) 320 321 static Handle<String> GetName(Handle<JSFunction> function); 322 323 // ES6 section 9.2.11 SetFunctionName 324 // Because of the way this abstract operation is used in the spec, 325 // it should never fail, but in practice it will fail if the generated 326 // function name's length exceeds String::kMaxLength. 327 static V8_WARN_UNUSED_RESULT bool SetName(Handle<JSFunction> function, 328 Handle<Name> name, 329 Handle<String> prefix); 330 331 // The function's name if it is configured, otherwise shared function info 332 // debug name. 333 static Handle<String> GetDebugName(Handle<JSFunction> function); 334 335 // The function's string representation implemented according to 336 // ES6 section 19.2.3.5 Function.prototype.toString ( ). 337 static Handle<String> ToString(Handle<JSFunction> function); 338 339 class BodyDescriptor; 340 341 private: 342 // JSFunction doesn't have a fixed header size: 343 // Hide TorqueGeneratedClass::kHeaderSize to avoid confusion. 344 static const int kHeaderSize; 345 346 // Hide generated accessors; custom accessors are called "shared". 347 DECL_ACCESSORS(shared_function_info, SharedFunctionInfo) 348 349 // Hide generated accessors; custom accessors are called "raw_feedback_cell". 350 DECL_ACCESSORS(feedback_cell, FeedbackCell) 351 352 // Returns the set of code kinds of compilation artifacts (bytecode, 353 // generated code) attached to this JSFunction. 354 // Note that attached code objects that are marked_for_deoptimization are not 355 // included in this set. 356 // TODO(jgruber): Currently at most one code kind can be attached. Consider 357 // adding a NOT_COMPILED kind and changing this function to simply return the 358 // kind if this becomes more convenient in the future. 359 CodeKinds GetAttachedCodeKinds() const; 360 361 // As above, but also considers locations outside of this JSFunction. For 362 // example the optimized code cache slot in the feedback vector, and the 363 // shared function info. 364 CodeKinds GetAvailableCodeKinds() const; 365 366 public: 367 static constexpr int kSizeWithoutPrototype = kPrototypeOrInitialMapOffset; 368 static constexpr int kSizeWithPrototype = TorqueGeneratedClass::kHeaderSize; 369 370 TQ_OBJECT_CONSTRUCTORS(JSFunction) 371 }; 372 373 } // namespace internal 374 } // namespace v8 375 376 #include "src/objects/object-macros-undef.h" 377 378 #endif // V8_OBJECTS_JS_FUNCTION_H_ 379