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