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