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
20namespace v8 {
21namespace internal {
22
23CodeKinds 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
33CodeKinds 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
62bool JSFunction::HasAttachedOptimizedCode() const {
63  CodeKinds result = GetAttachedCodeKinds();
64  return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
65}
66
67bool JSFunction::HasAvailableOptimizedCode() const {
68  CodeKinds result = GetAvailableCodeKinds();
69  return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
70}
71
72bool JSFunction::HasAttachedCodeKind(CodeKind kind) const {
73  CodeKinds result = GetAttachedCodeKinds();
74  return (result & CodeKindToCodeKindFlag(kind)) != 0;
75}
76
77bool JSFunction::HasAvailableCodeKind(CodeKind kind) const {
78  CodeKinds result = GetAvailableCodeKinds();
79  return (result & CodeKindToCodeKindFlag(kind)) != 0;
80}
81
82namespace {
83
84// Returns false if no highest tier exists (i.e. the function is not compiled),
85// otherwise returns true and sets highest_tier.
86V8_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
101base::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
133bool JSFunction::ActiveTierIsIgnition() const {
134  return GetActiveTier() == CodeKind::INTERPRETED_FUNCTION;
135}
136
137bool JSFunction::ActiveTierIsBaseline() const {
138  return GetActiveTier() == CodeKind::BASELINE;
139}
140
141bool JSFunction::ActiveTierIsMaglev() const {
142  return GetActiveTier() == CodeKind::MAGLEV;
143}
144
145bool JSFunction::ActiveTierIsTurbofan() const {
146  return GetActiveTier() == CodeKind::TURBOFAN;
147}
148
149bool 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
164namespace {
165
166constexpr 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
179void 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
214void JSFunction::SetInterruptBudget(Isolate* isolate) {
215  raw_feedback_cell().set_interrupt_budget(
216      TieringManager::InterruptBudgetFor(isolate, *this));
217}
218
219// static
220Maybe<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
305MaybeHandle<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
337Maybe<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
374Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
375  Isolate* const isolate = function->GetIsolate();
376  return isolate->factory()->function_native_code_string();
377}
378
379// static
380MaybeHandle<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
402Maybe<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
419Handle<String> JSWrappedFunction::ToString(Handle<JSWrappedFunction> function) {
420  Isolate* const isolate = function->GetIsolate();
421  return isolate->factory()->function_native_code_string();
422}
423
424// static
425MaybeHandle<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
480Handle<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
489void 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
538void 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
552void 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
580void 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
620namespace {
621
622void 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
666void 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
706void JSFunction::SetInitialMap(Isolate* isolate, Handle<JSFunction> function,
707                               Handle<Map> map, Handle<HeapObject> prototype) {
708  SetInitialMap(isolate, function, map, prototype, function);
709}
710
711void 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
726void 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
776namespace {
777
778#ifdef DEBUG
779bool 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
910bool 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
968MaybeHandle<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
1041namespace {
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
1055TYPED_ARRAYS(TYPED_ARRAY_CASE)
1056#undef TYPED_ARRAY_CASE
1057
1058int 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
1063int 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
1070Handle<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
1096int 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
1105std::unique_ptr<char[]> JSFunction::DebugNameCStr() {
1106  return shared().DebugNameCStr();
1107}
1108
1109void JSFunction::PrintName(FILE* out) {
1110  PrintF(out, "%s", DebugNameCStr().get());
1111}
1112
1113namespace {
1114
1115bool 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
1136Handle<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
1159bool 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
1182namespace {
1183
1184Handle<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
1197Handle<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
1257int 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
1301void 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
1329void 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