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
14namespace v8 {
15namespace 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.
22class 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.
40class 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.
61class 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.
86class 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
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