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