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