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