• 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 #include "src/objects/js-function.h"
6 
7 #include "src/codegen/compiler.h"
8 #include "src/diagnostics/code-tracer.h"
9 #include "src/execution/isolate.h"
10 #include "src/execution/tiering-manager.h"
11 #include "src/heap/heap-inl.h"
12 #include "src/ic/ic.h"
13 #include "src/init/bootstrapper.h"
14 #include "src/objects/feedback-cell-inl.h"
15 #include "src/strings/string-builder-inl.h"
16 
17 // Has to be the last include (doesn't have include guards):
18 #include "src/objects/object-macros.h"
19 
20 namespace v8 {
21 namespace internal {
22 
GetAttachedCodeKinds() const23 CodeKinds JSFunction::GetAttachedCodeKinds() const {
24   const CodeKind kind = code().kind();
25   if (!CodeKindIsJSFunction(kind)) return {};
26   if (CodeKindIsOptimizedJSFunction(kind) &&
27       code().marked_for_deoptimization()) {
28     return {};
29   }
30   return CodeKindToCodeKindFlag(kind);
31 }
32 
GetAvailableCodeKinds() const33 CodeKinds JSFunction::GetAvailableCodeKinds() const {
34   CodeKinds result = GetAttachedCodeKinds();
35 
36   if ((result & CodeKindFlag::INTERPRETED_FUNCTION) == 0) {
37     // The SharedFunctionInfo could have attached bytecode.
38     if (shared().HasBytecodeArray()) {
39       result |= CodeKindFlag::INTERPRETED_FUNCTION;
40     }
41   }
42 
43   if ((result & CodeKindFlag::BASELINE) == 0) {
44     // The SharedFunctionInfo could have attached baseline code.
45     if (shared().HasBaselineCode()) {
46       result |= CodeKindFlag::BASELINE;
47     }
48   }
49 
50   // Check the optimized code cache.
51   if (has_feedback_vector() && feedback_vector().has_optimized_code() &&
52       !feedback_vector().optimized_code().marked_for_deoptimization()) {
53     CodeT code = feedback_vector().optimized_code();
54     DCHECK(CodeKindIsOptimizedJSFunction(code.kind()));
55     result |= CodeKindToCodeKindFlag(code.kind());
56   }
57 
58   DCHECK_EQ((result & ~kJSFunctionCodeKindsMask), 0);
59   return result;
60 }
61 
HasAttachedOptimizedCode() const62 bool JSFunction::HasAttachedOptimizedCode() const {
63   CodeKinds result = GetAttachedCodeKinds();
64   return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
65 }
66 
HasAvailableOptimizedCode() const67 bool JSFunction::HasAvailableOptimizedCode() const {
68   CodeKinds result = GetAvailableCodeKinds();
69   return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
70 }
71 
HasAttachedCodeKind(CodeKind kind) const72 bool JSFunction::HasAttachedCodeKind(CodeKind kind) const {
73   CodeKinds result = GetAttachedCodeKinds();
74   return (result & CodeKindToCodeKindFlag(kind)) != 0;
75 }
76 
HasAvailableCodeKind(CodeKind kind) const77 bool JSFunction::HasAvailableCodeKind(CodeKind kind) const {
78   CodeKinds result = GetAvailableCodeKinds();
79   return (result & CodeKindToCodeKindFlag(kind)) != 0;
80 }
81 
82 namespace {
83 
84 // Returns false if no highest tier exists (i.e. the function is not compiled),
85 // otherwise returns true and sets highest_tier.
HighestTierOf(CodeKinds kinds,CodeKind * highest_tier)86 V8_WARN_UNUSED_RESULT bool HighestTierOf(CodeKinds kinds,
87                                          CodeKind* highest_tier) {
88   DCHECK_EQ((kinds & ~kJSFunctionCodeKindsMask), 0);
89   // Higher tiers > lower tiers.
90   STATIC_ASSERT(CodeKind::TURBOFAN > CodeKind::INTERPRETED_FUNCTION);
91   if (kinds == 0) return false;
92   const int highest_tier_log2 =
93       31 - base::bits::CountLeadingZeros(static_cast<uint32_t>(kinds));
94   DCHECK(CodeKindIsJSFunction(static_cast<CodeKind>(highest_tier_log2)));
95   *highest_tier = static_cast<CodeKind>(highest_tier_log2);
96   return true;
97 }
98 
99 }  // namespace
100 
GetActiveTier() const101 base::Optional<CodeKind> JSFunction::GetActiveTier() const {
102 #if V8_ENABLE_WEBASSEMBLY
103   // Asm/Wasm functions are currently not supported. For simplicity, this
104   // includes invalid asm.js functions whose code hasn't yet been updated to
105   // CompileLazy but is still the InstantiateAsmJs builtin.
106   if (shared().HasAsmWasmData() ||
107       code().builtin_id() == Builtin::kInstantiateAsmJs) {
108     return {};
109   }
110 #endif  // V8_ENABLE_WEBASSEMBLY
111 
112   CodeKind highest_tier;
113   if (!HighestTierOf(GetAvailableCodeKinds(), &highest_tier)) return {};
114 
115 #ifdef DEBUG
116   CHECK(highest_tier == CodeKind::TURBOFAN ||
117         highest_tier == CodeKind::BASELINE ||
118         highest_tier == CodeKind::MAGLEV ||
119         highest_tier == CodeKind::INTERPRETED_FUNCTION);
120 
121   if (highest_tier == CodeKind::INTERPRETED_FUNCTION) {
122     CHECK(code().is_interpreter_trampoline_builtin() ||
123           (CodeKindIsOptimizedJSFunction(code().kind()) &&
124            code().marked_for_deoptimization()) ||
125           (code().builtin_id() == Builtin::kCompileLazy &&
126            shared().HasBytecodeArray() && !shared().HasBaselineCode()));
127   }
128 #endif  // DEBUG
129 
130   return highest_tier;
131 }
132 
ActiveTierIsIgnition() const133 bool JSFunction::ActiveTierIsIgnition() const {
134   return GetActiveTier() == CodeKind::INTERPRETED_FUNCTION;
135 }
136 
ActiveTierIsBaseline() const137 bool JSFunction::ActiveTierIsBaseline() const {
138   return GetActiveTier() == CodeKind::BASELINE;
139 }
140 
ActiveTierIsMaglev() const141 bool JSFunction::ActiveTierIsMaglev() const {
142   return GetActiveTier() == CodeKind::MAGLEV;
143 }
144 
ActiveTierIsTurbofan() const145 bool JSFunction::ActiveTierIsTurbofan() const {
146   return GetActiveTier() == CodeKind::TURBOFAN;
147 }
148 
CanDiscardCompiled() const149 bool JSFunction::CanDiscardCompiled() const {
150   // Essentially, what we are asking here is, has this function been compiled
151   // from JS code? We can currently tell only indirectly, by looking at
152   // available code kinds. If any JS code kind exists, we can discard.
153   //
154   // Attached optimized code that is marked for deoptimization will not show up
155   // in the list of available code kinds, thus we must check for it manually.
156   //
157   // Note that when the function has not yet been compiled we also return
158   // false; that's fine, since nothing must be discarded in that case.
159   if (CodeKindIsOptimizedJSFunction(code().kind())) return true;
160   CodeKinds result = GetAvailableCodeKinds();
161   return (result & kJSFunctionCodeKindsMask) != 0;
162 }
163 
164 namespace {
165 
TieringStateFor(CodeKind target_kind,ConcurrencyMode mode)166 constexpr TieringState TieringStateFor(CodeKind target_kind,
167                                        ConcurrencyMode mode) {
168   DCHECK(target_kind == CodeKind::MAGLEV || target_kind == CodeKind::TURBOFAN);
169   return target_kind == CodeKind::MAGLEV
170              ? (IsConcurrent(mode) ? TieringState::kRequestMaglev_Concurrent
171                                    : TieringState::kRequestMaglev_Synchronous)
172              : (IsConcurrent(mode)
173                     ? TieringState::kRequestTurbofan_Concurrent
174                     : TieringState::kRequestTurbofan_Synchronous);
175 }
176 
177 }  // namespace
178 
MarkForOptimization(Isolate * isolate,CodeKind target_kind,ConcurrencyMode mode)179 void JSFunction::MarkForOptimization(Isolate* isolate, CodeKind target_kind,
180                                      ConcurrencyMode mode) {
181   if (!isolate->concurrent_recompilation_enabled() ||
182       isolate->bootstrapper()->IsActive()) {
183     mode = ConcurrencyMode::kSynchronous;
184   }
185 
186   DCHECK(CodeKindIsOptimizedJSFunction(target_kind));
187   DCHECK(!is_compiled() || ActiveTierIsIgnition() || ActiveTierIsBaseline() ||
188          ActiveTierIsMaglev());
189   DCHECK(!ActiveTierIsTurbofan());
190   DCHECK(shared().HasBytecodeArray());
191   DCHECK(shared().allows_lazy_compilation() ||
192          !shared().optimization_disabled());
193 
194   if (IsConcurrent(mode)) {
195     if (IsInProgress(tiering_state())) {
196       if (FLAG_trace_concurrent_recompilation) {
197         PrintF("  ** Not marking ");
198         ShortPrint();
199         PrintF(" -- already in optimization queue.\n");
200       }
201       return;
202     }
203     if (FLAG_trace_concurrent_recompilation) {
204       PrintF("  ** Marking ");
205       ShortPrint();
206       PrintF(" for concurrent %s recompilation.\n",
207              CodeKindToString(target_kind));
208     }
209   }
210 
211   set_tiering_state(TieringStateFor(target_kind, mode));
212 }
213 
SetInterruptBudget(Isolate * isolate)214 void JSFunction::SetInterruptBudget(Isolate* isolate) {
215   raw_feedback_cell().set_interrupt_budget(
216       TieringManager::InterruptBudgetFor(isolate, *this));
217 }
218 
219 // static
CopyNameAndLength(Isolate * isolate,Handle<JSFunctionOrBoundFunctionOrWrappedFunction> function,Handle<JSReceiver> target,Handle<String> prefix,int arg_count)220 Maybe<bool> JSFunctionOrBoundFunctionOrWrappedFunction::CopyNameAndLength(
221     Isolate* isolate,
222     Handle<JSFunctionOrBoundFunctionOrWrappedFunction> function,
223     Handle<JSReceiver> target, Handle<String> prefix, int arg_count) {
224   // Setup the "length" property based on the "length" of the {target}.
225   // If the targets length is the default JSFunction accessor, we can keep the
226   // accessor that's installed by default on the
227   // JSBoundFunction/JSWrappedFunction. It lazily computes the value from the
228   // underlying internal length.
229   Handle<AccessorInfo> function_length_accessor =
230       isolate->factory()->function_length_accessor();
231   LookupIterator length_lookup(isolate, target,
232                                isolate->factory()->length_string(), target,
233                                LookupIterator::OWN);
234   if (!target->IsJSFunction() ||
235       length_lookup.state() != LookupIterator::ACCESSOR ||
236       !length_lookup.GetAccessors().is_identical_to(function_length_accessor)) {
237     Handle<Object> length(Smi::zero(), isolate);
238     Maybe<PropertyAttributes> attributes =
239         JSReceiver::GetPropertyAttributes(&length_lookup);
240     if (attributes.IsNothing()) return Nothing<bool>();
241     if (attributes.FromJust() != ABSENT) {
242       Handle<Object> target_length;
243       ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_length,
244                                        Object::GetProperty(&length_lookup),
245                                        Nothing<bool>());
246       if (target_length->IsNumber()) {
247         length = isolate->factory()->NewNumber(std::max(
248             0.0, DoubleToInteger(target_length->Number()) - arg_count));
249       }
250     }
251     LookupIterator it(isolate, function, isolate->factory()->length_string(),
252                       function);
253     DCHECK_EQ(LookupIterator::ACCESSOR, it.state());
254     RETURN_ON_EXCEPTION_VALUE(isolate,
255                               JSObject::DefineOwnPropertyIgnoreAttributes(
256                                   &it, length, it.property_attributes()),
257                               Nothing<bool>());
258   }
259 
260   // Setup the "name" property based on the "name" of the {target}.
261   // If the target's name is the default JSFunction accessor, we can keep the
262   // accessor that's installed by default on the
263   // JSBoundFunction/JSWrappedFunction. It lazily computes the value from the
264   // underlying internal name.
265   Handle<AccessorInfo> function_name_accessor =
266       isolate->factory()->function_name_accessor();
267   LookupIterator name_lookup(isolate, target, isolate->factory()->name_string(),
268                              target);
269   if (!target->IsJSFunction() ||
270       name_lookup.state() != LookupIterator::ACCESSOR ||
271       !name_lookup.GetAccessors().is_identical_to(function_name_accessor) ||
272       (name_lookup.IsFound() && !name_lookup.HolderIsReceiver())) {
273     Handle<Object> target_name;
274     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, target_name,
275                                      Object::GetProperty(&name_lookup),
276                                      Nothing<bool>());
277     Handle<String> name;
278     if (target_name->IsString()) {
279       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
280           isolate, name,
281           Name::ToFunctionName(isolate, Handle<String>::cast(target_name)),
282           Nothing<bool>());
283       if (!prefix.is_null()) {
284         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
285             isolate, name, isolate->factory()->NewConsString(prefix, name),
286             Nothing<bool>());
287       }
288     } else if (prefix.is_null()) {
289       name = isolate->factory()->empty_string();
290     } else {
291       name = prefix;
292     }
293     LookupIterator it(isolate, function, isolate->factory()->name_string());
294     DCHECK_EQ(LookupIterator::ACCESSOR, it.state());
295     RETURN_ON_EXCEPTION_VALUE(isolate,
296                               JSObject::DefineOwnPropertyIgnoreAttributes(
297                                   &it, name, it.property_attributes()),
298                               Nothing<bool>());
299   }
300 
301   return Just(true);
302 }
303 
304 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)305 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
306                                              Handle<JSBoundFunction> function) {
307   Handle<String> prefix = isolate->factory()->bound__string();
308   Handle<String> target_name = prefix;
309   Factory* factory = isolate->factory();
310   // Concatenate the "bound " up to the last non-bound target.
311   while (function->bound_target_function().IsJSBoundFunction()) {
312     ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
313                                factory->NewConsString(prefix, target_name),
314                                String);
315     function = handle(JSBoundFunction::cast(function->bound_target_function()),
316                       isolate);
317   }
318   if (function->bound_target_function().IsJSWrappedFunction()) {
319     Handle<JSWrappedFunction> target(
320         JSWrappedFunction::cast(function->bound_target_function()), isolate);
321     Handle<String> name;
322     ASSIGN_RETURN_ON_EXCEPTION(
323         isolate, name, JSWrappedFunction::GetName(isolate, target), String);
324     return factory->NewConsString(target_name, name);
325   }
326   if (function->bound_target_function().IsJSFunction()) {
327     Handle<JSFunction> target(
328         JSFunction::cast(function->bound_target_function()), isolate);
329     Handle<String> name = JSFunction::GetName(isolate, target);
330     return factory->NewConsString(target_name, name);
331   }
332   // This will omit the proper target name for bound JSProxies.
333   return target_name;
334 }
335 
336 // static
GetLength(Isolate * isolate,Handle<JSBoundFunction> function)337 Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
338                                       Handle<JSBoundFunction> function) {
339   int nof_bound_arguments = function->bound_arguments().length();
340   while (function->bound_target_function().IsJSBoundFunction()) {
341     function = handle(JSBoundFunction::cast(function->bound_target_function()),
342                       isolate);
343     // Make sure we never overflow {nof_bound_arguments}, the number of
344     // arguments of a function is strictly limited by the max length of an
345     // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
346     int length = function->bound_arguments().length();
347     if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
348       nof_bound_arguments += length;
349     } else {
350       nof_bound_arguments = Smi::kMaxValue;
351     }
352   }
353   if (function->bound_target_function().IsJSWrappedFunction()) {
354     Handle<JSWrappedFunction> target(
355         JSWrappedFunction::cast(function->bound_target_function()), isolate);
356     int target_length = 0;
357     MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
358         isolate, target_length, JSWrappedFunction::GetLength(isolate, target),
359         Nothing<int>());
360     int length = std::max(0, target_length - nof_bound_arguments);
361     return Just(length);
362   }
363   // All non JSFunction targets get a direct property and don't use this
364   // accessor.
365   Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
366                             isolate);
367   int target_length = target->length();
368 
369   int length = std::max(0, target_length - nof_bound_arguments);
370   return Just(length);
371 }
372 
373 // static
ToString(Handle<JSBoundFunction> function)374 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
375   Isolate* const isolate = function->GetIsolate();
376   return isolate->factory()->function_native_code_string();
377 }
378 
379 // static
GetName(Isolate * isolate,Handle<JSWrappedFunction> function)380 MaybeHandle<String> JSWrappedFunction::GetName(
381     Isolate* isolate, Handle<JSWrappedFunction> function) {
382   STACK_CHECK(isolate, MaybeHandle<String>());
383   Factory* factory = isolate->factory();
384   Handle<String> target_name = factory->empty_string();
385   Handle<JSReceiver> target =
386       handle(function->wrapped_target_function(), isolate);
387   if (target->IsJSBoundFunction()) {
388     return JSBoundFunction::GetName(
389         isolate,
390         handle(JSBoundFunction::cast(function->wrapped_target_function()),
391                isolate));
392   } else if (target->IsJSFunction()) {
393     return JSFunction::GetName(
394         isolate,
395         handle(JSFunction::cast(function->wrapped_target_function()), isolate));
396   }
397   // This will omit the proper target name for bound JSProxies.
398   return target_name;
399 }
400 
401 // static
GetLength(Isolate * isolate,Handle<JSWrappedFunction> function)402 Maybe<int> JSWrappedFunction::GetLength(Isolate* isolate,
403                                         Handle<JSWrappedFunction> function) {
404   STACK_CHECK(isolate, Nothing<int>());
405   Handle<JSReceiver> target =
406       handle(function->wrapped_target_function(), isolate);
407   if (target->IsJSBoundFunction()) {
408     return JSBoundFunction::GetLength(
409         isolate,
410         handle(JSBoundFunction::cast(function->wrapped_target_function()),
411                isolate));
412   }
413   // All non JSFunction targets get a direct property and don't use this
414   // accessor.
415   return Just(Handle<JSFunction>::cast(target)->length());
416 }
417 
418 // static
ToString(Handle<JSWrappedFunction> function)419 Handle<String> JSWrappedFunction::ToString(Handle<JSWrappedFunction> function) {
420   Isolate* const isolate = function->GetIsolate();
421   return isolate->factory()->function_native_code_string();
422 }
423 
424 // static
Create(Isolate * isolate,Handle<NativeContext> creation_context,Handle<JSReceiver> value)425 MaybeHandle<Object> JSWrappedFunction::Create(
426     Isolate* isolate, Handle<NativeContext> creation_context,
427     Handle<JSReceiver> value) {
428   // The value must be a callable according to the specification.
429   DCHECK(value->IsCallable());
430   // The intermediate wrapped functions are not user-visible. And calling a
431   // wrapped function won't cause a side effect in the creation realm.
432   // Unwrap here to avoid nested unwrapping at the call site.
433   if (value->IsJSWrappedFunction()) {
434     Handle<JSWrappedFunction> target_wrapped =
435         Handle<JSWrappedFunction>::cast(value);
436     value =
437         Handle<JSReceiver>(target_wrapped->wrapped_target_function(), isolate);
438   }
439 
440   // 1. Let internalSlotsList be the internal slots listed in Table 2, plus
441   // [[Prototype]] and [[Extensible]].
442   // 2. Let wrapped be ! MakeBasicObject(internalSlotsList).
443   // 3. Set wrapped.[[Prototype]] to
444   // callerRealm.[[Intrinsics]].[[%Function.prototype%]].
445   // 4. Set wrapped.[[Call]] as described in 2.1.
446   // 5. Set wrapped.[[WrappedTargetFunction]] to Target.
447   // 6. Set wrapped.[[Realm]] to callerRealm.
448   Handle<JSWrappedFunction> wrapped =
449       isolate->factory()->NewJSWrappedFunction(creation_context, value);
450 
451   // 7. Let result be CopyNameAndLength(wrapped, Target, "wrapped").
452   Maybe<bool> is_abrupt =
453       JSFunctionOrBoundFunctionOrWrappedFunction::CopyNameAndLength(
454           isolate, wrapped, value, Handle<String>(), 0);
455 
456   // 8. If result is an Abrupt Completion, throw a TypeError exception.
457   if (is_abrupt.IsNothing()) {
458     DCHECK(isolate->has_pending_exception());
459     isolate->clear_pending_exception();
460     // TODO(v8:11989): provide a non-observable inspection on the
461     // pending_exception to the newly created TypeError.
462     // https://github.com/tc39/proposal-shadowrealm/issues/353
463 
464     // The TypeError thrown is created with creation Realm's TypeError
465     // constructor instead of the executing Realm's.
466     THROW_NEW_ERROR_RETURN_VALUE(
467         isolate,
468         NewError(Handle<JSFunction>(creation_context->type_error_function(),
469                                     isolate),
470                  MessageTemplate::kCannotWrap),
471         {});
472   }
473   DCHECK(is_abrupt.FromJust());
474 
475   // 9. Return wrapped.
476   return wrapped;
477 }
478 
479 // static
GetName(Isolate * isolate,Handle<JSFunction> function)480 Handle<String> JSFunction::GetName(Isolate* isolate,
481                                    Handle<JSFunction> function) {
482   if (function->shared().name_should_print_as_anonymous()) {
483     return isolate->factory()->anonymous_string();
484   }
485   return handle(function->shared().Name(), isolate);
486 }
487 
488 // static
EnsureClosureFeedbackCellArray(Handle<JSFunction> function,bool reset_budget_for_feedback_allocation)489 void JSFunction::EnsureClosureFeedbackCellArray(
490     Handle<JSFunction> function, bool reset_budget_for_feedback_allocation) {
491   Isolate* const isolate = function->GetIsolate();
492   DCHECK(function->shared().is_compiled());
493   DCHECK(function->shared().HasFeedbackMetadata());
494 #if V8_ENABLE_WEBASSEMBLY
495   if (function->shared().HasAsmWasmData()) return;
496 #endif  // V8_ENABLE_WEBASSEMBLY
497 
498   Handle<SharedFunctionInfo> shared(function->shared(), isolate);
499   DCHECK(function->shared().HasBytecodeArray());
500 
501   const bool has_closure_feedback_cell_array =
502       (function->has_closure_feedback_cell_array() ||
503        function->has_feedback_vector());
504   // Initialize the interrupt budget to the feedback vector allocation budget
505   // when initializing the feedback cell for the first time or after a bytecode
506   // flush. We retain the closure feedback cell array on bytecode flush, so
507   // reset_budget_for_feedback_allocation is used to reset the budget in these
508   // cases.
509   if (reset_budget_for_feedback_allocation ||
510       !has_closure_feedback_cell_array) {
511     function->SetInterruptBudget(isolate);
512   }
513 
514   if (has_closure_feedback_cell_array) {
515     return;
516   }
517 
518   Handle<HeapObject> feedback_cell_array =
519       ClosureFeedbackCellArray::New(isolate, shared);
520   // Many closure cell is used as a way to specify that there is no
521   // feedback cell for this function and a new feedback cell has to be
522   // allocated for this funciton. For ex: for eval functions, we have to create
523   // a feedback cell and cache it along with the code. It is safe to use
524   // many_closure_cell to indicate this because in regular cases, it should
525   // already have a feedback_vector / feedback cell array allocated.
526   if (function->raw_feedback_cell() == isolate->heap()->many_closures_cell()) {
527     Handle<FeedbackCell> feedback_cell =
528         isolate->factory()->NewOneClosureCell(feedback_cell_array);
529     function->set_raw_feedback_cell(*feedback_cell, kReleaseStore);
530     function->SetInterruptBudget(isolate);
531   } else {
532     function->raw_feedback_cell().set_value(*feedback_cell_array,
533                                             kReleaseStore);
534   }
535 }
536 
537 // static
EnsureFeedbackVector(Isolate * isolate,Handle<JSFunction> function,IsCompiledScope * compiled_scope)538 void JSFunction::EnsureFeedbackVector(Isolate* isolate,
539                                       Handle<JSFunction> function,
540                                       IsCompiledScope* compiled_scope) {
541   DCHECK(compiled_scope->is_compiled());
542   DCHECK(function->shared().HasFeedbackMetadata());
543   if (function->has_feedback_vector()) return;
544 #if V8_ENABLE_WEBASSEMBLY
545   if (function->shared().HasAsmWasmData()) return;
546 #endif  // V8_ENABLE_WEBASSEMBLY
547 
548   CreateAndAttachFeedbackVector(isolate, function, compiled_scope);
549 }
550 
551 // static
CreateAndAttachFeedbackVector(Isolate * isolate,Handle<JSFunction> function,IsCompiledScope * compiled_scope)552 void JSFunction::CreateAndAttachFeedbackVector(
553     Isolate* isolate, Handle<JSFunction> function,
554     IsCompiledScope* compiled_scope) {
555   DCHECK(compiled_scope->is_compiled());
556   DCHECK(function->shared().HasFeedbackMetadata());
557   DCHECK(!function->has_feedback_vector());
558 #if V8_ENABLE_WEBASSEMBLY
559   DCHECK(!function->shared().HasAsmWasmData());
560 #endif  // V8_ENABLE_WEBASSEMBLY
561 
562   Handle<SharedFunctionInfo> shared(function->shared(), isolate);
563   DCHECK(function->shared().HasBytecodeArray());
564 
565   EnsureClosureFeedbackCellArray(function, false);
566   Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
567       handle(function->closure_feedback_cell_array(), isolate);
568   Handle<HeapObject> feedback_vector = FeedbackVector::New(
569       isolate, shared, closure_feedback_cell_array, compiled_scope);
570   // EnsureClosureFeedbackCellArray should handle the special case where we need
571   // to allocate a new feedback cell. Please look at comment in that function
572   // for more details.
573   DCHECK(function->raw_feedback_cell() !=
574          isolate->heap()->many_closures_cell());
575   function->raw_feedback_cell().set_value(*feedback_vector, kReleaseStore);
576   function->SetInterruptBudget(isolate);
577 }
578 
579 // static
InitializeFeedbackCell(Handle<JSFunction> function,IsCompiledScope * is_compiled_scope,bool reset_budget_for_feedback_allocation)580 void JSFunction::InitializeFeedbackCell(
581     Handle<JSFunction> function, IsCompiledScope* is_compiled_scope,
582     bool reset_budget_for_feedback_allocation) {
583   Isolate* const isolate = function->GetIsolate();
584 #if V8_ENABLE_WEBASSEMBLY
585   // The following checks ensure that the feedback vectors are compatible with
586   // the feedback metadata. For Asm / Wasm functions we never allocate / use
587   // feedback vectors, so a mismatch between the metadata and feedback vector is
588   // harmless. The checks could fail for functions that has has_asm_wasm_broken
589   // set at runtime (for ex: failed instantiation).
590   if (function->shared().HasAsmWasmData()) return;
591 #endif  // V8_ENABLE_WEBASSEMBLY
592 
593   if (function->has_feedback_vector()) {
594     CHECK_EQ(function->feedback_vector().length(),
595              function->feedback_vector().metadata().slot_count());
596     return;
597   }
598 
599   if (function->has_closure_feedback_cell_array()) {
600     CHECK_EQ(
601         function->closure_feedback_cell_array().length(),
602         function->shared().feedback_metadata().create_closure_slot_count());
603   }
604 
605   const bool needs_feedback_vector =
606       !FLAG_lazy_feedback_allocation || FLAG_always_opt ||
607       // We also need a feedback vector for certain log events, collecting type
608       // profile and more precise code coverage.
609       FLAG_log_function_events || !isolate->is_best_effort_code_coverage() ||
610       isolate->is_collecting_type_profile();
611 
612   if (needs_feedback_vector) {
613     CreateAndAttachFeedbackVector(isolate, function, is_compiled_scope);
614   } else {
615     EnsureClosureFeedbackCellArray(function,
616                                    reset_budget_for_feedback_allocation);
617   }
618 }
619 
620 namespace {
621 
SetInstancePrototype(Isolate * isolate,Handle<JSFunction> function,Handle<JSReceiver> value)622 void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
623                           Handle<JSReceiver> value) {
624   // Now some logic for the maps of the objects that are created by using this
625   // function as a constructor.
626   if (function->has_initial_map()) {
627     // If the function has allocated the initial map replace it with a
628     // copy containing the new prototype.  Also complete any in-object
629     // slack tracking that is in progress at this point because it is
630     // still tracking the old copy.
631     function->CompleteInobjectSlackTrackingIfActive();
632 
633     Handle<Map> initial_map(function->initial_map(), isolate);
634 
635     if (!isolate->bootstrapper()->IsActive() &&
636         initial_map->instance_type() == JS_OBJECT_TYPE) {
637       // Put the value in the initial map field until an initial map is needed.
638       // At that point, a new initial map is created and the prototype is put
639       // into the initial map where it belongs.
640       function->set_prototype_or_initial_map(*value, kReleaseStore);
641     } else {
642       Handle<Map> new_map =
643           Map::Copy(isolate, initial_map, "SetInstancePrototype");
644       JSFunction::SetInitialMap(isolate, function, new_map, value);
645       DCHECK_IMPLIES(!isolate->bootstrapper()->IsActive(),
646                      *function != function->native_context().array_function());
647     }
648 
649     // Deoptimize all code that embeds the previous initial map.
650     initial_map->dependent_code().DeoptimizeDependentCodeGroup(
651         isolate, DependentCode::kInitialMapChangedGroup);
652   } else {
653     // Put the value in the initial map field until an initial map is
654     // needed.  At that point, a new initial map is created and the
655     // prototype is put into the initial map where it belongs.
656     function->set_prototype_or_initial_map(*value, kReleaseStore);
657     if (value->IsJSObject()) {
658       // Optimize as prototype to detach it from its transition tree.
659       JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
660     }
661   }
662 }
663 
664 }  // anonymous namespace
665 
SetPrototype(Handle<JSFunction> function,Handle<Object> value)666 void JSFunction::SetPrototype(Handle<JSFunction> function,
667                               Handle<Object> value) {
668   DCHECK(function->IsConstructor() ||
669          IsGeneratorFunction(function->shared().kind()));
670   Isolate* isolate = function->GetIsolate();
671   Handle<JSReceiver> construct_prototype;
672 
673   // If the value is not a JSReceiver, store the value in the map's
674   // constructor field so it can be accessed.  Also, set the prototype
675   // used for constructing objects to the original object prototype.
676   // See ECMA-262 13.2.2.
677   if (!value->IsJSReceiver()) {
678     // Copy the map so this does not affect unrelated functions.
679     // Remove map transitions because they point to maps with a
680     // different prototype.
681     Handle<Map> new_map =
682         Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
683 
684     new_map->SetConstructor(*value);
685     new_map->set_has_non_instance_prototype(true);
686     JSObject::MigrateToMap(isolate, function, new_map);
687 
688     FunctionKind kind = function->shared().kind();
689     Handle<Context> native_context(function->native_context(), isolate);
690 
691     construct_prototype = Handle<JSReceiver>(
692         IsGeneratorFunction(kind)
693             ? IsAsyncFunction(kind)
694                   ? native_context->initial_async_generator_prototype()
695                   : native_context->initial_generator_prototype()
696             : native_context->initial_object_prototype(),
697         isolate);
698   } else {
699     construct_prototype = Handle<JSReceiver>::cast(value);
700     function->map().set_has_non_instance_prototype(false);
701   }
702 
703   SetInstancePrototype(isolate, function, construct_prototype);
704 }
705 
SetInitialMap(Isolate * isolate,Handle<JSFunction> function,Handle<Map> map,Handle<HeapObject> prototype)706 void JSFunction::SetInitialMap(Isolate* isolate, Handle<JSFunction> function,
707                                Handle<Map> map, Handle<HeapObject> prototype) {
708   SetInitialMap(isolate, function, map, prototype, function);
709 }
710 
SetInitialMap(Isolate * isolate,Handle<JSFunction> function,Handle<Map> map,Handle<HeapObject> prototype,Handle<JSFunction> constructor)711 void JSFunction::SetInitialMap(Isolate* isolate, Handle<JSFunction> function,
712                                Handle<Map> map, Handle<HeapObject> prototype,
713                                Handle<JSFunction> constructor) {
714   if (map->prototype() != *prototype) {
715     Map::SetPrototype(isolate, map, prototype);
716   }
717   map->SetConstructor(*constructor);
718   function->set_prototype_or_initial_map(*map, kReleaseStore);
719   if (FLAG_log_maps) {
720     LOG(isolate, MapEvent("InitialMap", Handle<Map>(), map, "",
721                           SharedFunctionInfo::DebugName(
722                               handle(function->shared(), isolate))));
723   }
724 }
725 
EnsureHasInitialMap(Handle<JSFunction> function)726 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
727   DCHECK(function->has_prototype_slot());
728   DCHECK(function->IsConstructor() ||
729          IsResumableFunction(function->shared().kind()));
730   if (function->has_initial_map()) return;
731   Isolate* isolate = function->GetIsolate();
732 
733   int expected_nof_properties =
734       CalculateExpectedNofProperties(isolate, function);
735 
736   // {CalculateExpectedNofProperties} can have had the side effect of creating
737   // the initial map (e.g. it could have triggered an optimized compilation
738   // whose dependency installation reentered {EnsureHasInitialMap}).
739   if (function->has_initial_map()) return;
740 
741   // Create a new map with the size and number of in-object properties suggested
742   // by the function.
743   InstanceType instance_type;
744   if (IsResumableFunction(function->shared().kind())) {
745     instance_type = IsAsyncGeneratorFunction(function->shared().kind())
746                         ? JS_ASYNC_GENERATOR_OBJECT_TYPE
747                         : JS_GENERATOR_OBJECT_TYPE;
748   } else {
749     instance_type = JS_OBJECT_TYPE;
750   }
751 
752   int instance_size;
753   int inobject_properties;
754   CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
755                               &instance_size, &inobject_properties);
756 
757   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
758                                                TERMINAL_FAST_ELEMENTS_KIND,
759                                                inobject_properties);
760 
761   // Fetch or allocate prototype.
762   Handle<HeapObject> prototype;
763   if (function->has_instance_prototype()) {
764     prototype = handle(function->instance_prototype(), isolate);
765   } else {
766     prototype = isolate->factory()->NewFunctionPrototype(function);
767   }
768   DCHECK(map->has_fast_object_elements());
769 
770   // Finally link initial map and constructor function.
771   DCHECK(prototype->IsJSReceiver());
772   JSFunction::SetInitialMap(isolate, function, map, prototype);
773   map->StartInobjectSlackTracking();
774 }
775 
776 namespace {
777 
778 #ifdef DEBUG
CanSubclassHaveInobjectProperties(InstanceType instance_type)779 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
780   switch (instance_type) {
781     case JS_API_OBJECT_TYPE:
782     case JS_ARRAY_BUFFER_TYPE:
783     case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE:
784     case JS_ARRAY_TYPE:
785     case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
786     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
787     case JS_DATA_VIEW_TYPE:
788     case JS_DATE_TYPE:
789     case JS_GENERATOR_OBJECT_TYPE:
790     case JS_FUNCTION_TYPE:
791     case JS_CLASS_CONSTRUCTOR_TYPE:
792     case JS_PROMISE_CONSTRUCTOR_TYPE:
793     case JS_REG_EXP_CONSTRUCTOR_TYPE:
794     case JS_ARRAY_CONSTRUCTOR_TYPE:
795 #define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype) \
796   case TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE:
797       TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTORS_SWITCH)
798 #undef TYPED_ARRAY_CONSTRUCTORS_SWITCH
799     case JS_ITERATOR_PROTOTYPE_TYPE:
800     case JS_MAP_ITERATOR_PROTOTYPE_TYPE:
801     case JS_OBJECT_PROTOTYPE_TYPE:
802     case JS_PROMISE_PROTOTYPE_TYPE:
803     case JS_REG_EXP_PROTOTYPE_TYPE:
804     case JS_SET_ITERATOR_PROTOTYPE_TYPE:
805     case JS_SET_PROTOTYPE_TYPE:
806     case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
807     case JS_TYPED_ARRAY_PROTOTYPE_TYPE:
808 #ifdef V8_INTL_SUPPORT
809     case JS_COLLATOR_TYPE:
810     case JS_DATE_TIME_FORMAT_TYPE:
811     case JS_DISPLAY_NAMES_TYPE:
812     case JS_LIST_FORMAT_TYPE:
813     case JS_LOCALE_TYPE:
814     case JS_NUMBER_FORMAT_TYPE:
815     case JS_PLURAL_RULES_TYPE:
816     case JS_RELATIVE_TIME_FORMAT_TYPE:
817     case JS_SEGMENT_ITERATOR_TYPE:
818     case JS_SEGMENTER_TYPE:
819     case JS_SEGMENTS_TYPE:
820     case JS_V8_BREAK_ITERATOR_TYPE:
821 #endif
822     case JS_ASYNC_FUNCTION_OBJECT_TYPE:
823     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
824     case JS_MAP_TYPE:
825     case JS_MESSAGE_OBJECT_TYPE:
826     case JS_OBJECT_TYPE:
827     case JS_ERROR_TYPE:
828     case JS_FINALIZATION_REGISTRY_TYPE:
829     case JS_ARGUMENTS_OBJECT_TYPE:
830     case JS_PROMISE_TYPE:
831     case JS_REG_EXP_TYPE:
832     case JS_SET_TYPE:
833     case JS_SHADOW_REALM_TYPE:
834     case JS_SPECIAL_API_OBJECT_TYPE:
835     case JS_TYPED_ARRAY_TYPE:
836     case JS_PRIMITIVE_WRAPPER_TYPE:
837     case JS_TEMPORAL_CALENDAR_TYPE:
838     case JS_TEMPORAL_DURATION_TYPE:
839     case JS_TEMPORAL_INSTANT_TYPE:
840     case JS_TEMPORAL_PLAIN_DATE_TYPE:
841     case JS_TEMPORAL_PLAIN_DATE_TIME_TYPE:
842     case JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE:
843     case JS_TEMPORAL_PLAIN_TIME_TYPE:
844     case JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE:
845     case JS_TEMPORAL_TIME_ZONE_TYPE:
846     case JS_TEMPORAL_ZONED_DATE_TIME_TYPE:
847     case JS_WEAK_MAP_TYPE:
848     case JS_WEAK_REF_TYPE:
849     case JS_WEAK_SET_TYPE:
850 #if V8_ENABLE_WEBASSEMBLY
851     case WASM_GLOBAL_OBJECT_TYPE:
852     case WASM_INSTANCE_OBJECT_TYPE:
853     case WASM_MEMORY_OBJECT_TYPE:
854     case WASM_MODULE_OBJECT_TYPE:
855     case WASM_TABLE_OBJECT_TYPE:
856     case WASM_VALUE_OBJECT_TYPE:
857 #endif  // V8_ENABLE_WEBASSEMBLY
858       return true;
859 
860     case BIGINT_TYPE:
861     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
862     case BYTECODE_ARRAY_TYPE:
863     case BYTE_ARRAY_TYPE:
864     case CELL_TYPE:
865     case CODE_TYPE:
866     case FILLER_TYPE:
867     case FIXED_ARRAY_TYPE:
868     case SCRIPT_CONTEXT_TABLE_TYPE:
869     case FIXED_DOUBLE_ARRAY_TYPE:
870     case FEEDBACK_METADATA_TYPE:
871     case FOREIGN_TYPE:
872     case FREE_SPACE_TYPE:
873     case HASH_TABLE_TYPE:
874     case ORDERED_HASH_MAP_TYPE:
875     case ORDERED_HASH_SET_TYPE:
876     case ORDERED_NAME_DICTIONARY_TYPE:
877     case NAME_DICTIONARY_TYPE:
878     case GLOBAL_DICTIONARY_TYPE:
879     case NUMBER_DICTIONARY_TYPE:
880     case SIMPLE_NUMBER_DICTIONARY_TYPE:
881     case HEAP_NUMBER_TYPE:
882     case JS_BOUND_FUNCTION_TYPE:
883     case JS_GLOBAL_OBJECT_TYPE:
884     case JS_GLOBAL_PROXY_TYPE:
885     case JS_PROXY_TYPE:
886     case JS_WRAPPED_FUNCTION_TYPE:
887     case MAP_TYPE:
888     case ODDBALL_TYPE:
889     case PROPERTY_CELL_TYPE:
890     case SHARED_FUNCTION_INFO_TYPE:
891     case SYMBOL_TYPE:
892     case ALLOCATION_SITE_TYPE:
893 
894 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
895   case FIXED_##TYPE##_ARRAY_TYPE:
896 #undef TYPED_ARRAY_CASE
897 
898 #define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
899       STRUCT_LIST(MAKE_STRUCT_CASE)
900 #undef MAKE_STRUCT_CASE
901       // We must not end up here for these instance types at all.
902       UNREACHABLE();
903     // Fall through.
904     default:
905       return false;
906   }
907 }
908 #endif  // DEBUG
909 
FastInitializeDerivedMap(Isolate * isolate,Handle<JSFunction> new_target,Handle<JSFunction> constructor,Handle<Map> constructor_initial_map)910 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
911                               Handle<JSFunction> constructor,
912                               Handle<Map> constructor_initial_map) {
913   // Use the default intrinsic prototype instead.
914   if (!new_target->has_prototype_slot()) return false;
915   // Check that |function|'s initial map still in sync with the |constructor|,
916   // otherwise we must create a new initial map for |function|.
917   if (new_target->has_initial_map() &&
918       new_target->initial_map().GetConstructor() == *constructor) {
919     DCHECK(new_target->instance_prototype().IsJSReceiver());
920     return true;
921   }
922   InstanceType instance_type = constructor_initial_map->instance_type();
923   DCHECK(CanSubclassHaveInobjectProperties(instance_type));
924   // Create a new map with the size and number of in-object properties
925   // suggested by |function|.
926 
927   // Link initial map and constructor function if the new.target is actually a
928   // subclass constructor.
929   if (!IsDerivedConstructor(new_target->shared().kind())) return false;
930 
931   int instance_size;
932   int in_object_properties;
933   int embedder_fields =
934       JSObject::GetEmbedderFieldCount(*constructor_initial_map);
935   // Constructor expects certain number of in-object properties to be in the
936   // object. However, CalculateExpectedNofProperties() may return smaller value
937   // if 1) the constructor is not in the prototype chain of new_target, or
938   // 2) the prototype chain is modified during iteration, or 3) compilation
939   // failure occur during prototype chain iteration.
940   // So we take the maximum of two values.
941   int expected_nof_properties = std::max(
942       static_cast<int>(constructor->shared().expected_nof_properties()),
943       JSFunction::CalculateExpectedNofProperties(isolate, new_target));
944   JSFunction::CalculateInstanceSizeHelper(
945       instance_type, constructor_initial_map->has_prototype_slot(),
946       embedder_fields, expected_nof_properties, &instance_size,
947       &in_object_properties);
948 
949   int pre_allocated = constructor_initial_map->GetInObjectProperties() -
950                       constructor_initial_map->UnusedPropertyFields();
951   CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
952   int unused_property_fields = in_object_properties - pre_allocated;
953   Handle<Map> map =
954       Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
955                           in_object_properties, unused_property_fields);
956   map->set_new_target_is_base(false);
957   Handle<HeapObject> prototype(new_target->instance_prototype(), isolate);
958   JSFunction::SetInitialMap(isolate, new_target, map, prototype, constructor);
959   DCHECK(new_target->instance_prototype().IsJSReceiver());
960   map->set_construction_counter(Map::kNoSlackTracking);
961   map->StartInobjectSlackTracking();
962   return true;
963 }
964 
965 }  // namespace
966 
967 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)968 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
969                                            Handle<JSFunction> constructor,
970                                            Handle<JSReceiver> new_target) {
971   EnsureHasInitialMap(constructor);
972 
973   Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
974   if (*new_target == *constructor) return constructor_initial_map;
975 
976   Handle<Map> result_map;
977   // Fast case, new.target is a subclass of constructor. The map is cacheable
978   // (and may already have been cached). new.target.prototype is guaranteed to
979   // be a JSReceiver.
980   if (new_target->IsJSFunction()) {
981     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
982     if (FastInitializeDerivedMap(isolate, function, constructor,
983                                  constructor_initial_map)) {
984       return handle(function->initial_map(), isolate);
985     }
986   }
987 
988   // Slow path, new.target is either a proxy or can't cache the map.
989   // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
990   // fall back to the intrinsicDefaultProto.
991   Handle<Object> prototype;
992   if (new_target->IsJSFunction()) {
993     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
994     if (function->has_prototype_slot()) {
995       // Make sure the new.target.prototype is cached.
996       EnsureHasInitialMap(function);
997       prototype = handle(function->prototype(), isolate);
998     } else {
999       // No prototype property, use the intrinsict default proto further down.
1000       prototype = isolate->factory()->undefined_value();
1001     }
1002   } else {
1003     Handle<String> prototype_string = isolate->factory()->prototype_string();
1004     ASSIGN_RETURN_ON_EXCEPTION(
1005         isolate, prototype,
1006         JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
1007     // The above prototype lookup might change the constructor and its
1008     // prototype, hence we have to reload the initial map.
1009     EnsureHasInitialMap(constructor);
1010     constructor_initial_map = handle(constructor->initial_map(), isolate);
1011   }
1012 
1013   // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
1014   // correct realm. Rather than directly fetching the .prototype, we fetch the
1015   // constructor that points to the .prototype. This relies on
1016   // constructor.prototype being FROZEN for those constructors.
1017   if (!prototype->IsJSReceiver()) {
1018     Handle<Context> context;
1019     ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
1020                                JSReceiver::GetFunctionRealm(new_target), Map);
1021     DCHECK(context->IsNativeContext());
1022     Handle<Object> maybe_index = JSReceiver::GetDataProperty(
1023         isolate, constructor,
1024         isolate->factory()->native_context_index_symbol());
1025     int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
1026                                      : Context::OBJECT_FUNCTION_INDEX;
1027     Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
1028                                          isolate);
1029     prototype = handle(realm_constructor->prototype(), isolate);
1030   }
1031 
1032   Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
1033   map->set_new_target_is_base(false);
1034   CHECK(prototype->IsJSReceiver());
1035   if (map->prototype() != *prototype)
1036     Map::SetPrototype(isolate, map, Handle<HeapObject>::cast(prototype));
1037   map->SetConstructor(*constructor);
1038   return map;
1039 }
1040 
1041 namespace {
1042 
1043 // Assert that the computations in TypedArrayElementsKindToConstructorIndex and
1044 // TypedArrayElementsKindToRabGsabCtorIndex are sound.
1045 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                         \
1046   STATIC_ASSERT(Context::TYPE##_ARRAY_FUN_INDEX ==                        \
1047                 Context::FIRST_FIXED_TYPED_ARRAY_FUN_INDEX +              \
1048                     ElementsKind::TYPE##_ELEMENTS -                       \
1049                     ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); \
1050   STATIC_ASSERT(Context::RAB_GSAB_##TYPE##_ARRAY_MAP_INDEX ==             \
1051                 Context::FIRST_RAB_GSAB_TYPED_ARRAY_MAP_INDEX +           \
1052                     ElementsKind::TYPE##_ELEMENTS -                       \
1053                     ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
1054 
TYPED_ARRAYS(TYPED_ARRAY_CASE)1055 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1056 #undef TYPED_ARRAY_CASE
1057 
1058 int TypedArrayElementsKindToConstructorIndex(ElementsKind elements_kind) {
1059   return Context::FIRST_FIXED_TYPED_ARRAY_FUN_INDEX + elements_kind -
1060          ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
1061 }
1062 
TypedArrayElementsKindToRabGsabCtorIndex(ElementsKind elements_kind)1063 int TypedArrayElementsKindToRabGsabCtorIndex(ElementsKind elements_kind) {
1064   return Context::FIRST_RAB_GSAB_TYPED_ARRAY_MAP_INDEX + elements_kind -
1065          ElementsKind::FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
1066 }
1067 
1068 }  // namespace
1069 
GetDerivedRabGsabMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)1070 Handle<Map> JSFunction::GetDerivedRabGsabMap(Isolate* isolate,
1071                                              Handle<JSFunction> constructor,
1072                                              Handle<JSReceiver> new_target) {
1073   Handle<Map> map =
1074       GetDerivedMap(isolate, constructor, new_target).ToHandleChecked();
1075   {
1076     DisallowHeapAllocation no_alloc;
1077     NativeContext context = isolate->context().native_context();
1078     int ctor_index =
1079         TypedArrayElementsKindToConstructorIndex(map->elements_kind());
1080     if (*new_target == context.get(ctor_index)) {
1081       ctor_index =
1082           TypedArrayElementsKindToRabGsabCtorIndex(map->elements_kind());
1083       return handle(Map::cast(context.get(ctor_index)), isolate);
1084     }
1085   }
1086 
1087   // This only happens when subclassing TypedArrays. Create a new map with the
1088   // corresponding RAB / GSAB ElementsKind. Note: the map is not cached and
1089   // reused -> every array gets a unique map, making ICs slow.
1090   Handle<Map> rab_gsab_map = Map::Copy(isolate, map, "RAB / GSAB");
1091   rab_gsab_map->set_elements_kind(
1092       GetCorrespondingRabGsabElementsKind(map->elements_kind()));
1093   return rab_gsab_map;
1094 }
1095 
ComputeInstanceSizeWithMinSlack(Isolate * isolate)1096 int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
1097   CHECK(has_initial_map());
1098   if (initial_map().IsInobjectSlackTrackingInProgress()) {
1099     int slack = initial_map().ComputeMinObjectSlack(isolate);
1100     return initial_map().InstanceSizeFromSlack(slack);
1101   }
1102   return initial_map().instance_size();
1103 }
1104 
DebugNameCStr()1105 std::unique_ptr<char[]> JSFunction::DebugNameCStr() {
1106   return shared().DebugNameCStr();
1107 }
1108 
PrintName(FILE * out)1109 void JSFunction::PrintName(FILE* out) {
1110   PrintF(out, "%s", DebugNameCStr().get());
1111 }
1112 
1113 namespace {
1114 
UseFastFunctionNameLookup(Isolate * isolate,Map map)1115 bool UseFastFunctionNameLookup(Isolate* isolate, Map map) {
1116   DCHECK(map.IsJSFunctionMap());
1117   if (map.NumberOfOwnDescriptors() <
1118       JSFunction::kMinDescriptorsForFastBindAndWrap) {
1119     return false;
1120   }
1121   DCHECK(!map.is_dictionary_map());
1122   HeapObject value;
1123   ReadOnlyRoots roots(isolate);
1124   auto descriptors = map.instance_descriptors(isolate);
1125   InternalIndex kNameIndex{JSFunction::kNameDescriptorIndex};
1126   if (descriptors.GetKey(kNameIndex) != roots.name_string() ||
1127       !descriptors.GetValue(kNameIndex)
1128            .GetHeapObjectIfStrong(isolate, &value)) {
1129     return false;
1130   }
1131   return value.IsAccessorInfo();
1132 }
1133 
1134 }  // namespace
1135 
GetDebugName(Handle<JSFunction> function)1136 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
1137   // Below we use the same fast-path that we already established for
1138   // Function.prototype.bind(), where we avoid a slow "name" property
1139   // lookup if the DescriptorArray for the |function| still has the
1140   // "name" property at the original spot and that property is still
1141   // implemented via an AccessorInfo (which effectively means that
1142   // it must be the FunctionNameGetter).
1143   Isolate* isolate = function->GetIsolate();
1144   if (!UseFastFunctionNameLookup(isolate, function->map())) {
1145     // Normally there should be an else case for the fast-path check
1146     // above, which should invoke JSFunction::GetName(), since that's
1147     // what the FunctionNameGetter does, however GetDataProperty() has
1148     // never invoked accessors and thus always returned undefined for
1149     // JSFunction where the "name" property is untouched, so we retain
1150     // that exact behavior and go with SharedFunctionInfo::DebugName()
1151     // in case of the fast-path.
1152     Handle<Object> name =
1153         GetDataProperty(isolate, function, isolate->factory()->name_string());
1154     if (name->IsString()) return Handle<String>::cast(name);
1155   }
1156   return SharedFunctionInfo::DebugName(handle(function->shared(), isolate));
1157 }
1158 
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)1159 bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
1160                          Handle<String> prefix) {
1161   Isolate* isolate = function->GetIsolate();
1162   Handle<String> function_name;
1163   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
1164                                    Name::ToFunctionName(isolate, name), false);
1165   if (prefix->length() > 0) {
1166     IncrementalStringBuilder builder(isolate);
1167     builder.AppendString(prefix);
1168     builder.AppendCharacter(' ');
1169     builder.AppendString(function_name);
1170     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
1171                                      false);
1172   }
1173   RETURN_ON_EXCEPTION_VALUE(
1174       isolate,
1175       JSObject::DefinePropertyOrElementIgnoreAttributes(
1176           function, isolate->factory()->name_string(), function_name,
1177           static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
1178       false);
1179   return true;
1180 }
1181 
1182 namespace {
1183 
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)1184 Handle<String> NativeCodeFunctionSourceString(
1185     Handle<SharedFunctionInfo> shared_info) {
1186   Isolate* const isolate = shared_info->GetIsolate();
1187   IncrementalStringBuilder builder(isolate);
1188   builder.AppendCStringLiteral("function ");
1189   builder.AppendString(handle(shared_info->Name(), isolate));
1190   builder.AppendCStringLiteral("() { [native code] }");
1191   return builder.Finish().ToHandleChecked();
1192 }
1193 
1194 }  // namespace
1195 
1196 // static
ToString(Handle<JSFunction> function)1197 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
1198   Isolate* const isolate = function->GetIsolate();
1199   Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
1200 
1201   // Check if {function} should hide its source code.
1202   if (!shared_info->IsUserJavaScript()) {
1203     return NativeCodeFunctionSourceString(shared_info);
1204   }
1205 
1206   // Check if we should print {function} as a class.
1207   Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
1208       isolate, function, isolate->factory()->class_positions_symbol());
1209   if (maybe_class_positions->IsClassPositions()) {
1210     ClassPositions class_positions =
1211         ClassPositions::cast(*maybe_class_positions);
1212     int start_position = class_positions.start();
1213     int end_position = class_positions.end();
1214     Handle<String> script_source(
1215         String::cast(Script::cast(shared_info->script()).source()), isolate);
1216     return isolate->factory()->NewSubString(script_source, start_position,
1217                                             end_position);
1218   }
1219 
1220   // Check if we have source code for the {function}.
1221   if (!shared_info->HasSourceCode()) {
1222     return NativeCodeFunctionSourceString(shared_info);
1223   }
1224 
1225   // If this function was compiled from asm.js, use the recorded offset
1226   // information.
1227 #if V8_ENABLE_WEBASSEMBLY
1228   if (shared_info->HasWasmExportedFunctionData()) {
1229     Handle<WasmExportedFunctionData> function_data(
1230         shared_info->wasm_exported_function_data(), isolate);
1231     const wasm::WasmModule* module = function_data->instance().module();
1232     if (is_asmjs_module(module)) {
1233       std::pair<int, int> offsets =
1234           module->asm_js_offset_information->GetFunctionOffsets(
1235               declared_function_index(module, function_data->function_index()));
1236       Handle<String> source(
1237           String::cast(Script::cast(shared_info->script()).source()), isolate);
1238       return isolate->factory()->NewSubString(source, offsets.first,
1239                                               offsets.second);
1240     }
1241   }
1242 #endif  // V8_ENABLE_WEBASSEMBLY
1243 
1244   if (shared_info->function_token_position() == kNoSourcePosition) {
1245     // If the function token position isn't valid, return [native code] to
1246     // ensure calling eval on the returned source code throws rather than
1247     // giving inconsistent call behaviour.
1248     isolate->CountUsage(
1249         v8::Isolate::UseCounterFeature::kFunctionTokenOffsetTooLongForToString);
1250     return NativeCodeFunctionSourceString(shared_info);
1251   }
1252   return Handle<String>::cast(
1253       SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
1254 }
1255 
1256 // static
CalculateExpectedNofProperties(Isolate * isolate,Handle<JSFunction> function)1257 int JSFunction::CalculateExpectedNofProperties(Isolate* isolate,
1258                                                Handle<JSFunction> function) {
1259   int expected_nof_properties = 0;
1260   for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
1261        !iter.IsAtEnd(); iter.Advance()) {
1262     Handle<JSReceiver> current =
1263         PrototypeIterator::GetCurrent<JSReceiver>(iter);
1264     if (!current->IsJSFunction()) break;
1265     Handle<JSFunction> func = Handle<JSFunction>::cast(current);
1266     // The super constructor should be compiled for the number of expected
1267     // properties to be available.
1268     Handle<SharedFunctionInfo> shared(func->shared(), isolate);
1269     IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
1270     if (is_compiled_scope.is_compiled() ||
1271         Compiler::Compile(isolate, func, Compiler::CLEAR_EXCEPTION,
1272                           &is_compiled_scope)) {
1273       DCHECK(shared->is_compiled());
1274       int count = shared->expected_nof_properties();
1275       // Check that the estimate is sensible.
1276       if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
1277         expected_nof_properties += count;
1278       } else {
1279         return JSObject::kMaxInObjectProperties;
1280       }
1281     } else {
1282       // In case there was a compilation error proceed iterating in case there
1283       // will be a builtin function in the prototype chain that requires
1284       // certain number of in-object properties.
1285       continue;
1286     }
1287   }
1288   // Inobject slack tracking will reclaim redundant inobject space
1289   // later, so we can afford to adjust the estimate generously,
1290   // meaning we over-allocate by at least 8 slots in the beginning.
1291   if (expected_nof_properties > 0) {
1292     expected_nof_properties += 8;
1293     if (expected_nof_properties > JSObject::kMaxInObjectProperties) {
1294       expected_nof_properties = JSObject::kMaxInObjectProperties;
1295     }
1296   }
1297   return expected_nof_properties;
1298 }
1299 
1300 // static
CalculateInstanceSizeHelper(InstanceType instance_type,bool has_prototype_slot,int requested_embedder_fields,int requested_in_object_properties,int * instance_size,int * in_object_properties)1301 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
1302                                              bool has_prototype_slot,
1303                                              int requested_embedder_fields,
1304                                              int requested_in_object_properties,
1305                                              int* instance_size,
1306                                              int* in_object_properties) {
1307   DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
1308             JSObject::kMaxEmbedderFields);
1309   int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
1310   requested_embedder_fields *= kEmbedderDataSlotSizeInTaggedSlots;
1311 
1312   int max_nof_fields =
1313       (JSObject::kMaxInstanceSize - header_size) >> kTaggedSizeLog2;
1314   CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
1315   CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
1316            static_cast<unsigned>(max_nof_fields));
1317   *in_object_properties = std::min(requested_in_object_properties,
1318                                    max_nof_fields - requested_embedder_fields);
1319   *instance_size =
1320       header_size +
1321       ((requested_embedder_fields + *in_object_properties) << kTaggedSizeLog2);
1322   CHECK_EQ(*in_object_properties,
1323            ((*instance_size - header_size) >> kTaggedSizeLog2) -
1324                requested_embedder_fields);
1325   CHECK_LE(static_cast<unsigned>(*instance_size),
1326            static_cast<unsigned>(JSObject::kMaxInstanceSize));
1327 }
1328 
ClearTypeFeedbackInfo()1329 void JSFunction::ClearTypeFeedbackInfo() {
1330   ResetIfCodeFlushed();
1331   if (has_feedback_vector()) {
1332     FeedbackVector vector = feedback_vector();
1333     Isolate* isolate = GetIsolate();
1334     if (vector.ClearSlots(isolate)) {
1335       IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(),
1336                             "ClearTypeFeedbackInfo");
1337     }
1338   }
1339 }
1340 
1341 }  // namespace internal
1342 }  // namespace v8
1343 
1344 #include "src/objects/object-macros-undef.h"
1345