• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 <stdlib.h>
6 
7 #include <limits>
8 
9 #include "src/builtins/accessors.h"
10 #include "src/common/globals.h"
11 #include "src/common/message-template.h"
12 #include "src/debug/debug.h"
13 #include "src/execution/arguments-inl.h"
14 #include "src/execution/frames-inl.h"
15 #include "src/execution/isolate-inl.h"
16 #include "src/logging/counters.h"
17 #include "src/logging/log.h"
18 #include "src/objects/elements.h"
19 #include "src/objects/hash-table-inl.h"
20 #include "src/objects/literal-objects-inl.h"
21 #include "src/objects/lookup-inl.h"
22 #include "src/objects/smi.h"
23 #include "src/objects/struct-inl.h"
24 #include "src/runtime/runtime-utils.h"
25 #include "src/runtime/runtime.h"
26 
27 namespace v8 {
28 namespace internal {
29 
30 
RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError)31 RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
32   HandleScope scope(isolate);
33   DCHECK_EQ(0, args.length());
34   THROW_NEW_ERROR_RETURN_FAILURE(
35       isolate, NewReferenceError(MessageTemplate::kUnsupportedSuper));
36 }
37 
38 
RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError)39 RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
40   HandleScope scope(isolate);
41   DCHECK_EQ(1, args.length());
42   Handle<JSFunction> constructor = args.at<JSFunction>(0);
43   Handle<String> name(constructor->shared().Name(), isolate);
44 
45   Handle<Context> context = handle(constructor->native_context(), isolate);
46   DCHECK(context->IsNativeContext());
47   Handle<JSFunction> realm_type_error_function(
48       JSFunction::cast(context->get(Context::TYPE_ERROR_FUNCTION_INDEX)),
49       isolate);
50   if (name->length() == 0) {
51     THROW_NEW_ERROR_RETURN_FAILURE(
52         isolate, NewError(realm_type_error_function,
53                           MessageTemplate::kAnonymousConstructorNonCallable));
54   }
55   THROW_NEW_ERROR_RETURN_FAILURE(
56       isolate, NewError(realm_type_error_function,
57                         MessageTemplate::kConstructorNonCallable, name));
58 }
59 
60 
RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError)61 RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) {
62   HandleScope scope(isolate);
63   DCHECK_EQ(0, args.length());
64   THROW_NEW_ERROR_RETURN_FAILURE(
65       isolate, NewTypeError(MessageTemplate::kStaticPrototype));
66 }
67 
RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError)68 RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) {
69   HandleScope scope(isolate);
70   DCHECK_EQ(0, args.length());
71   THROW_NEW_ERROR_RETURN_FAILURE(
72       isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled));
73 }
74 
RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled)75 RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled) {
76   HandleScope scope(isolate);
77   DCHECK_EQ(0, args.length());
78   THROW_NEW_ERROR_RETURN_FAILURE(
79       isolate, NewReferenceError(MessageTemplate::kSuperNotCalled));
80 }
81 
82 namespace {
83 
ThrowNotSuperConstructor(Isolate * isolate,Handle<Object> constructor,Handle<JSFunction> function)84 Object ThrowNotSuperConstructor(Isolate* isolate, Handle<Object> constructor,
85                                 Handle<JSFunction> function) {
86   Handle<String> super_name;
87   if (constructor->IsJSFunction()) {
88     super_name =
89         handle(Handle<JSFunction>::cast(constructor)->shared().Name(), isolate);
90   } else if (constructor->IsOddball()) {
91     DCHECK(constructor->IsNull(isolate));
92     super_name = isolate->factory()->null_string();
93   } else {
94     super_name = Object::NoSideEffectsToString(isolate, constructor);
95   }
96   // null constructor
97   if (super_name->length() == 0) {
98     super_name = isolate->factory()->null_string();
99   }
100   Handle<String> function_name(function->shared().Name(), isolate);
101   // anonymous class
102   if (function_name->length() == 0) {
103     THROW_NEW_ERROR_RETURN_FAILURE(
104         isolate,
105         NewTypeError(MessageTemplate::kNotSuperConstructorAnonymousClass,
106                      super_name));
107   }
108   THROW_NEW_ERROR_RETURN_FAILURE(
109       isolate, NewTypeError(MessageTemplate::kNotSuperConstructor, super_name,
110                             function_name));
111 }
112 
113 }  // namespace
114 
RUNTIME_FUNCTION(Runtime_ThrowNotSuperConstructor)115 RUNTIME_FUNCTION(Runtime_ThrowNotSuperConstructor) {
116   HandleScope scope(isolate);
117   DCHECK_EQ(2, args.length());
118   Handle<Object> constructor = args.at(0);
119   Handle<JSFunction> function = args.at<JSFunction>(1);
120   return ThrowNotSuperConstructor(isolate, constructor, function);
121 }
122 
123 namespace {
124 
125 template <typename Dictionary>
KeyToName(Isolate * isolate,Handle<Object> key)126 Handle<Name> KeyToName(Isolate* isolate, Handle<Object> key) {
127   STATIC_ASSERT((std::is_same<Dictionary, SwissNameDictionary>::value ||
128                  std::is_same<Dictionary, NameDictionary>::value));
129   DCHECK(key->IsName());
130   return Handle<Name>::cast(key);
131 }
132 
133 template <>
KeyToName(Isolate * isolate,Handle<Object> key)134 Handle<Name> KeyToName<NumberDictionary>(Isolate* isolate, Handle<Object> key) {
135   DCHECK(key->IsNumber());
136   return isolate->factory()->NumberToString(key);
137 }
138 
139 // Gets |index|'th argument which may be a class constructor object, a class
140 // prototype object or a class method. In the latter case the following
141 // post-processing may be required:
142 // 1) set method's name to a concatenation of |name_prefix| and |key| if the
143 //    method's shared function info indicates that method does not have a
144 //    shared name.
145 template <typename Dictionary>
GetMethodAndSetName(Isolate * isolate,RuntimeArguments & args,Smi index,Handle<String> name_prefix,Handle<Object> key)146 MaybeHandle<Object> GetMethodAndSetName(Isolate* isolate,
147                                         RuntimeArguments& args, Smi index,
148                                         Handle<String> name_prefix,
149                                         Handle<Object> key) {
150   int int_index = index.value();
151 
152   // Class constructor and prototype values do not require post processing.
153   if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
154     return args.at<Object>(int_index);
155   }
156 
157   Handle<JSFunction> method = args.at<JSFunction>(int_index);
158 
159   if (!method->shared().HasSharedName()) {
160     // TODO(ishell): method does not have a shared name at this point only if
161     // the key is a computed property name. However, the bytecode generator
162     // explicitly generates ToName bytecodes to ensure that the computed
163     // property name is properly converted to Name. So, we can actually be smart
164     // here and avoid converting Smi keys back to Name.
165     Handle<Name> name = KeyToName<Dictionary>(isolate, key);
166     if (!JSFunction::SetName(method, name, name_prefix)) {
167       return MaybeHandle<Object>();
168     }
169   }
170   return method;
171 }
172 
173 // Gets |index|'th argument which may be a class constructor object, a class
174 // prototype object or a class method.
175 // This is a simplified version of GetMethodAndSetName()
176 // function above that is used when it's guaranteed that the method has
177 // shared name.
GetMethodWithSharedName(Isolate * isolate,RuntimeArguments & args,Object index)178 Object GetMethodWithSharedName(Isolate* isolate, RuntimeArguments& args,
179                                Object index) {
180   DisallowGarbageCollection no_gc;
181   int int_index = Smi::ToInt(index);
182 
183   // Class constructor and prototype values do not require post processing.
184   if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
185     return args[int_index];
186   }
187 
188   Handle<JSFunction> method = args.at<JSFunction>(int_index);
189   DCHECK(method->shared().HasSharedName());
190   return *method;
191 }
192 
193 template <typename Dictionary>
ShallowCopyDictionaryTemplate(Isolate * isolate,Handle<Dictionary> dictionary_template)194 Handle<Dictionary> ShallowCopyDictionaryTemplate(
195     Isolate* isolate, Handle<Dictionary> dictionary_template) {
196   Handle<Dictionary> dictionary =
197       Dictionary::ShallowCopy(isolate, dictionary_template);
198   // Clone all AccessorPairs in the dictionary.
199   for (InternalIndex i : dictionary->IterateEntries()) {
200     Object value = dictionary->ValueAt(i);
201     if (value.IsAccessorPair()) {
202       Handle<AccessorPair> pair(AccessorPair::cast(value), isolate);
203       pair = AccessorPair::Copy(isolate, pair);
204       dictionary->ValueAtPut(i, *pair);
205     }
206   }
207   return dictionary;
208 }
209 
210 template <typename Dictionary>
SubstituteValues(Isolate * isolate,Handle<Dictionary> dictionary,RuntimeArguments & args)211 bool SubstituteValues(Isolate* isolate, Handle<Dictionary> dictionary,
212                       RuntimeArguments& args) {
213   // Replace all indices with proper methods.
214   ReadOnlyRoots roots(isolate);
215   for (InternalIndex i : dictionary->IterateEntries()) {
216     Object maybe_key = dictionary->KeyAt(i);
217     if (!Dictionary::IsKey(roots, maybe_key)) continue;
218     Handle<Object> key(maybe_key, isolate);
219     Handle<Object> value(dictionary->ValueAt(i), isolate);
220     if (value->IsAccessorPair()) {
221       Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
222       Object tmp = pair->getter();
223       if (tmp.IsSmi()) {
224         Handle<Object> result;
225         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
226             isolate, result,
227             GetMethodAndSetName<Dictionary>(isolate, args, Smi::cast(tmp),
228                                             isolate->factory()->get_string(),
229                                             key),
230             false);
231         pair->set_getter(*result);
232       }
233       tmp = pair->setter();
234       if (tmp.IsSmi()) {
235         Handle<Object> result;
236         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
237             isolate, result,
238             GetMethodAndSetName<Dictionary>(isolate, args, Smi::cast(tmp),
239                                             isolate->factory()->set_string(),
240                                             key),
241             false);
242         pair->set_setter(*result);
243       }
244     } else if (value->IsSmi()) {
245       Handle<Object> result;
246       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
247           isolate, result,
248           GetMethodAndSetName<Dictionary>(isolate, args, Smi::cast(*value),
249                                           isolate->factory()->empty_string(),
250                                           key),
251           false);
252       dictionary->ValueAtPut(i, *result);
253     }
254   }
255   return true;
256 }
257 
258 template <typename Dictionary>
UpdateProtectors(Isolate * isolate,Handle<JSObject> receiver,Handle<Dictionary> properties_dictionary)259 void UpdateProtectors(Isolate* isolate, Handle<JSObject> receiver,
260                       Handle<Dictionary> properties_dictionary) {
261   ReadOnlyRoots roots(isolate);
262   for (InternalIndex i : properties_dictionary->IterateEntries()) {
263     Object maybe_key = properties_dictionary->KeyAt(i);
264     if (!Dictionary::IsKey(roots, maybe_key)) continue;
265     Handle<Name> name(Name::cast(maybe_key), isolate);
266     LookupIterator::UpdateProtector(isolate, receiver, name);
267   }
268 }
269 
UpdateProtectors(Isolate * isolate,Handle<JSObject> receiver,Handle<DescriptorArray> properties_template)270 void UpdateProtectors(Isolate* isolate, Handle<JSObject> receiver,
271                       Handle<DescriptorArray> properties_template) {
272   int nof_descriptors = properties_template->number_of_descriptors();
273   for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
274     Handle<Name> name(properties_template->GetKey(i), isolate);
275     LookupIterator::UpdateProtector(isolate, receiver, name);
276   }
277 }
278 
AddDescriptorsByTemplate(Isolate * isolate,Handle<Map> map,Handle<DescriptorArray> descriptors_template,Handle<NumberDictionary> elements_dictionary_template,Handle<JSObject> receiver,RuntimeArguments & args)279 bool AddDescriptorsByTemplate(
280     Isolate* isolate, Handle<Map> map,
281     Handle<DescriptorArray> descriptors_template,
282     Handle<NumberDictionary> elements_dictionary_template,
283     Handle<JSObject> receiver, RuntimeArguments& args) {
284   int nof_descriptors = descriptors_template->number_of_descriptors();
285 
286   Handle<DescriptorArray> descriptors =
287       DescriptorArray::Allocate(isolate, nof_descriptors, 0);
288 
289   Handle<NumberDictionary> elements_dictionary =
290       *elements_dictionary_template ==
291               ReadOnlyRoots(isolate).empty_slow_element_dictionary()
292           ? elements_dictionary_template
293           : ShallowCopyDictionaryTemplate(isolate,
294                                           elements_dictionary_template);
295 
296   // Count the number of properties that must be in the instance and
297   // create the property array to hold the constants.
298   int count = 0;
299   for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
300     PropertyDetails details = descriptors_template->GetDetails(i);
301     if (details.location() == PropertyLocation::kDescriptor &&
302         details.kind() == PropertyKind::kData) {
303       count++;
304     }
305   }
306   Handle<PropertyArray> property_array =
307       isolate->factory()->NewPropertyArray(count);
308 
309   // Read values from |descriptors_template| and store possibly post-processed
310   // values into "instantiated" |descriptors| array.
311   int field_index = 0;
312   for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
313     Object value = descriptors_template->GetStrongValue(i);
314     if (value.IsAccessorPair()) {
315       Handle<AccessorPair> pair = AccessorPair::Copy(
316           isolate, handle(AccessorPair::cast(value), isolate));
317       value = *pair;
318     }
319     DisallowGarbageCollection no_gc;
320     Name name = descriptors_template->GetKey(i);
321     DCHECK(name.IsUniqueName());
322     PropertyDetails details = descriptors_template->GetDetails(i);
323     if (details.location() == PropertyLocation::kDescriptor) {
324       if (details.kind() == PropertyKind::kData) {
325         if (value.IsSmi()) {
326           value = GetMethodWithSharedName(isolate, args, value);
327         }
328         details = details.CopyWithRepresentation(
329             value.OptimalRepresentation(isolate));
330       } else {
331         DCHECK_EQ(PropertyKind::kAccessor, details.kind());
332         if (value.IsAccessorPair()) {
333           AccessorPair pair = AccessorPair::cast(value);
334           Object tmp = pair.getter();
335           if (tmp.IsSmi()) {
336             pair.set_getter(GetMethodWithSharedName(isolate, args, tmp));
337           }
338           tmp = pair.setter();
339           if (tmp.IsSmi()) {
340             pair.set_setter(GetMethodWithSharedName(isolate, args, tmp));
341           }
342         }
343       }
344     } else {
345       UNREACHABLE();
346     }
347     DCHECK(value.FitsRepresentation(details.representation()));
348     if (details.location() == PropertyLocation::kDescriptor &&
349         details.kind() == PropertyKind::kData) {
350       details =
351           PropertyDetails(details.kind(), details.attributes(),
352                           PropertyLocation::kField, PropertyConstness::kConst,
353                           details.representation(), field_index)
354               .set_pointer(details.pointer());
355 
356       property_array->set(field_index, value);
357       field_index++;
358       descriptors->Set(i, name, MaybeObject::FromObject(FieldType::Any()),
359                        details);
360     } else {
361       descriptors->Set(i, name, MaybeObject::FromObject(value), details);
362     }
363   }
364 
365   UpdateProtectors(isolate, receiver, descriptors_template);
366 
367   map->InitializeDescriptors(isolate, *descriptors);
368   if (elements_dictionary->NumberOfElements() > 0) {
369     if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
370                                             args)) {
371       return false;
372     }
373     map->set_elements_kind(DICTIONARY_ELEMENTS);
374   }
375 
376   // Atomically commit the changes.
377   receiver->set_map(*map, kReleaseStore);
378   if (elements_dictionary->NumberOfElements() > 0) {
379     receiver->set_elements(*elements_dictionary);
380   }
381   if (property_array->length() > 0) {
382     receiver->SetProperties(*property_array);
383   }
384   return true;
385 }
386 
387 // TODO(v8:7569): This is a workaround for the Handle vs MaybeHandle difference
388 // in the return types of the different Add functions:
389 // OrderedNameDictionary::Add returns MaybeHandle, NameDictionary::Add returns
390 // Handle.
391 template <typename T>
ToHandle(Handle<T> h)392 Handle<T> ToHandle(Handle<T> h) {
393   return h;
394 }
395 template <typename T>
ToHandle(MaybeHandle<T> h)396 Handle<T> ToHandle(MaybeHandle<T> h) {
397   return h.ToHandleChecked();
398 }
399 
400 template <typename Dictionary>
AddDescriptorsByTemplate(Isolate * isolate,Handle<Map> map,Handle<Dictionary> properties_dictionary_template,Handle<NumberDictionary> elements_dictionary_template,Handle<FixedArray> computed_properties,Handle<JSObject> receiver,RuntimeArguments & args)401 bool AddDescriptorsByTemplate(
402     Isolate* isolate, Handle<Map> map,
403     Handle<Dictionary> properties_dictionary_template,
404     Handle<NumberDictionary> elements_dictionary_template,
405     Handle<FixedArray> computed_properties, Handle<JSObject> receiver,
406     RuntimeArguments& args) {
407   int computed_properties_length = computed_properties->length();
408 
409   // Shallow-copy properties template.
410   Handle<Dictionary> properties_dictionary =
411       ShallowCopyDictionaryTemplate(isolate, properties_dictionary_template);
412   Handle<NumberDictionary> elements_dictionary =
413       ShallowCopyDictionaryTemplate(isolate, elements_dictionary_template);
414 
415   using ValueKind = ClassBoilerplate::ValueKind;
416   using ComputedEntryFlags = ClassBoilerplate::ComputedEntryFlags;
417 
418   // Merge computed properties with properties and elements dictionary
419   // templates.
420   int i = 0;
421   while (i < computed_properties_length) {
422     int flags = Smi::ToInt(computed_properties->get(i++));
423 
424     ValueKind value_kind = ComputedEntryFlags::ValueKindBits::decode(flags);
425     int key_index = ComputedEntryFlags::KeyIndexBits::decode(flags);
426     Smi value = Smi::FromInt(key_index + 1);  // Value follows name.
427 
428     Handle<Object> key = args.at(key_index);
429     DCHECK(key->IsName());
430     uint32_t element;
431     Handle<Name> name = Handle<Name>::cast(key);
432     if (name->AsArrayIndex(&element)) {
433       ClassBoilerplate::AddToElementsTemplate(
434           isolate, elements_dictionary, element, key_index, value_kind, value);
435 
436     } else {
437       name = isolate->factory()->InternalizeName(name);
438       ClassBoilerplate::AddToPropertiesTemplate(
439           isolate, properties_dictionary, name, key_index, value_kind, value);
440     }
441   }
442 
443   // Replace all indices with proper methods.
444   if (!SubstituteValues<Dictionary>(isolate, properties_dictionary, args)) {
445     return false;
446   }
447 
448   UpdateProtectors(isolate, receiver, properties_dictionary);
449 
450   if (elements_dictionary->NumberOfElements() > 0) {
451     if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
452                                             args)) {
453       return false;
454     }
455     map->set_elements_kind(DICTIONARY_ELEMENTS);
456   }
457 
458   // Atomically commit the changes.
459   receiver->set_map(*map, kReleaseStore);
460   receiver->set_raw_properties_or_hash(*properties_dictionary, kRelaxedStore);
461   if (elements_dictionary->NumberOfElements() > 0) {
462     receiver->set_elements(*elements_dictionary);
463   }
464   return true;
465 }
466 
CreateClassPrototype(Isolate * isolate)467 Handle<JSObject> CreateClassPrototype(Isolate* isolate) {
468   // For constant tracking we want to avoid the hassle of handling
469   // in-object properties, so create a map with no in-object
470   // properties.
471 
472   // TODO(ishell) Support caching of zero in-object properties map
473   // by ObjectLiteralMapFromCache().
474   Handle<Map> map = Map::Create(isolate, 0);
475   return isolate->factory()->NewJSObjectFromMap(map);
476 }
477 
InitClassPrototype(Isolate * isolate,Handle<ClassBoilerplate> class_boilerplate,Handle<JSObject> prototype,Handle<HeapObject> prototype_parent,Handle<JSFunction> constructor,RuntimeArguments & args)478 bool InitClassPrototype(Isolate* isolate,
479                         Handle<ClassBoilerplate> class_boilerplate,
480                         Handle<JSObject> prototype,
481                         Handle<HeapObject> prototype_parent,
482                         Handle<JSFunction> constructor,
483                         RuntimeArguments& args) {
484   Handle<Map> map(prototype->map(), isolate);
485   map = Map::CopyDropDescriptors(isolate, map);
486   map->set_is_prototype_map(true);
487   Map::SetPrototype(isolate, map, prototype_parent);
488   constructor->set_prototype_or_initial_map(*prototype, kReleaseStore);
489   map->SetConstructor(*constructor);
490   Handle<FixedArray> computed_properties(
491       class_boilerplate->instance_computed_properties(), isolate);
492   Handle<NumberDictionary> elements_dictionary_template(
493       NumberDictionary::cast(class_boilerplate->instance_elements_template()),
494       isolate);
495 
496   Handle<Object> properties_template(
497       class_boilerplate->instance_properties_template(), isolate);
498 
499   if (properties_template->IsDescriptorArray()) {
500     Handle<DescriptorArray> descriptors_template =
501         Handle<DescriptorArray>::cast(properties_template);
502 
503     // The size of the prototype object is known at this point.
504     // So we can create it now and then add the rest instance methods to the
505     // map.
506     return AddDescriptorsByTemplate(isolate, map, descriptors_template,
507                                     elements_dictionary_template, prototype,
508                                     args);
509   } else {
510     map->set_is_dictionary_map(true);
511     map->set_is_migration_target(false);
512     map->set_may_have_interesting_symbols(true);
513     map->set_construction_counter(Map::kNoSlackTracking);
514 
515     if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
516       Handle<SwissNameDictionary> properties_dictionary_template =
517           Handle<SwissNameDictionary>::cast(properties_template);
518       return AddDescriptorsByTemplate(
519           isolate, map, properties_dictionary_template,
520           elements_dictionary_template, computed_properties, prototype, args);
521     } else {
522       Handle<NameDictionary> properties_dictionary_template =
523           Handle<NameDictionary>::cast(properties_template);
524       return AddDescriptorsByTemplate(
525           isolate, map, properties_dictionary_template,
526           elements_dictionary_template, computed_properties, prototype, args);
527     }
528   }
529 }
530 
InitClassConstructor(Isolate * isolate,Handle<ClassBoilerplate> class_boilerplate,Handle<HeapObject> constructor_parent,Handle<JSFunction> constructor,RuntimeArguments & args)531 bool InitClassConstructor(Isolate* isolate,
532                           Handle<ClassBoilerplate> class_boilerplate,
533                           Handle<HeapObject> constructor_parent,
534                           Handle<JSFunction> constructor,
535                           RuntimeArguments& args) {
536   Handle<Map> map(constructor->map(), isolate);
537   map = Map::CopyDropDescriptors(isolate, map);
538   DCHECK(map->is_prototype_map());
539 
540   if (!constructor_parent.is_null()) {
541     // Set map's prototype without enabling prototype setup mode for superclass
542     // because it does not make sense.
543     Map::SetPrototype(isolate, map, constructor_parent, false);
544     // Ensure that setup mode will never be enabled for superclass.
545     JSObject::MakePrototypesFast(constructor_parent, kStartAtReceiver, isolate);
546   }
547 
548   Handle<NumberDictionary> elements_dictionary_template(
549       NumberDictionary::cast(class_boilerplate->static_elements_template()),
550       isolate);
551   Handle<FixedArray> computed_properties(
552       class_boilerplate->static_computed_properties(), isolate);
553 
554   Handle<Object> properties_template(
555       class_boilerplate->static_properties_template(), isolate);
556 
557   if (properties_template->IsDescriptorArray()) {
558     Handle<DescriptorArray> descriptors_template =
559         Handle<DescriptorArray>::cast(properties_template);
560 
561     return AddDescriptorsByTemplate(isolate, map, descriptors_template,
562                                     elements_dictionary_template, constructor,
563                                     args);
564   } else {
565     map->set_is_dictionary_map(true);
566     map->InitializeDescriptors(isolate,
567                                ReadOnlyRoots(isolate).empty_descriptor_array());
568     map->set_is_migration_target(false);
569     map->set_may_have_interesting_symbols(true);
570     map->set_construction_counter(Map::kNoSlackTracking);
571 
572     if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
573       Handle<SwissNameDictionary> properties_dictionary_template =
574           Handle<SwissNameDictionary>::cast(properties_template);
575 
576       return AddDescriptorsByTemplate(
577           isolate, map, properties_dictionary_template,
578           elements_dictionary_template, computed_properties, constructor, args);
579     } else {
580       Handle<NameDictionary> properties_dictionary_template =
581           Handle<NameDictionary>::cast(properties_template);
582       return AddDescriptorsByTemplate(
583           isolate, map, properties_dictionary_template,
584           elements_dictionary_template, computed_properties, constructor, args);
585     }
586   }
587 }
588 
DefineClass(Isolate * isolate,Handle<ClassBoilerplate> class_boilerplate,Handle<Object> super_class,Handle<JSFunction> constructor,RuntimeArguments & args)589 MaybeHandle<Object> DefineClass(Isolate* isolate,
590                                 Handle<ClassBoilerplate> class_boilerplate,
591                                 Handle<Object> super_class,
592                                 Handle<JSFunction> constructor,
593                                 RuntimeArguments& args) {
594   Handle<Object> prototype_parent;
595   Handle<HeapObject> constructor_parent;
596 
597   if (super_class->IsTheHole(isolate)) {
598     prototype_parent = isolate->initial_object_prototype();
599   } else {
600     if (super_class->IsNull(isolate)) {
601       prototype_parent = isolate->factory()->null_value();
602     } else if (super_class->IsConstructor()) {
603       DCHECK(!super_class->IsJSFunction() ||
604              !IsResumableFunction(
605                  Handle<JSFunction>::cast(super_class)->shared().kind()));
606       ASSIGN_RETURN_ON_EXCEPTION(
607           isolate, prototype_parent,
608           Runtime::GetObjectProperty(isolate, super_class,
609                                      isolate->factory()->prototype_string()),
610           Object);
611       if (!prototype_parent->IsNull(isolate) &&
612           !prototype_parent->IsJSReceiver()) {
613         THROW_NEW_ERROR(
614             isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
615                                   prototype_parent),
616             Object);
617       }
618       // Create new handle to avoid |constructor_parent| corruption because of
619       // |super_class| handle value overwriting via storing to
620       // args[ClassBoilerplate::kPrototypeArgumentIndex] below.
621       constructor_parent = handle(HeapObject::cast(*super_class), isolate);
622     } else {
623       THROW_NEW_ERROR(isolate,
624                       NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
625                                    super_class),
626                       Object);
627     }
628   }
629 
630   Handle<JSObject> prototype = CreateClassPrototype(isolate);
631   DCHECK_EQ(*constructor, args[ClassBoilerplate::kConstructorArgumentIndex]);
632   // Temporarily change ClassBoilerplate::kPrototypeArgumentIndex for the
633   // subsequent calls, but use a scope to make sure to change it back before
634   // returning, to not corrupt the caller's argument frame (in particular, for
635   // the interpreter, to not clobber the register frame).
636   RuntimeArguments::ChangeValueScope set_prototype_value_scope(
637       isolate, &args, ClassBoilerplate::kPrototypeArgumentIndex, *prototype);
638 
639   if (!InitClassConstructor(isolate, class_boilerplate, constructor_parent,
640                             constructor, args) ||
641       !InitClassPrototype(isolate, class_boilerplate, prototype,
642                           Handle<HeapObject>::cast(prototype_parent),
643                           constructor, args)) {
644     DCHECK(isolate->has_pending_exception());
645     return MaybeHandle<Object>();
646   }
647   if (FLAG_log_maps) {
648     Handle<Map> empty_map;
649     LOG(isolate,
650         MapEvent("InitialMap", empty_map, handle(constructor->map(), isolate),
651                  "init class constructor",
652                  SharedFunctionInfo::DebugName(
653                      handle(constructor->shared(), isolate))));
654     LOG(isolate,
655         MapEvent("InitialMap", empty_map, handle(prototype->map(), isolate),
656                  "init class prototype"));
657   }
658 
659   return prototype;
660 }
661 
662 }  // namespace
663 
RUNTIME_FUNCTION(Runtime_DefineClass)664 RUNTIME_FUNCTION(Runtime_DefineClass) {
665   HandleScope scope(isolate);
666   DCHECK_LE(ClassBoilerplate::kFirstDynamicArgumentIndex, args.length());
667   Handle<ClassBoilerplate> class_boilerplate = args.at<ClassBoilerplate>(0);
668   Handle<JSFunction> constructor = args.at<JSFunction>(1);
669   Handle<Object> super_class = args.at(2);
670   DCHECK_EQ(class_boilerplate->arguments_count(), args.length());
671 
672   RETURN_RESULT_OR_FAILURE(
673       isolate,
674       DefineClass(isolate, class_boilerplate, super_class, constructor, args));
675 }
676 
677 namespace {
678 
679 enum class SuperMode { kLoad, kStore };
680 
GetSuperHolder(Isolate * isolate,Handle<JSObject> home_object,SuperMode mode,PropertyKey * key)681 MaybeHandle<JSReceiver> GetSuperHolder(Isolate* isolate,
682                                        Handle<JSObject> home_object,
683                                        SuperMode mode, PropertyKey* key) {
684   if (home_object->IsAccessCheckNeeded() &&
685       !isolate->MayAccess(handle(isolate->context(), isolate), home_object)) {
686     isolate->ReportFailedAccessCheck(home_object);
687     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, JSReceiver);
688   }
689 
690   PrototypeIterator iter(isolate, home_object);
691   Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
692   if (!proto->IsJSReceiver()) {
693     MessageTemplate message =
694         mode == SuperMode::kLoad
695             ? MessageTemplate::kNonObjectPropertyLoadWithProperty
696             : MessageTemplate::kNonObjectPropertyStoreWithProperty;
697     Handle<Name> name = key->GetName(isolate);
698     THROW_NEW_ERROR(isolate, NewTypeError(message, proto, name), JSReceiver);
699   }
700   return Handle<JSReceiver>::cast(proto);
701 }
702 
LoadFromSuper(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> home_object,PropertyKey * key)703 MaybeHandle<Object> LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
704                                   Handle<JSObject> home_object,
705                                   PropertyKey* key) {
706   Handle<JSReceiver> holder;
707   ASSIGN_RETURN_ON_EXCEPTION(
708       isolate, holder,
709       GetSuperHolder(isolate, home_object, SuperMode::kLoad, key), Object);
710   LookupIterator it(isolate, receiver, *key, holder);
711   Handle<Object> result;
712   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
713   return result;
714 }
715 
716 }  // anonymous namespace
717 
RUNTIME_FUNCTION(Runtime_LoadFromSuper)718 RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
719   HandleScope scope(isolate);
720   DCHECK_EQ(3, args.length());
721   Handle<Object> receiver = args.at(0);
722   Handle<JSObject> home_object = args.at<JSObject>(1);
723   Handle<Name> name = args.at<Name>(2);
724 
725   PropertyKey key(isolate, name);
726 
727   RETURN_RESULT_OR_FAILURE(isolate,
728                            LoadFromSuper(isolate, receiver, home_object, &key));
729 }
730 
731 
RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper)732 RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
733   HandleScope scope(isolate);
734   DCHECK_EQ(3, args.length());
735   Handle<Object> receiver = args.at(0);
736   Handle<JSObject> home_object = args.at<JSObject>(1);
737   // TODO(ishell): To improve performance, consider performing the to-string
738   // conversion of {key} before calling into the runtime.
739   Handle<Object> key = args.at(2);
740 
741   bool success;
742   PropertyKey lookup_key(isolate, key, &success);
743   if (!success) return ReadOnlyRoots(isolate).exception();
744 
745   RETURN_RESULT_OR_FAILURE(
746       isolate, LoadFromSuper(isolate, receiver, home_object, &lookup_key));
747 }
748 
749 namespace {
750 
StoreToSuper(Isolate * isolate,Handle<JSObject> home_object,Handle<Object> receiver,PropertyKey * key,Handle<Object> value,StoreOrigin store_origin)751 MaybeHandle<Object> StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
752                                  Handle<Object> receiver, PropertyKey* key,
753                                  Handle<Object> value,
754                                  StoreOrigin store_origin) {
755   Handle<JSReceiver> holder;
756   ASSIGN_RETURN_ON_EXCEPTION(
757       isolate, holder,
758       GetSuperHolder(isolate, home_object, SuperMode::kStore, key), Object);
759   LookupIterator it(isolate, receiver, *key, holder);
760   MAYBE_RETURN(Object::SetSuperProperty(&it, value, store_origin),
761                MaybeHandle<Object>());
762   return value;
763 }
764 
765 }  // anonymous namespace
766 
RUNTIME_FUNCTION(Runtime_StoreToSuper)767 RUNTIME_FUNCTION(Runtime_StoreToSuper) {
768   HandleScope scope(isolate);
769   DCHECK_EQ(4, args.length());
770   Handle<Object> receiver = args.at(0);
771   Handle<JSObject> home_object = args.at<JSObject>(1);
772   Handle<Name> name = args.at<Name>(2);
773   Handle<Object> value = args.at(3);
774 
775   PropertyKey key(isolate, name);
776 
777   RETURN_RESULT_OR_FAILURE(
778       isolate, StoreToSuper(isolate, home_object, receiver, &key, value,
779                             StoreOrigin::kNamed));
780 }
781 
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper)782 RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper) {
783   HandleScope scope(isolate);
784   DCHECK_EQ(4, args.length());
785   Handle<Object> receiver = args.at(0);
786   Handle<JSObject> home_object = args.at<JSObject>(1);
787   // TODO(ishell): To improve performance, consider performing the to-string
788   // conversion of {key} before calling into the runtime.
789   Handle<Object> key = args.at(2);
790   Handle<Object> value = args.at(3);
791 
792   bool success;
793   PropertyKey lookup_key(isolate, key, &success);
794   if (!success) return ReadOnlyRoots(isolate).exception();
795 
796   RETURN_RESULT_OR_FAILURE(
797       isolate, StoreToSuper(isolate, home_object, receiver, &lookup_key, value,
798                             StoreOrigin::kMaybeKeyed));
799 }
800 
801 }  // namespace internal
802 }  // namespace v8
803