• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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