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