• 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/heap/heap-inl.h"
10 #include "src/ic/ic.h"
11 #include "src/init/bootstrapper.h"
12 #include "src/objects/feedback-cell-inl.h"
13 #include "src/strings/string-builder-inl.h"
14 
15 // Has to be the last include (doesn't have include guards):
16 #include "src/objects/object-macros.h"
17 
18 namespace v8 {
19 namespace internal {
20 
GetAttachedCodeKinds() const21 CodeKinds JSFunction::GetAttachedCodeKinds() const {
22   CodeKinds result;
23 
24   // Note: There's a special case when bytecode has been aged away. After
25   // flushing the bytecode, the JSFunction will still have the interpreter
26   // entry trampoline attached, but the bytecode is no longer available.
27   if (code().is_interpreter_trampoline_builtin()) {
28     result |= CodeKindFlag::INTERPRETED_FUNCTION;
29   }
30 
31   const CodeKind kind = code().kind();
32   if (!CodeKindIsOptimizedJSFunction(kind) ||
33       code().marked_for_deoptimization()) {
34     DCHECK_EQ((result & ~kJSFunctionCodeKindsMask), 0);
35     return result;
36   }
37 
38   DCHECK(CodeKindIsOptimizedJSFunction(kind));
39   result |= CodeKindToCodeKindFlag(kind);
40 
41   DCHECK_EQ((result & ~kJSFunctionCodeKindsMask), 0);
42   return result;
43 }
44 
GetAvailableCodeKinds() const45 CodeKinds JSFunction::GetAvailableCodeKinds() const {
46   CodeKinds result = GetAttachedCodeKinds();
47 
48   if ((result & CodeKindFlag::INTERPRETED_FUNCTION) == 0) {
49     // The SharedFunctionInfo could have attached bytecode.
50     if (shared().HasBytecodeArray()) {
51       result |= CodeKindFlag::INTERPRETED_FUNCTION;
52     }
53   }
54 
55   if ((result & kOptimizedJSFunctionCodeKindsMask) == 0) {
56     // Check the optimized code cache.
57     if (has_feedback_vector() && feedback_vector().has_optimized_code() &&
58         !feedback_vector().optimized_code().marked_for_deoptimization()) {
59       Code code = feedback_vector().optimized_code();
60       DCHECK(CodeKindIsOptimizedJSFunction(code.kind()));
61       result |= CodeKindToCodeKindFlag(code.kind());
62     }
63   }
64 
65   DCHECK_EQ((result & ~kJSFunctionCodeKindsMask), 0);
66   return result;
67 }
68 
HasAttachedOptimizedCode() const69 bool JSFunction::HasAttachedOptimizedCode() const {
70   CodeKinds result = GetAttachedCodeKinds();
71   return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
72 }
73 
HasAvailableOptimizedCode() const74 bool JSFunction::HasAvailableOptimizedCode() const {
75   CodeKinds result = GetAvailableCodeKinds();
76   return (result & kOptimizedJSFunctionCodeKindsMask) != 0;
77 }
78 
HasAvailableCodeKind(CodeKind kind) const79 bool JSFunction::HasAvailableCodeKind(CodeKind kind) const {
80   CodeKinds result = GetAvailableCodeKinds();
81   return (result & CodeKindToCodeKindFlag(kind)) != 0;
82 }
83 
84 namespace {
85 
86 // Returns false if no highest tier exists (i.e. the function is not compiled),
87 // otherwise returns true and sets highest_tier.
HighestTierOf(CodeKinds kinds,CodeKind * highest_tier)88 bool HighestTierOf(CodeKinds kinds, CodeKind* highest_tier) {
89   DCHECK_EQ((kinds & ~kJSFunctionCodeKindsMask), 0);
90   if ((kinds & CodeKindFlag::TURBOFAN) != 0) {
91     *highest_tier = CodeKind::TURBOFAN;
92     return true;
93   } else if ((kinds & CodeKindFlag::TURBOPROP) != 0) {
94     *highest_tier = CodeKind::TURBOPROP;
95     return true;
96   } else if ((kinds & CodeKindFlag::NATIVE_CONTEXT_INDEPENDENT) != 0) {
97     *highest_tier = CodeKind::NATIVE_CONTEXT_INDEPENDENT;
98     return true;
99   } else if ((kinds & CodeKindFlag::INTERPRETED_FUNCTION) != 0) {
100     *highest_tier = CodeKind::INTERPRETED_FUNCTION;
101     return true;
102   }
103   DCHECK_EQ(kinds, 0);
104   return false;
105 }
106 
107 }  // namespace
108 
ActiveTierIsIgnition() const109 bool JSFunction::ActiveTierIsIgnition() const {
110   CodeKind highest_tier;
111   if (!HighestTierOf(GetAvailableCodeKinds(), &highest_tier)) return false;
112   bool result = (highest_tier == CodeKind::INTERPRETED_FUNCTION);
113   DCHECK_IMPLIES(result,
114                  code().is_interpreter_trampoline_builtin() ||
115                      (CodeKindIsOptimizedJSFunction(code().kind()) &&
116                       code().marked_for_deoptimization()) ||
117                      (code().builtin_index() == Builtins::kCompileLazy &&
118                       shared().IsInterpreted()));
119   return result;
120 }
121 
ActiveTierIsTurbofan() const122 bool JSFunction::ActiveTierIsTurbofan() const {
123   CodeKind highest_tier;
124   if (!HighestTierOf(GetAvailableCodeKinds(), &highest_tier)) return false;
125   return highest_tier == CodeKind::TURBOFAN;
126 }
127 
ActiveTierIsNCI() const128 bool JSFunction::ActiveTierIsNCI() const {
129   CodeKind highest_tier;
130   if (!HighestTierOf(GetAvailableCodeKinds(), &highest_tier)) return false;
131   return highest_tier == CodeKind::NATIVE_CONTEXT_INDEPENDENT;
132 }
133 
ActiveTierIsToptierTurboprop() const134 bool JSFunction::ActiveTierIsToptierTurboprop() const {
135   CodeKind highest_tier;
136   if (!FLAG_turboprop) return false;
137   if (!HighestTierOf(GetAvailableCodeKinds(), &highest_tier)) return false;
138   return highest_tier == CodeKind::TURBOPROP && !FLAG_turboprop_as_midtier;
139 }
140 
ActiveTierIsMidtierTurboprop() const141 bool JSFunction::ActiveTierIsMidtierTurboprop() const {
142   CodeKind highest_tier;
143   if (!FLAG_turboprop_as_midtier) return false;
144   if (!HighestTierOf(GetAvailableCodeKinds(), &highest_tier)) return false;
145   return highest_tier == CodeKind::TURBOPROP && FLAG_turboprop_as_midtier;
146 }
147 
NextTier() const148 CodeKind JSFunction::NextTier() const {
149   if (V8_UNLIKELY(FLAG_turbo_nci_as_midtier && ActiveTierIsIgnition())) {
150     return CodeKind::NATIVE_CONTEXT_INDEPENDENT;
151   } else if (V8_UNLIKELY(FLAG_turboprop) && ActiveTierIsMidtierTurboprop()) {
152     return CodeKind::TURBOFAN;
153   } else if (V8_UNLIKELY(FLAG_turboprop)) {
154     DCHECK(ActiveTierIsIgnition());
155     return CodeKind::TURBOPROP;
156   }
157   return CodeKind::TURBOFAN;
158 }
159 
CanDiscardCompiled() const160 bool JSFunction::CanDiscardCompiled() const {
161   // Essentially, what we are asking here is, has this function been compiled
162   // from JS code? We can currently tell only indirectly, by looking at
163   // available code kinds. If any JS code kind exists, we can discard.
164   //
165   // Attached optimized code that is marked for deoptimization will not show up
166   // in the list of available code kinds, thus we must check for it manually.
167   //
168   // Note that when the function has not yet been compiled we also return
169   // false; that's fine, since nothing must be discarded in that case.
170   if (CodeKindIsOptimizedJSFunction(code().kind())) return true;
171   CodeKinds result = GetAvailableCodeKinds();
172   return (result & kJSFunctionCodeKindsMask) != 0;
173 }
174 
175 // static
GetFunctionRealm(Handle<JSBoundFunction> function)176 MaybeHandle<NativeContext> JSBoundFunction::GetFunctionRealm(
177     Handle<JSBoundFunction> function) {
178   DCHECK(function->map().is_constructor());
179   return JSReceiver::GetFunctionRealm(
180       handle(function->bound_target_function(), function->GetIsolate()));
181 }
182 
183 // static
GetName(Isolate * isolate,Handle<JSBoundFunction> function)184 MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
185                                              Handle<JSBoundFunction> function) {
186   Handle<String> prefix = isolate->factory()->bound__string();
187   Handle<String> target_name = prefix;
188   Factory* factory = isolate->factory();
189   // Concatenate the "bound " up to the last non-bound target.
190   while (function->bound_target_function().IsJSBoundFunction()) {
191     ASSIGN_RETURN_ON_EXCEPTION(isolate, target_name,
192                                factory->NewConsString(prefix, target_name),
193                                String);
194     function = handle(JSBoundFunction::cast(function->bound_target_function()),
195                       isolate);
196   }
197   if (function->bound_target_function().IsJSFunction()) {
198     Handle<JSFunction> target(
199         JSFunction::cast(function->bound_target_function()), isolate);
200     Handle<Object> name = JSFunction::GetName(isolate, target);
201     if (!name->IsString()) return target_name;
202     return factory->NewConsString(target_name, Handle<String>::cast(name));
203   }
204   // This will omit the proper target name for bound JSProxies.
205   return target_name;
206 }
207 
208 // static
GetLength(Isolate * isolate,Handle<JSBoundFunction> function)209 Maybe<int> JSBoundFunction::GetLength(Isolate* isolate,
210                                       Handle<JSBoundFunction> function) {
211   int nof_bound_arguments = function->bound_arguments().length();
212   while (function->bound_target_function().IsJSBoundFunction()) {
213     function = handle(JSBoundFunction::cast(function->bound_target_function()),
214                       isolate);
215     // Make sure we never overflow {nof_bound_arguments}, the number of
216     // arguments of a function is strictly limited by the max length of an
217     // JSAarray, Smi::kMaxValue is thus a reasonably good overestimate.
218     int length = function->bound_arguments().length();
219     if (V8_LIKELY(Smi::kMaxValue - nof_bound_arguments > length)) {
220       nof_bound_arguments += length;
221     } else {
222       nof_bound_arguments = Smi::kMaxValue;
223     }
224   }
225   // All non JSFunction targets get a direct property and don't use this
226   // accessor.
227   Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
228                             isolate);
229   int target_length = target->length();
230 
231   int length = std::max(0, target_length - nof_bound_arguments);
232   return Just(length);
233 }
234 
235 // static
ToString(Handle<JSBoundFunction> function)236 Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
237   Isolate* const isolate = function->GetIsolate();
238   return isolate->factory()->function_native_code_string();
239 }
240 
241 // static
GetName(Isolate * isolate,Handle<JSFunction> function)242 Handle<Object> JSFunction::GetName(Isolate* isolate,
243                                    Handle<JSFunction> function) {
244   if (function->shared().name_should_print_as_anonymous()) {
245     return isolate->factory()->anonymous_string();
246   }
247   return handle(function->shared().Name(), isolate);
248 }
249 
250 // static
GetFunctionRealm(Handle<JSFunction> function)251 Handle<NativeContext> JSFunction::GetFunctionRealm(
252     Handle<JSFunction> function) {
253   DCHECK(function->map().is_constructor());
254   return handle(function->context().native_context(), function->GetIsolate());
255 }
256 
257 // static
EnsureClosureFeedbackCellArray(Handle<JSFunction> function)258 void JSFunction::EnsureClosureFeedbackCellArray(Handle<JSFunction> function) {
259   Isolate* const isolate = function->GetIsolate();
260   DCHECK(function->shared().is_compiled());
261   DCHECK(function->shared().HasFeedbackMetadata());
262   if (function->has_closure_feedback_cell_array() ||
263       function->has_feedback_vector()) {
264     return;
265   }
266   if (function->shared().HasAsmWasmData()) return;
267 
268   Handle<SharedFunctionInfo> shared(function->shared(), isolate);
269   DCHECK(function->shared().HasBytecodeArray());
270   Handle<HeapObject> feedback_cell_array =
271       ClosureFeedbackCellArray::New(isolate, shared);
272   // Many closure cell is used as a way to specify that there is no
273   // feedback cell for this function and a new feedback cell has to be
274   // allocated for this funciton. For ex: for eval functions, we have to create
275   // a feedback cell and cache it along with the code. It is safe to use
276   // many_closure_cell to indicate this because in regular cases, it should
277   // already have a feedback_vector / feedback cell array allocated.
278   if (function->raw_feedback_cell() == isolate->heap()->many_closures_cell()) {
279     Handle<FeedbackCell> feedback_cell =
280         isolate->factory()->NewOneClosureCell(feedback_cell_array);
281     function->set_raw_feedback_cell(*feedback_cell);
282   } else {
283     function->raw_feedback_cell().set_value(*feedback_cell_array);
284   }
285 }
286 
287 // static
EnsureFeedbackVector(Handle<JSFunction> function,IsCompiledScope * is_compiled_scope)288 void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function,
289                                       IsCompiledScope* is_compiled_scope) {
290   Isolate* const isolate = function->GetIsolate();
291   DCHECK(is_compiled_scope->is_compiled());
292   DCHECK(function->shared().HasFeedbackMetadata());
293   if (function->has_feedback_vector()) return;
294   if (function->shared().HasAsmWasmData()) return;
295 
296   Handle<SharedFunctionInfo> shared(function->shared(), isolate);
297   DCHECK(function->shared().HasBytecodeArray());
298 
299   EnsureClosureFeedbackCellArray(function);
300   Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
301       handle(function->closure_feedback_cell_array(), isolate);
302   Handle<HeapObject> feedback_vector = FeedbackVector::New(
303       isolate, shared, closure_feedback_cell_array, is_compiled_scope);
304   // EnsureClosureFeedbackCellArray should handle the special case where we need
305   // to allocate a new feedback cell. Please look at comment in that function
306   // for more details.
307   DCHECK(function->raw_feedback_cell() !=
308          isolate->heap()->many_closures_cell());
309   function->raw_feedback_cell().set_value(*feedback_vector);
310   function->raw_feedback_cell().SetInterruptBudget();
311 }
312 
313 // static
InitializeFeedbackCell(Handle<JSFunction> function,IsCompiledScope * is_compiled_scope)314 void JSFunction::InitializeFeedbackCell(Handle<JSFunction> function,
315                                         IsCompiledScope* is_compiled_scope) {
316   Isolate* const isolate = function->GetIsolate();
317 
318   if (function->has_feedback_vector()) {
319     CHECK_EQ(function->feedback_vector().length(),
320              function->feedback_vector().metadata().slot_count());
321     return;
322   }
323 
324   const bool needs_feedback_vector =
325       !FLAG_lazy_feedback_allocation || FLAG_always_opt ||
326       function->shared().may_have_cached_code() ||
327       // We also need a feedback vector for certain log events, collecting type
328       // profile and more precise code coverage.
329       FLAG_log_function_events || !isolate->is_best_effort_code_coverage() ||
330       isolate->is_collecting_type_profile();
331 
332   if (needs_feedback_vector) {
333     EnsureFeedbackVector(function, is_compiled_scope);
334   } else {
335     EnsureClosureFeedbackCellArray(function);
336   }
337 }
338 
339 namespace {
340 
SetInstancePrototype(Isolate * isolate,Handle<JSFunction> function,Handle<JSReceiver> value)341 void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
342                           Handle<JSReceiver> value) {
343   // Now some logic for the maps of the objects that are created by using this
344   // function as a constructor.
345   if (function->has_initial_map()) {
346     // If the function has allocated the initial map replace it with a
347     // copy containing the new prototype.  Also complete any in-object
348     // slack tracking that is in progress at this point because it is
349     // still tracking the old copy.
350     function->CompleteInobjectSlackTrackingIfActive();
351 
352     Handle<Map> initial_map(function->initial_map(), isolate);
353 
354     if (!isolate->bootstrapper()->IsActive() &&
355         initial_map->instance_type() == JS_OBJECT_TYPE) {
356       // Put the value in the initial map field until an initial map is needed.
357       // At that point, a new initial map is created and the prototype is put
358       // into the initial map where it belongs.
359       function->set_prototype_or_initial_map(*value);
360     } else {
361       Handle<Map> new_map =
362           Map::Copy(isolate, initial_map, "SetInstancePrototype");
363       JSFunction::SetInitialMap(function, new_map, value);
364 
365       // If the function is used as the global Array function, cache the
366       // updated initial maps (and transitioned versions) in the native context.
367       Handle<Context> native_context(function->context().native_context(),
368                                      isolate);
369       Handle<Object> array_function(
370           native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate);
371       if (array_function->IsJSFunction() &&
372           *function == JSFunction::cast(*array_function)) {
373         CacheInitialJSArrayMaps(isolate, native_context, new_map);
374       }
375     }
376 
377     // Deoptimize all code that embeds the previous initial map.
378     initial_map->dependent_code().DeoptimizeDependentCodeGroup(
379         DependentCode::kInitialMapChangedGroup);
380   } else {
381     // Put the value in the initial map field until an initial map is
382     // needed.  At that point, a new initial map is created and the
383     // prototype is put into the initial map where it belongs.
384     function->set_prototype_or_initial_map(*value);
385     if (value->IsJSObject()) {
386       // Optimize as prototype to detach it from its transition tree.
387       JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
388     }
389   }
390 }
391 
392 }  // anonymous namespace
393 
SetPrototype(Handle<JSFunction> function,Handle<Object> value)394 void JSFunction::SetPrototype(Handle<JSFunction> function,
395                               Handle<Object> value) {
396   DCHECK(function->IsConstructor() ||
397          IsGeneratorFunction(function->shared().kind()));
398   Isolate* isolate = function->GetIsolate();
399   Handle<JSReceiver> construct_prototype;
400 
401   // If the value is not a JSReceiver, store the value in the map's
402   // constructor field so it can be accessed.  Also, set the prototype
403   // used for constructing objects to the original object prototype.
404   // See ECMA-262 13.2.2.
405   if (!value->IsJSReceiver()) {
406     // Copy the map so this does not affect unrelated functions.
407     // Remove map transitions because they point to maps with a
408     // different prototype.
409     Handle<Map> new_map =
410         Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype");
411 
412     JSObject::MigrateToMap(isolate, function, new_map);
413     new_map->SetConstructor(*value);
414     new_map->set_has_non_instance_prototype(true);
415 
416     FunctionKind kind = function->shared().kind();
417     Handle<Context> native_context(function->context().native_context(),
418                                    isolate);
419 
420     construct_prototype = Handle<JSReceiver>(
421         IsGeneratorFunction(kind)
422             ? IsAsyncFunction(kind)
423                   ? native_context->initial_async_generator_prototype()
424                   : native_context->initial_generator_prototype()
425             : native_context->initial_object_prototype(),
426         isolate);
427   } else {
428     construct_prototype = Handle<JSReceiver>::cast(value);
429     function->map().set_has_non_instance_prototype(false);
430   }
431 
432   SetInstancePrototype(isolate, function, construct_prototype);
433 }
434 
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<HeapObject> prototype)435 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
436                                Handle<HeapObject> prototype) {
437   if (map->prototype() != *prototype) {
438     Map::SetPrototype(function->GetIsolate(), map, prototype);
439   }
440   function->set_prototype_or_initial_map(*map);
441   map->SetConstructor(*function);
442   if (FLAG_trace_maps) {
443     LOG(function->GetIsolate(), MapEvent("InitialMap", Handle<Map>(), map, "",
444                                          handle(function->shared().DebugName(),
445                                                 function->GetIsolate())));
446   }
447 }
448 
EnsureHasInitialMap(Handle<JSFunction> function)449 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
450   DCHECK(function->has_prototype_slot());
451   DCHECK(function->IsConstructor() ||
452          IsResumableFunction(function->shared().kind()));
453   if (function->has_initial_map()) return;
454   Isolate* isolate = function->GetIsolate();
455 
456   int expected_nof_properties =
457       CalculateExpectedNofProperties(isolate, function);
458 
459   // {CalculateExpectedNofProperties} can have had the side effect of creating
460   // the initial map (e.g. it could have triggered an optimized compilation
461   // whose dependency installation reentered {EnsureHasInitialMap}).
462   if (function->has_initial_map()) return;
463 
464   // Create a new map with the size and number of in-object properties suggested
465   // by the function.
466   InstanceType instance_type;
467   if (IsResumableFunction(function->shared().kind())) {
468     instance_type = IsAsyncGeneratorFunction(function->shared().kind())
469                         ? JS_ASYNC_GENERATOR_OBJECT_TYPE
470                         : JS_GENERATOR_OBJECT_TYPE;
471   } else {
472     instance_type = JS_OBJECT_TYPE;
473   }
474 
475   int instance_size;
476   int inobject_properties;
477   CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties,
478                               &instance_size, &inobject_properties);
479 
480   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size,
481                                                TERMINAL_FAST_ELEMENTS_KIND,
482                                                inobject_properties);
483 
484   // Fetch or allocate prototype.
485   Handle<HeapObject> prototype;
486   if (function->has_instance_prototype()) {
487     prototype = handle(function->instance_prototype(), isolate);
488   } else {
489     prototype = isolate->factory()->NewFunctionPrototype(function);
490   }
491   DCHECK(map->has_fast_object_elements());
492 
493   // Finally link initial map and constructor function.
494   DCHECK(prototype->IsJSReceiver());
495   JSFunction::SetInitialMap(function, map, prototype);
496   map->StartInobjectSlackTracking();
497 }
498 
499 namespace {
500 
501 #ifdef DEBUG
CanSubclassHaveInobjectProperties(InstanceType instance_type)502 bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
503   switch (instance_type) {
504     case JS_API_OBJECT_TYPE:
505     case JS_ARRAY_BUFFER_TYPE:
506     case JS_ARRAY_TYPE:
507     case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
508     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
509     case JS_DATA_VIEW_TYPE:
510     case JS_DATE_TYPE:
511     case JS_FUNCTION_TYPE:
512     case JS_GENERATOR_OBJECT_TYPE:
513 #ifdef V8_INTL_SUPPORT
514     case JS_COLLATOR_TYPE:
515     case JS_DATE_TIME_FORMAT_TYPE:
516     case JS_DISPLAY_NAMES_TYPE:
517     case JS_LIST_FORMAT_TYPE:
518     case JS_LOCALE_TYPE:
519     case JS_NUMBER_FORMAT_TYPE:
520     case JS_PLURAL_RULES_TYPE:
521     case JS_RELATIVE_TIME_FORMAT_TYPE:
522     case JS_SEGMENT_ITERATOR_TYPE:
523     case JS_SEGMENTER_TYPE:
524     case JS_SEGMENTS_TYPE:
525     case JS_V8_BREAK_ITERATOR_TYPE:
526 #endif
527     case JS_ASYNC_FUNCTION_OBJECT_TYPE:
528     case JS_ASYNC_GENERATOR_OBJECT_TYPE:
529     case JS_MAP_TYPE:
530     case JS_MESSAGE_OBJECT_TYPE:
531     case JS_OBJECT_TYPE:
532     case JS_ERROR_TYPE:
533     case JS_FINALIZATION_REGISTRY_TYPE:
534     case JS_ARGUMENTS_OBJECT_TYPE:
535     case JS_PROMISE_TYPE:
536     case JS_REG_EXP_TYPE:
537     case JS_SET_TYPE:
538     case JS_SPECIAL_API_OBJECT_TYPE:
539     case JS_TYPED_ARRAY_TYPE:
540     case JS_PRIMITIVE_WRAPPER_TYPE:
541     case JS_WEAK_MAP_TYPE:
542     case JS_WEAK_REF_TYPE:
543     case JS_WEAK_SET_TYPE:
544     case WASM_GLOBAL_OBJECT_TYPE:
545     case WASM_INSTANCE_OBJECT_TYPE:
546     case WASM_MEMORY_OBJECT_TYPE:
547     case WASM_MODULE_OBJECT_TYPE:
548     case WASM_TABLE_OBJECT_TYPE:
549       return true;
550 
551     case BIGINT_TYPE:
552     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
553     case BYTECODE_ARRAY_TYPE:
554     case BYTE_ARRAY_TYPE:
555     case CELL_TYPE:
556     case CODE_TYPE:
557     case FILLER_TYPE:
558     case FIXED_ARRAY_TYPE:
559     case SCRIPT_CONTEXT_TABLE_TYPE:
560     case FIXED_DOUBLE_ARRAY_TYPE:
561     case FEEDBACK_METADATA_TYPE:
562     case FOREIGN_TYPE:
563     case FREE_SPACE_TYPE:
564     case HASH_TABLE_TYPE:
565     case ORDERED_HASH_MAP_TYPE:
566     case ORDERED_HASH_SET_TYPE:
567     case ORDERED_NAME_DICTIONARY_TYPE:
568     case NAME_DICTIONARY_TYPE:
569     case GLOBAL_DICTIONARY_TYPE:
570     case NUMBER_DICTIONARY_TYPE:
571     case SIMPLE_NUMBER_DICTIONARY_TYPE:
572     case HEAP_NUMBER_TYPE:
573     case JS_BOUND_FUNCTION_TYPE:
574     case JS_GLOBAL_OBJECT_TYPE:
575     case JS_GLOBAL_PROXY_TYPE:
576     case JS_PROXY_TYPE:
577     case MAP_TYPE:
578     case ODDBALL_TYPE:
579     case PROPERTY_CELL_TYPE:
580     case SHARED_FUNCTION_INFO_TYPE:
581     case SYMBOL_TYPE:
582     case ALLOCATION_SITE_TYPE:
583 
584 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
585   case FIXED_##TYPE##_ARRAY_TYPE:
586 #undef TYPED_ARRAY_CASE
587 
588 #define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
589       STRUCT_LIST(MAKE_STRUCT_CASE)
590 #undef MAKE_STRUCT_CASE
591       // We must not end up here for these instance types at all.
592       UNREACHABLE();
593     // Fall through.
594     default:
595       return false;
596   }
597 }
598 #endif  // DEBUG
599 
FastInitializeDerivedMap(Isolate * isolate,Handle<JSFunction> new_target,Handle<JSFunction> constructor,Handle<Map> constructor_initial_map)600 bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
601                               Handle<JSFunction> constructor,
602                               Handle<Map> constructor_initial_map) {
603   // Use the default intrinsic prototype instead.
604   if (!new_target->has_prototype_slot()) return false;
605   // Check that |function|'s initial map still in sync with the |constructor|,
606   // otherwise we must create a new initial map for |function|.
607   if (new_target->has_initial_map() &&
608       new_target->initial_map().GetConstructor() == *constructor) {
609     DCHECK(new_target->instance_prototype().IsJSReceiver());
610     return true;
611   }
612   InstanceType instance_type = constructor_initial_map->instance_type();
613   DCHECK(CanSubclassHaveInobjectProperties(instance_type));
614   // Create a new map with the size and number of in-object properties
615   // suggested by |function|.
616 
617   // Link initial map and constructor function if the new.target is actually a
618   // subclass constructor.
619   if (!IsDerivedConstructor(new_target->shared().kind())) return false;
620 
621   int instance_size;
622   int in_object_properties;
623   int embedder_fields =
624       JSObject::GetEmbedderFieldCount(*constructor_initial_map);
625   // Constructor expects certain number of in-object properties to be in the
626   // object. However, CalculateExpectedNofProperties() may return smaller value
627   // if 1) the constructor is not in the prototype chain of new_target, or
628   // 2) the prototype chain is modified during iteration, or 3) compilation
629   // failure occur during prototype chain iteration.
630   // So we take the maximum of two values.
631   int expected_nof_properties = std::max(
632       static_cast<int>(constructor->shared().expected_nof_properties()),
633       JSFunction::CalculateExpectedNofProperties(isolate, new_target));
634   JSFunction::CalculateInstanceSizeHelper(
635       instance_type, true, embedder_fields, expected_nof_properties,
636       &instance_size, &in_object_properties);
637 
638   int pre_allocated = constructor_initial_map->GetInObjectProperties() -
639                       constructor_initial_map->UnusedPropertyFields();
640   CHECK_LE(constructor_initial_map->UsedInstanceSize(), instance_size);
641   int unused_property_fields = in_object_properties - pre_allocated;
642   Handle<Map> map =
643       Map::CopyInitialMap(isolate, constructor_initial_map, instance_size,
644                           in_object_properties, unused_property_fields);
645   map->set_new_target_is_base(false);
646   Handle<HeapObject> prototype(new_target->instance_prototype(), isolate);
647   JSFunction::SetInitialMap(new_target, map, prototype);
648   DCHECK(new_target->instance_prototype().IsJSReceiver());
649   map->SetConstructor(*constructor);
650   map->set_construction_counter(Map::kNoSlackTracking);
651   map->StartInobjectSlackTracking();
652   return true;
653 }
654 
655 }  // namespace
656 
657 // static
GetDerivedMap(Isolate * isolate,Handle<JSFunction> constructor,Handle<JSReceiver> new_target)658 MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
659                                            Handle<JSFunction> constructor,
660                                            Handle<JSReceiver> new_target) {
661   EnsureHasInitialMap(constructor);
662 
663   Handle<Map> constructor_initial_map(constructor->initial_map(), isolate);
664   if (*new_target == *constructor) return constructor_initial_map;
665 
666   Handle<Map> result_map;
667   // Fast case, new.target is a subclass of constructor. The map is cacheable
668   // (and may already have been cached). new.target.prototype is guaranteed to
669   // be a JSReceiver.
670   if (new_target->IsJSFunction()) {
671     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
672     if (FastInitializeDerivedMap(isolate, function, constructor,
673                                  constructor_initial_map)) {
674       return handle(function->initial_map(), isolate);
675     }
676   }
677 
678   // Slow path, new.target is either a proxy or can't cache the map.
679   // new.target.prototype is not guaranteed to be a JSReceiver, and may need to
680   // fall back to the intrinsicDefaultProto.
681   Handle<Object> prototype;
682   if (new_target->IsJSFunction()) {
683     Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
684     if (function->has_prototype_slot()) {
685       // Make sure the new.target.prototype is cached.
686       EnsureHasInitialMap(function);
687       prototype = handle(function->prototype(), isolate);
688     } else {
689       // No prototype property, use the intrinsict default proto further down.
690       prototype = isolate->factory()->undefined_value();
691     }
692   } else {
693     Handle<String> prototype_string = isolate->factory()->prototype_string();
694     ASSIGN_RETURN_ON_EXCEPTION(
695         isolate, prototype,
696         JSReceiver::GetProperty(isolate, new_target, prototype_string), Map);
697     // The above prototype lookup might change the constructor and its
698     // prototype, hence we have to reload the initial map.
699     EnsureHasInitialMap(constructor);
700     constructor_initial_map = handle(constructor->initial_map(), isolate);
701   }
702 
703   // If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
704   // correct realm. Rather than directly fetching the .prototype, we fetch the
705   // constructor that points to the .prototype. This relies on
706   // constructor.prototype being FROZEN for those constructors.
707   if (!prototype->IsJSReceiver()) {
708     Handle<Context> context;
709     ASSIGN_RETURN_ON_EXCEPTION(isolate, context,
710                                JSReceiver::GetFunctionRealm(new_target), Map);
711     DCHECK(context->IsNativeContext());
712     Handle<Object> maybe_index = JSReceiver::GetDataProperty(
713         constructor, isolate->factory()->native_context_index_symbol());
714     int index = maybe_index->IsSmi() ? Smi::ToInt(*maybe_index)
715                                      : Context::OBJECT_FUNCTION_INDEX;
716     Handle<JSFunction> realm_constructor(JSFunction::cast(context->get(index)),
717                                          isolate);
718     prototype = handle(realm_constructor->prototype(), isolate);
719   }
720 
721   Handle<Map> map = Map::CopyInitialMap(isolate, constructor_initial_map);
722   map->set_new_target_is_base(false);
723   CHECK(prototype->IsJSReceiver());
724   if (map->prototype() != *prototype)
725     Map::SetPrototype(isolate, map, Handle<HeapObject>::cast(prototype));
726   map->SetConstructor(*constructor);
727   return map;
728 }
729 
ComputeInstanceSizeWithMinSlack(Isolate * isolate)730 int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
731   CHECK(has_initial_map());
732   if (initial_map().IsInobjectSlackTrackingInProgress()) {
733     int slack = initial_map().ComputeMinObjectSlack(isolate);
734     return initial_map().InstanceSizeFromSlack(slack);
735   }
736   return initial_map().instance_size();
737 }
738 
PrintName(FILE * out)739 void JSFunction::PrintName(FILE* out) {
740   std::unique_ptr<char[]> name = shared().DebugName().ToCString();
741   PrintF(out, "%s", name.get());
742 }
743 
GetName(Handle<JSFunction> function)744 Handle<String> JSFunction::GetName(Handle<JSFunction> function) {
745   Isolate* isolate = function->GetIsolate();
746   Handle<Object> name =
747       JSReceiver::GetDataProperty(function, isolate->factory()->name_string());
748   if (name->IsString()) return Handle<String>::cast(name);
749   return handle(function->shared().DebugName(), isolate);
750 }
751 
GetDebugName(Handle<JSFunction> function)752 Handle<String> JSFunction::GetDebugName(Handle<JSFunction> function) {
753   Isolate* isolate = function->GetIsolate();
754   Handle<Object> name = JSReceiver::GetDataProperty(
755       function, isolate->factory()->display_name_string());
756   if (name->IsString()) return Handle<String>::cast(name);
757   return JSFunction::GetName(function);
758 }
759 
SetName(Handle<JSFunction> function,Handle<Name> name,Handle<String> prefix)760 bool JSFunction::SetName(Handle<JSFunction> function, Handle<Name> name,
761                          Handle<String> prefix) {
762   Isolate* isolate = function->GetIsolate();
763   Handle<String> function_name;
764   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name,
765                                    Name::ToFunctionName(isolate, name), false);
766   if (prefix->length() > 0) {
767     IncrementalStringBuilder builder(isolate);
768     builder.AppendString(prefix);
769     builder.AppendCharacter(' ');
770     builder.AppendString(function_name);
771     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, function_name, builder.Finish(),
772                                      false);
773   }
774   RETURN_ON_EXCEPTION_VALUE(
775       isolate,
776       JSObject::DefinePropertyOrElementIgnoreAttributes(
777           function, isolate->factory()->name_string(), function_name,
778           static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY)),
779       false);
780   return true;
781 }
782 
783 namespace {
784 
NativeCodeFunctionSourceString(Handle<SharedFunctionInfo> shared_info)785 Handle<String> NativeCodeFunctionSourceString(
786     Handle<SharedFunctionInfo> shared_info) {
787   Isolate* const isolate = shared_info->GetIsolate();
788   IncrementalStringBuilder builder(isolate);
789   builder.AppendCString("function ");
790   builder.AppendString(handle(shared_info->Name(), isolate));
791   builder.AppendCString("() { [native code] }");
792   return builder.Finish().ToHandleChecked();
793 }
794 
795 }  // namespace
796 
797 // static
ToString(Handle<JSFunction> function)798 Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
799   Isolate* const isolate = function->GetIsolate();
800   Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
801 
802   // Check if {function} should hide its source code.
803   if (!shared_info->IsUserJavaScript()) {
804     return NativeCodeFunctionSourceString(shared_info);
805   }
806 
807   // Check if we should print {function} as a class.
808   Handle<Object> maybe_class_positions = JSReceiver::GetDataProperty(
809       function, isolate->factory()->class_positions_symbol());
810   if (maybe_class_positions->IsClassPositions()) {
811     ClassPositions class_positions =
812         ClassPositions::cast(*maybe_class_positions);
813     int start_position = class_positions.start();
814     int end_position = class_positions.end();
815     Handle<String> script_source(
816         String::cast(Script::cast(shared_info->script()).source()), isolate);
817     return isolate->factory()->NewSubString(script_source, start_position,
818                                             end_position);
819   }
820 
821   // Check if we have source code for the {function}.
822   if (!shared_info->HasSourceCode()) {
823     return NativeCodeFunctionSourceString(shared_info);
824   }
825 
826   // If this function was compiled from asm.js, use the recorded offset
827   // information.
828   if (shared_info->HasWasmExportedFunctionData()) {
829     Handle<WasmExportedFunctionData> function_data(
830         shared_info->wasm_exported_function_data(), isolate);
831     const wasm::WasmModule* module = function_data->instance().module();
832     if (is_asmjs_module(module)) {
833       std::pair<int, int> offsets =
834           module->asm_js_offset_information->GetFunctionOffsets(
835               declared_function_index(module, function_data->function_index()));
836       Handle<String> source(
837           String::cast(Script::cast(shared_info->script()).source()), isolate);
838       return isolate->factory()->NewSubString(source, offsets.first,
839                                               offsets.second);
840     }
841   }
842 
843   if (shared_info->function_token_position() == kNoSourcePosition) {
844     // If the function token position isn't valid, return [native code] to
845     // ensure calling eval on the returned source code throws rather than
846     // giving inconsistent call behaviour.
847     isolate->CountUsage(
848         v8::Isolate::UseCounterFeature::kFunctionTokenOffsetTooLongForToString);
849     return NativeCodeFunctionSourceString(shared_info);
850   }
851   return Handle<String>::cast(
852       SharedFunctionInfo::GetSourceCodeHarmony(shared_info));
853 }
854 
855 // static
CalculateExpectedNofProperties(Isolate * isolate,Handle<JSFunction> function)856 int JSFunction::CalculateExpectedNofProperties(Isolate* isolate,
857                                                Handle<JSFunction> function) {
858   int expected_nof_properties = 0;
859   for (PrototypeIterator iter(isolate, function, kStartAtReceiver);
860        !iter.IsAtEnd(); iter.Advance()) {
861     Handle<JSReceiver> current =
862         PrototypeIterator::GetCurrent<JSReceiver>(iter);
863     if (!current->IsJSFunction()) break;
864     Handle<JSFunction> func = Handle<JSFunction>::cast(current);
865     // The super constructor should be compiled for the number of expected
866     // properties to be available.
867     Handle<SharedFunctionInfo> shared(func->shared(), isolate);
868     IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
869     if (is_compiled_scope.is_compiled() ||
870         Compiler::Compile(func, Compiler::CLEAR_EXCEPTION,
871                           &is_compiled_scope)) {
872       DCHECK(shared->is_compiled());
873       int count = shared->expected_nof_properties();
874       // Check that the estimate is sensible.
875       if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) {
876         expected_nof_properties += count;
877       } else {
878         return JSObject::kMaxInObjectProperties;
879       }
880     } else {
881       // In case there was a compilation error proceed iterating in case there
882       // will be a builtin function in the prototype chain that requires
883       // certain number of in-object properties.
884       continue;
885     }
886   }
887   // Inobject slack tracking will reclaim redundant inobject space
888   // later, so we can afford to adjust the estimate generously,
889   // meaning we over-allocate by at least 8 slots in the beginning.
890   if (expected_nof_properties > 0) {
891     expected_nof_properties += 8;
892     if (expected_nof_properties > JSObject::kMaxInObjectProperties) {
893       expected_nof_properties = JSObject::kMaxInObjectProperties;
894     }
895   }
896   return expected_nof_properties;
897 }
898 
899 // 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)900 void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
901                                              bool has_prototype_slot,
902                                              int requested_embedder_fields,
903                                              int requested_in_object_properties,
904                                              int* instance_size,
905                                              int* in_object_properties) {
906   DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
907             JSObject::kMaxEmbedderFields);
908   int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
909   if (requested_embedder_fields) {
910     // If there are embedder fields, then the embedder fields start offset must
911     // be properly aligned (embedder fields are located between object header
912     // and inobject fields).
913     header_size = RoundUp<kSystemPointerSize>(header_size);
914     requested_embedder_fields *= kEmbedderDataSlotSizeInTaggedSlots;
915   }
916   int max_nof_fields =
917       (JSObject::kMaxInstanceSize - header_size) >> kTaggedSizeLog2;
918   CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
919   CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
920            static_cast<unsigned>(max_nof_fields));
921   *in_object_properties = std::min(requested_in_object_properties,
922                                    max_nof_fields - requested_embedder_fields);
923   *instance_size =
924       header_size +
925       ((requested_embedder_fields + *in_object_properties) << kTaggedSizeLog2);
926   CHECK_EQ(*in_object_properties,
927            ((*instance_size - header_size) >> kTaggedSizeLog2) -
928                requested_embedder_fields);
929   CHECK_LE(static_cast<unsigned>(*instance_size),
930            static_cast<unsigned>(JSObject::kMaxInstanceSize));
931 }
932 
ClearTypeFeedbackInfo()933 void JSFunction::ClearTypeFeedbackInfo() {
934   ResetIfBytecodeFlushed();
935   if (has_feedback_vector()) {
936     FeedbackVector vector = feedback_vector();
937     Isolate* isolate = GetIsolate();
938     if (vector.ClearSlots(isolate)) {
939       IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(),
940                             "ClearTypeFeedbackInfo");
941     }
942   }
943 }
944 
945 }  // namespace internal
946 }  // namespace v8
947 
948 #include "src/objects/object-macros-undef.h"
949