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 #include "torque-generated/field-offsets.h" 11 12 // Has to be the last include (doesn't have include guards): 13 #include "src/objects/object-macros.h" 14 15 namespace v8 { 16 namespace internal { 17 18 #include "torque-generated/src/objects/js-function-tq.inc" 19 20 // An abstract superclass for classes representing JavaScript function values. 21 // It doesn't carry any functionality but allows function classes to be 22 // identified in the type system. 23 class JSFunctionOrBoundFunction 24 : public TorqueGeneratedJSFunctionOrBoundFunction<JSFunctionOrBoundFunction, 25 JSObject> { 26 public: 27 STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize); 28 TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction) 29 }; 30 31 // JSBoundFunction describes a bound function exotic object. 32 class JSBoundFunction 33 : public TorqueGeneratedJSBoundFunction<JSBoundFunction, 34 JSFunctionOrBoundFunction> { 35 public: 36 static MaybeHandle<String> GetName(Isolate* isolate, 37 Handle<JSBoundFunction> function); 38 static Maybe<int> GetLength(Isolate* isolate, 39 Handle<JSBoundFunction> function); 40 static MaybeHandle<NativeContext> GetFunctionRealm( 41 Handle<JSBoundFunction> function); 42 43 // Dispatched behavior. 44 DECL_PRINTER(JSBoundFunction) 45 DECL_VERIFIER(JSBoundFunction) 46 47 // The bound function's string representation implemented according 48 // to ES6 section 19.2.3.5 Function.prototype.toString ( ). 49 static Handle<String> ToString(Handle<JSBoundFunction> function); 50 51 TQ_OBJECT_CONSTRUCTORS(JSBoundFunction) 52 }; 53 54 // JSFunction describes JavaScript functions. 55 class JSFunction : public JSFunctionOrBoundFunction { 56 public: 57 // [prototype_or_initial_map]: 58 DECL_ACCESSORS(prototype_or_initial_map, HeapObject) 59 60 // [shared]: The information about the function that 61 // can be shared by instances. 62 DECL_ACCESSORS(shared, SharedFunctionInfo) 63 64 static const int kLengthDescriptorIndex = 0; 65 static const int kNameDescriptorIndex = 1; 66 // Home object descriptor index when function has a [[HomeObject]] slot. 67 static const int kMaybeHomeObjectDescriptorIndex = 2; 68 // Fast binding requires length and name accessors. 69 static const int kMinDescriptorsForFastBind = 2; 70 71 // [context]: The context for this function. 72 inline Context context(); 73 inline bool has_context() const; 74 inline void set_context(HeapObject context); 75 inline JSGlobalProxy global_proxy(); 76 inline NativeContext native_context(); 77 inline int length(); 78 79 static Handle<Object> GetName(Isolate* isolate, Handle<JSFunction> function); 80 static Handle<NativeContext> GetFunctionRealm(Handle<JSFunction> function); 81 82 // [code]: The generated code object for this function. Executed 83 // when the function is invoked, e.g. foo() or new foo(). See 84 // [[Call]] and [[Construct]] description in ECMA-262, section 85 // 8.6.2, page 27. 86 inline Code code() const; 87 inline void set_code(Code code); 88 inline void set_code_no_write_barrier(Code code); 89 90 // Get the abstract code associated with the function, which will either be 91 // a Code object or a BytecodeArray. 92 inline AbstractCode abstract_code(); 93 94 // The predicates for querying code kinds related to this function have 95 // specific terminology: 96 // 97 // - Attached: all code kinds that are directly attached to this JSFunction 98 // object. 99 // - Available: all code kinds that are either attached or available through 100 // indirect means such as the feedback vector's optimized code cache. 101 // - Active: the single code kind that would be executed if this function 102 // were called in its current state. Note that there may not be an active 103 // code kind if the function is not compiled. 104 // 105 // Note: code objects that are marked_for_deoptimization are not part of the 106 // attached/available/active sets. This is because the JSFunction might have 107 // been already deoptimized but its code() still needs to be unlinked, which 108 // will happen on its next activation. 109 110 // True, iff any generated code kind is attached/available to this function. 111 V8_EXPORT_PRIVATE bool HasAttachedOptimizedCode() const; 112 bool HasAvailableOptimizedCode() const; 113 114 bool HasAvailableCodeKind(CodeKind kind) const; 115 116 V8_EXPORT_PRIVATE bool ActiveTierIsIgnition() const; 117 bool ActiveTierIsTurbofan() const; 118 bool ActiveTierIsNCI() const; 119 bool ActiveTierIsMidtierTurboprop() const; 120 bool ActiveTierIsToptierTurboprop() const; 121 122 CodeKind NextTier() const; 123 124 // Similar to SharedFunctionInfo::CanDiscardCompiled. Returns true, if the 125 // attached code can be recreated at a later point by replacing it with 126 // CompileLazy. 127 bool CanDiscardCompiled() const; 128 129 // Tells whether or not this function checks its optimization marker in its 130 // feedback vector. 131 inline bool ChecksOptimizationMarker(); 132 133 // Tells whether or not this function has a (non-zero) optimization marker. 134 inline bool HasOptimizationMarker(); 135 136 // Mark this function for lazy recompilation. The function will be recompiled 137 // the next time it is executed. 138 inline void MarkForOptimization(ConcurrencyMode mode); 139 140 // Tells whether or not the function is already marked for lazy recompilation. 141 inline bool IsMarkedForOptimization(); 142 inline bool IsMarkedForConcurrentOptimization(); 143 144 // Tells whether or not the function is on the concurrent recompilation queue. 145 inline bool IsInOptimizationQueue(); 146 147 // Sets the optimization marker in the function's feedback vector. 148 inline void SetOptimizationMarker(OptimizationMarker marker); 149 150 // Clears the optimization marker in the function's feedback vector. 151 inline void ClearOptimizationMarker(); 152 153 // If slack tracking is active, it computes instance size of the initial map 154 // with minimum permissible object slack. If it is not active, it simply 155 // returns the initial map's instance size. 156 int ComputeInstanceSizeWithMinSlack(Isolate* isolate); 157 158 // Completes inobject slack tracking on initial map if it is active. 159 inline void CompleteInobjectSlackTrackingIfActive(); 160 161 // [raw_feedback_cell]: Gives raw access to the FeedbackCell used to hold the 162 /// FeedbackVector eventually. Generally this shouldn't be used to get the 163 // feedback_vector, instead use feedback_vector() which correctly deals with 164 // the JSFunction's bytecode being flushed. 165 DECL_ACCESSORS(raw_feedback_cell, FeedbackCell) 166 167 // Functions related to feedback vector. feedback_vector() can be used once 168 // the function has feedback vectors allocated. feedback vectors may not be 169 // available after compile when lazily allocating feedback vectors. 170 inline FeedbackVector feedback_vector() const; 171 inline bool has_feedback_vector() const; 172 V8_EXPORT_PRIVATE static void EnsureFeedbackVector( 173 Handle<JSFunction> function, IsCompiledScope* compiled_scope); 174 175 // Functions related to closure feedback cell array that holds feedback cells 176 // used to create closures from this function. We allocate closure feedback 177 // cell arrays after compile, when we want to allocate feedback vectors 178 // lazily. 179 inline bool has_closure_feedback_cell_array() const; 180 inline ClosureFeedbackCellArray closure_feedback_cell_array() const; 181 static void EnsureClosureFeedbackCellArray(Handle<JSFunction> function); 182 183 // Initializes the feedback cell of |function|. In lite mode, this would be 184 // initialized to the closure feedback cell array that holds the feedback 185 // cells for create closure calls from this function. In the regular mode, 186 // this allocates feedback vector. 187 static void InitializeFeedbackCell(Handle<JSFunction> function, 188 IsCompiledScope* compiled_scope); 189 190 // Unconditionally clear the type feedback vector. 191 void ClearTypeFeedbackInfo(); 192 193 // Resets function to clear compiled data after bytecode has been flushed. 194 inline bool NeedsResetDueToFlushedBytecode(); 195 inline void ResetIfBytecodeFlushed( 196 base::Optional<std::function<void(HeapObject object, ObjectSlot slot, 197 HeapObject target)>> 198 gc_notify_updated_slot = base::nullopt); 199 200 DECL_GETTER(has_prototype_slot, bool) 201 202 // The initial map for an object created by this constructor. 203 DECL_GETTER(initial_map, Map) 204 205 static void SetInitialMap(Handle<JSFunction> function, Handle<Map> map, 206 Handle<HeapObject> prototype); 207 DECL_GETTER(has_initial_map, bool) 208 V8_EXPORT_PRIVATE static void EnsureHasInitialMap( 209 Handle<JSFunction> function); 210 211 // Creates a map that matches the constructor's initial map, but with 212 // [[prototype]] being new.target.prototype. Because new.target can be a 213 // JSProxy, this can call back into JavaScript. 214 static V8_WARN_UNUSED_RESULT MaybeHandle<Map> GetDerivedMap( 215 Isolate* isolate, Handle<JSFunction> constructor, 216 Handle<JSReceiver> new_target); 217 218 // Get and set the prototype property on a JSFunction. If the 219 // function has an initial map the prototype is set on the initial 220 // map. Otherwise, the prototype is put in the initial map field 221 // until an initial map is needed. 222 DECL_GETTER(has_prototype, bool) 223 DECL_GETTER(has_instance_prototype, bool) 224 DECL_GETTER(prototype, Object) 225 DECL_GETTER(instance_prototype, HeapObject) 226 DECL_GETTER(has_prototype_property, bool) 227 DECL_GETTER(PrototypeRequiresRuntimeLookup, bool) 228 static void SetPrototype(Handle<JSFunction> function, Handle<Object> value); 229 230 // Returns if this function has been compiled to native code yet. 231 inline bool is_compiled() const; 232 GetHeaderSize(bool function_has_prototype_slot)233 static int GetHeaderSize(bool function_has_prototype_slot) { 234 return function_has_prototype_slot ? JSFunction::kSizeWithPrototype 235 : JSFunction::kSizeWithoutPrototype; 236 } 237 238 // Prints the name of the function using PrintF. 239 void PrintName(FILE* out = stdout); 240 241 DECL_CAST(JSFunction) 242 243 // Calculate the instance size and in-object properties count. 244 // {CalculateExpectedNofProperties} can trigger compilation. 245 static V8_WARN_UNUSED_RESULT int CalculateExpectedNofProperties( 246 Isolate* isolate, Handle<JSFunction> function); 247 static void CalculateInstanceSizeHelper(InstanceType instance_type, 248 bool has_prototype_slot, 249 int requested_embedder_fields, 250 int requested_in_object_properties, 251 int* instance_size, 252 int* in_object_properties); 253 254 // Dispatched behavior. 255 DECL_PRINTER(JSFunction) 256 DECL_VERIFIER(JSFunction) 257 258 // The function's name if it is configured, otherwise shared function info 259 // debug name. 260 static Handle<String> GetName(Handle<JSFunction> function); 261 262 // ES6 section 9.2.11 SetFunctionName 263 // Because of the way this abstract operation is used in the spec, 264 // it should never fail, but in practice it will fail if the generated 265 // function name's length exceeds String::kMaxLength. 266 static V8_WARN_UNUSED_RESULT bool SetName(Handle<JSFunction> function, 267 Handle<Name> name, 268 Handle<String> prefix); 269 270 // The function's displayName if it is set, otherwise name if it is 271 // configured, otherwise shared function info 272 // debug name. 273 static Handle<String> GetDebugName(Handle<JSFunction> function); 274 275 // The function's string representation implemented according to 276 // ES6 section 19.2.3.5 Function.prototype.toString ( ). 277 static Handle<String> ToString(Handle<JSFunction> function); 278 279 struct FieldOffsets { 280 DEFINE_FIELD_OFFSET_CONSTANTS(JSFunctionOrBoundFunction::kHeaderSize, 281 TORQUE_GENERATED_JS_FUNCTION_FIELDS) 282 }; 283 static constexpr int kSharedFunctionInfoOffset = 284 FieldOffsets::kSharedFunctionInfoOffset; 285 static constexpr int kContextOffset = FieldOffsets::kContextOffset; 286 static constexpr int kFeedbackCellOffset = FieldOffsets::kFeedbackCellOffset; 287 static constexpr int kCodeOffset = FieldOffsets::kCodeOffset; 288 static constexpr int kPrototypeOrInitialMapOffset = 289 FieldOffsets::kPrototypeOrInitialMapOffset; 290 291 private: 292 // JSFunction doesn't have a fixed header size: 293 // Hide JSFunctionOrBoundFunction::kHeaderSize to avoid confusion. 294 static const int kHeaderSize; 295 296 // Returns the set of code kinds of compilation artifacts (bytecode, 297 // generated code) attached to this JSFunction. 298 // Note that attached code objects that are marked_for_deoptimization are not 299 // included in this set. 300 // TODO(jgruber): Currently at most one code kind can be attached. Consider 301 // adding a NOT_COMPILED kind and changing this function to simply return the 302 // kind if this becomes more convenient in the future. 303 CodeKinds GetAttachedCodeKinds() const; 304 305 // As above, but also considers locations outside of this JSFunction. For 306 // example the optimized code cache slot in the feedback vector, and the 307 // shared function info. 308 CodeKinds GetAvailableCodeKinds() const; 309 310 public: 311 static constexpr int kSizeWithoutPrototype = kPrototypeOrInitialMapOffset; 312 static constexpr int kSizeWithPrototype = FieldOffsets::kHeaderSize; 313 314 OBJECT_CONSTRUCTORS(JSFunction, JSFunctionOrBoundFunction); 315 }; 316 317 } // namespace internal 318 } // namespace v8 319 320 #include "src/objects/object-macros-undef.h" 321 322 #endif // V8_OBJECTS_JS_FUNCTION_H_ 323