runtime-classes.cc 30.5 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#include "src/runtime/runtime-utils.h"

7 8 9
#include <stdlib.h>
#include <limits>

10
#include "src/builtins/accessors.h"
11
#include "src/common/message-template.h"
12
#include "src/debug/debug.h"
13 14
#include "src/execution/arguments-inl.h"
#include "src/execution/isolate-inl.h"
15 16
#include "src/logging/counters.h"
#include "src/logging/log.h"
17
#include "src/objects/elements.h"
18
#include "src/objects/hash-table-inl.h"
19
#include "src/objects/literal-objects-inl.h"
20
#include "src/objects/lookup-inl.h"
21
#include "src/objects/smi.h"
22
#include "src/objects/struct-inl.h"
23 24 25 26 27 28
#include "src/runtime/runtime.h"

namespace v8 {
namespace internal {


29 30
RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
  HandleScope scope(isolate);
31
  DCHECK_EQ(0, args.length());
32 33
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewReferenceError(MessageTemplate::kUnsupportedSuper));
34 35 36
}


37 38
RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
  HandleScope scope(isolate);
39
  DCHECK_EQ(1, args.length());
40
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
41
  Handle<String> name(constructor->shared().Name(), isolate);
42 43 44 45 46
  if (name->length() == 0) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate,
        NewTypeError(MessageTemplate::kAnonymousConstructorNonCallable));
  }
47
  THROW_NEW_ERROR_RETURN_FAILURE(
48
      isolate, NewTypeError(MessageTemplate::kConstructorNonCallable, name));
49 50 51
}


52 53
RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) {
  HandleScope scope(isolate);
54
  DCHECK_EQ(0, args.length());
55 56
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewTypeError(MessageTemplate::kStaticPrototype));
57 58
}

59 60 61 62 63 64 65
RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) {
  HandleScope scope(isolate);
  DCHECK_EQ(0, args.length());
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled));
}

66 67 68 69 70 71 72
RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled) {
  HandleScope scope(isolate);
  DCHECK_EQ(0, args.length());
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewReferenceError(MessageTemplate::kSuperNotCalled));
}

73 74
namespace {

75 76
Object ThrowNotSuperConstructor(Isolate* isolate, Handle<Object> constructor,
                                Handle<JSFunction> function) {
77
  Handle<String> super_name;
78
  if (constructor->IsJSFunction()) {
79 80
    super_name =
        handle(Handle<JSFunction>::cast(constructor)->shared().Name(), isolate);
81 82 83 84 85 86 87
  } else if (constructor->IsOddball()) {
    DCHECK(constructor->IsNull(isolate));
    super_name = isolate->factory()->null_string();
  } else {
    super_name = Object::NoSideEffectsToString(isolate, constructor);
  }
  // null constructor
88
  if (super_name->length() == 0) {
89 90
    super_name = isolate->factory()->null_string();
  }
91
  Handle<String> function_name(function->shared().Name(), isolate);
92
  // anonymous class
93
  if (function_name->length() == 0) {
94 95 96 97 98 99 100 101 102 103 104 105 106 107
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate,
        NewTypeError(MessageTemplate::kNotSuperConstructorAnonymousClass,
                     super_name));
  }
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewTypeError(MessageTemplate::kNotSuperConstructor, super_name,
                            function_name));
}

}  // namespace

RUNTIME_FUNCTION(Runtime_ThrowNotSuperConstructor) {
  HandleScope scope(isolate);
108
  DCHECK_EQ(2, args.length());
109 110 111 112 113
  CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
  return ThrowNotSuperConstructor(isolate, constructor, function);
}

114
RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
115
  DCHECK_EQ(0, args.length());
116
  return ReadOnlyRoots(isolate).home_object_symbol();
117 118
}

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
namespace {

template <typename Dictionary>
Handle<Name> KeyToName(Isolate* isolate, Handle<Object> key);

template <>
Handle<Name> KeyToName<NameDictionary>(Isolate* isolate, Handle<Object> key) {
  DCHECK(key->IsName());
  return Handle<Name>::cast(key);
}

template <>
Handle<Name> KeyToName<NumberDictionary>(Isolate* isolate, Handle<Object> key) {
  DCHECK(key->IsNumber());
  return isolate->factory()->NumberToString(key);
}

136 137
inline void SetHomeObject(Isolate* isolate, JSFunction method,
                          JSObject home_object) {
138
  if (method.shared().needs_home_object()) {
139 140
    const InternalIndex kPropertyIndex(
        JSFunction::kMaybeHomeObjectDescriptorIndex);
141
    CHECK_EQ(method.map().instance_descriptors().GetKey(kPropertyIndex),
142
             ReadOnlyRoots(isolate).home_object_symbol());
143 144

    FieldIndex field_index =
145 146
        FieldIndex::ForDescriptor(method.map(), kPropertyIndex);
    method.RawFastPropertyAtPut(field_index, home_object);
147 148 149 150 151 152 153 154 155 156 157 158 159
  }
}

// Gets |index|'th argument which may be a class constructor object, a class
// prototype object or a class method. In the latter case the following
// post-processing may be required:
// 1) set [[HomeObject]] slot to given |home_object| value if the method's
//    shared function info indicates that the method requires that;
// 2) set method's name to a concatenation of |name_prefix| and |key| if the
//    method's shared function info indicates that method does not have a
//    shared name.
template <typename Dictionary>
MaybeHandle<Object> GetMethodAndSetHomeObjectAndName(
160 161
    Isolate* isolate,
    RuntimeArguments& args,  // NOLINT(runtime/references)
162 163
    Smi index, Handle<JSObject> home_object, Handle<String> name_prefix,
    Handle<Object> key) {
164
  int int_index = index.value();
165 166 167 168 169 170 171 172 173 174

  // Class constructor and prototype values do not require post processing.
  if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
    return args.at<Object>(int_index);
  }

  Handle<JSFunction> method = args.at<JSFunction>(int_index);

  SetHomeObject(isolate, *method, *home_object);

175
  if (!method->shared().HasSharedName()) {
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    // TODO(ishell): method does not have a shared name at this point only if
    // the key is a computed property name. However, the bytecode generator
    // explicitly generates ToName bytecodes to ensure that the computed
    // property name is properly converted to Name. So, we can actually be smart
    // here and avoid converting Smi keys back to Name.
    Handle<Name> name = KeyToName<Dictionary>(isolate, key);
    if (!JSFunction::SetName(method, name, name_prefix)) {
      return MaybeHandle<Object>();
    }
  }
  return method;
}

// Gets |index|'th argument which may be a class constructor object, a class
// prototype object or a class method. In the latter case the following
// post-processing may be required:
// 1) set [[HomeObject]] slot to given |home_object| value if the method's
//    shared function info indicates that the method requires that;
// This is a simplified version of GetMethodWithSharedNameAndSetHomeObject()
// function above that is used when it's guaranteed that the method has
// shared name.
197 198
Object GetMethodWithSharedNameAndSetHomeObject(
    Isolate* isolate,
199
    RuntimeArguments& args,  // NOLINT(runtime/references)
200
    Object index, JSObject home_object) {
201 202 203 204 205 206 207 208 209 210 211 212
  DisallowHeapAllocation no_gc;
  int int_index = Smi::ToInt(index);

  // Class constructor and prototype values do not require post processing.
  if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
    return args[int_index];
  }

  Handle<JSFunction> method = args.at<JSFunction>(int_index);

  SetHomeObject(isolate, *method, home_object);

213
  DCHECK(method->shared().HasSharedName());
214 215 216 217 218 219 220 221 222 223 224
  return *method;
}

template <typename Dictionary>
Handle<Dictionary> ShallowCopyDictionaryTemplate(
    Isolate* isolate, Handle<Dictionary> dictionary_template) {
  Handle<Map> dictionary_map(dictionary_template->map(), isolate);
  Handle<Dictionary> dictionary =
      Handle<Dictionary>::cast(isolate->factory()->CopyFixedArrayWithMap(
          dictionary_template, dictionary_map));
  // Clone all AccessorPairs in the dictionary.
225
  for (InternalIndex i : dictionary->IterateEntries()) {
226
    Object value = dictionary->ValueAt(i);
227
    if (value.IsAccessorPair()) {
228
      Handle<AccessorPair> pair(AccessorPair::cast(value), isolate);
229
      pair = AccessorPair::Copy(isolate, pair);
230 231 232 233 234 235 236 237
      dictionary->ValueAtPut(i, *pair);
    }
  }
  return dictionary;
}

template <typename Dictionary>
bool SubstituteValues(Isolate* isolate, Handle<Dictionary> dictionary,
238
                      Handle<JSObject> receiver,
239
                      RuntimeArguments& args,  // NOLINT(runtime/references)
240 241 242 243
                      bool* install_name_accessor = nullptr) {
  Handle<Name> name_string = isolate->factory()->name_string();

  // Replace all indices with proper methods.
244
  ReadOnlyRoots roots(isolate);
245
  for (InternalIndex i : dictionary->IterateEntries()) {
246
    Object maybe_key = dictionary->KeyAt(i);
247
    if (!Dictionary::IsKey(roots, maybe_key)) continue;
248 249 250 251 252 253 254 255
    if (install_name_accessor && *install_name_accessor &&
        (maybe_key == *name_string)) {
      *install_name_accessor = false;
    }
    Handle<Object> key(maybe_key, isolate);
    Handle<Object> value(dictionary->ValueAt(i), isolate);
    if (value->IsAccessorPair()) {
      Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
256
      Object tmp = pair->getter();
257
      if (tmp.IsSmi()) {
258 259 260 261 262 263 264 265 266 267
        Handle<Object> result;
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
            isolate, result,
            GetMethodAndSetHomeObjectAndName<Dictionary>(
                isolate, args, Smi::cast(tmp), receiver,
                isolate->factory()->get_string(), key),
            false);
        pair->set_getter(*result);
      }
      tmp = pair->setter();
268
      if (tmp.IsSmi()) {
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
        Handle<Object> result;
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
            isolate, result,
            GetMethodAndSetHomeObjectAndName<Dictionary>(
                isolate, args, Smi::cast(tmp), receiver,
                isolate->factory()->set_string(), key),
            false);
        pair->set_setter(*result);
      }
    } else if (value->IsSmi()) {
      Handle<Object> result;
      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
          isolate, result,
          GetMethodAndSetHomeObjectAndName<Dictionary>(
              isolate, args, Smi::cast(*value), receiver,
              isolate->factory()->empty_string(), key),
          false);
      dictionary->ValueAtPut(i, *result);
    }
  }
  return true;
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
void UpdateProtectors(Isolate* isolate, Handle<JSObject> receiver,
                      Handle<NameDictionary> properties_dictionary) {
  ReadOnlyRoots roots(isolate);
  for (InternalIndex i : properties_dictionary->IterateEntries()) {
    Object maybe_key = properties_dictionary->KeyAt(i);
    if (!NameDictionary::IsKey(roots, maybe_key)) continue;
    Handle<Name> name(Name::cast(maybe_key), isolate);
    LookupIterator::UpdateProtector(isolate, receiver, name);
  }
}

void UpdateProtectors(Isolate* isolate, Handle<JSObject> receiver,
                      Handle<DescriptorArray> properties_template) {
  int nof_descriptors = properties_template->number_of_descriptors();
  for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
    Handle<Name> name(properties_template->GetKey(i), isolate);
    LookupIterator::UpdateProtector(isolate, receiver, name);
  }
}

312 313 314 315
bool AddDescriptorsByTemplate(
    Isolate* isolate, Handle<Map> map,
    Handle<DescriptorArray> descriptors_template,
    Handle<NumberDictionary> elements_dictionary_template,
316 317
    Handle<JSObject> receiver,
    RuntimeArguments& args) {  // NOLINT(runtime/references)
318 319 320 321 322 323 324
  int nof_descriptors = descriptors_template->number_of_descriptors();

  Handle<DescriptorArray> descriptors =
      DescriptorArray::Allocate(isolate, nof_descriptors, 0);

  Handle<NumberDictionary> elements_dictionary =
      *elements_dictionary_template ==
325
              ReadOnlyRoots(isolate).empty_slow_element_dictionary()
326 327 328 329
          ? elements_dictionary_template
          : ShallowCopyDictionaryTemplate(isolate,
                                          elements_dictionary_template);

330 331 332
  // Count the number of properties that must be in the instance and
  // create the property array to hold the constants.
  int count = 0;
333
  for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
334 335 336
    PropertyDetails details = descriptors_template->GetDetails(i);
    if (details.location() == kDescriptor && details.kind() == kData) {
      count++;
337 338
    }
  }
339 340
  Handle<PropertyArray> property_array =
      isolate->factory()->NewPropertyArray(count);
341

342 343
  // Read values from |descriptors_template| and store possibly post-processed
  // values into "instantiated" |descriptors| array.
344
  int field_index = 0;
345
  for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
346
    Object value = descriptors_template->GetStrongValue(i);
347
    if (value.IsAccessorPair()) {
348 349
      Handle<AccessorPair> pair = AccessorPair::Copy(
          isolate, handle(AccessorPair::cast(value), isolate));
350 351 352
      value = *pair;
    }
    DisallowHeapAllocation no_gc;
353
    Name name = descriptors_template->GetKey(i);
354
    DCHECK(name.IsUniqueName());
355 356 357
    PropertyDetails details = descriptors_template->GetDetails(i);
    if (details.location() == kDescriptor) {
      if (details.kind() == kData) {
358
        if (value.IsSmi()) {
359 360 361
          value = GetMethodWithSharedNameAndSetHomeObject(isolate, args, value,
                                                          *receiver);
        }
362 363
        details = details.CopyWithRepresentation(
            value.OptimalRepresentation(isolate));
364 365
      } else {
        DCHECK_EQ(kAccessor, details.kind());
366
        if (value.IsAccessorPair()) {
367
          AccessorPair pair = AccessorPair::cast(value);
368 369 370
          Object tmp = pair.getter();
          if (tmp.IsSmi()) {
            pair.set_getter(GetMethodWithSharedNameAndSetHomeObject(
371 372
                isolate, args, tmp, *receiver));
          }
373 374 375
          tmp = pair.setter();
          if (tmp.IsSmi()) {
            pair.set_setter(GetMethodWithSharedNameAndSetHomeObject(
376 377 378 379 380
                isolate, args, tmp, *receiver));
          }
        }
      }
    } else {
381
      UNREACHABLE();
382
    }
383
    DCHECK(value.FitsRepresentation(details.representation()));
384
    if (details.location() == kDescriptor && details.kind() == kData) {
385 386 387 388 389 390 391 392 393 394 395 396
      details = PropertyDetails(details.kind(), details.attributes(), kField,
                                PropertyConstness::kConst,
                                details.representation(), field_index)
                    .set_pointer(details.pointer());

      property_array->set(field_index, value);
      field_index++;
      descriptors->Set(i, name, MaybeObject::FromObject(FieldType::Any()),
                       details);
    } else {
      descriptors->Set(i, name, MaybeObject::FromObject(value), details);
    }
397 398
  }

399 400
  UpdateProtectors(isolate, receiver, descriptors_template);

401
  map->InitializeDescriptors(isolate, *descriptors,
402 403 404 405 406 407 408 409 410 411 412 413 414 415
                             LayoutDescriptor::FastPointerLayout());
  if (elements_dictionary->NumberOfElements() > 0) {
    if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
                                            receiver, args)) {
      return false;
    }
    map->set_elements_kind(DICTIONARY_ELEMENTS);
  }

  // Atomically commit the changes.
  receiver->synchronized_set_map(*map);
  if (elements_dictionary->NumberOfElements() > 0) {
    receiver->set_elements(*elements_dictionary);
  }
416 417 418
  if (property_array->length() > 0) {
    receiver->SetProperties(*property_array);
  }
419 420 421 422 423 424 425 426
  return true;
}

bool AddDescriptorsByTemplate(
    Isolate* isolate, Handle<Map> map,
    Handle<NameDictionary> properties_dictionary_template,
    Handle<NumberDictionary> elements_dictionary_template,
    Handle<FixedArray> computed_properties, Handle<JSObject> receiver,
427
    bool install_name_accessor,
428
    RuntimeArguments& args) {  // NOLINT(runtime/references)
429 430 431 432 433 434 435 436
  int computed_properties_length = computed_properties->length();

  // Shallow-copy properties template.
  Handle<NameDictionary> properties_dictionary =
      ShallowCopyDictionaryTemplate(isolate, properties_dictionary_template);
  Handle<NumberDictionary> elements_dictionary =
      ShallowCopyDictionaryTemplate(isolate, elements_dictionary_template);

437 438
  using ValueKind = ClassBoilerplate::ValueKind;
  using ComputedEntryFlags = ClassBoilerplate::ComputedEntryFlags;
439 440 441 442 443 444 445 446 447

  // Merge computed properties with properties and elements dictionary
  // templates.
  int i = 0;
  while (i < computed_properties_length) {
    int flags = Smi::ToInt(computed_properties->get(i++));

    ValueKind value_kind = ComputedEntryFlags::ValueKindBits::decode(flags);
    int key_index = ComputedEntryFlags::KeyIndexBits::decode(flags);
448
    Smi value = Smi::FromInt(key_index + 1);  // Value follows name.
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475

    Handle<Object> key = args.at<Object>(key_index);
    DCHECK(key->IsName());
    uint32_t element;
    Handle<Name> name = Handle<Name>::cast(key);
    if (name->AsArrayIndex(&element)) {
      ClassBoilerplate::AddToElementsTemplate(
          isolate, elements_dictionary, element, key_index, value_kind, value);

    } else {
      name = isolate->factory()->InternalizeName(name);
      ClassBoilerplate::AddToPropertiesTemplate(
          isolate, properties_dictionary, name, key_index, value_kind, value);
    }
  }

  // Replace all indices with proper methods.
  if (!SubstituteValues<NameDictionary>(isolate, properties_dictionary,
                                        receiver, args,
                                        &install_name_accessor)) {
    return false;
  }
  if (install_name_accessor) {
    PropertyAttributes attribs =
        static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
    PropertyDetails details(kAccessor, attribs, PropertyCellType::kNoCell);
    Handle<NameDictionary> dict = NameDictionary::Add(
476
        isolate, properties_dictionary, isolate->factory()->name_string(),
477 478 479 480
        isolate->factory()->function_name_accessor(), details);
    CHECK_EQ(*dict, *properties_dictionary);
  }

481 482
  UpdateProtectors(isolate, receiver, properties_dictionary);

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
  if (elements_dictionary->NumberOfElements() > 0) {
    if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
                                            receiver, args)) {
      return false;
    }
    map->set_elements_kind(DICTIONARY_ELEMENTS);
  }

  // Atomically commit the changes.
  receiver->synchronized_set_map(*map);
  receiver->set_raw_properties_or_hash(*properties_dictionary);
  if (elements_dictionary->NumberOfElements() > 0) {
    receiver->set_elements(*elements_dictionary);
  }
  return true;
}

Handle<JSObject> CreateClassPrototype(Isolate* isolate) {
501 502 503 504 505 506 507 508
  // For constant tracking we want to avoid the hassle of handling
  // in-object properties, so create a map with no in-object
  // properties.

  // TODO(ishell) Support caching of zero in-object properties map
  // by ObjectLiteralMapFromCache().
  Handle<Map> map = Map::Create(isolate, 0);
  return isolate->factory()->NewJSObjectFromMap(map);
509 510 511 512 513
}

bool InitClassPrototype(Isolate* isolate,
                        Handle<ClassBoilerplate> class_boilerplate,
                        Handle<JSObject> prototype,
514
                        Handle<HeapObject> prototype_parent,
515
                        Handle<JSFunction> constructor,
516
                        RuntimeArguments& args) {  // NOLINT(runtime/references)
517
  Handle<Map> map(prototype->map(), isolate);
518
  map = Map::CopyDropDescriptors(isolate, map);
519
  map->set_is_prototype_map(true);
520
  Map::SetPrototype(isolate, map, prototype_parent);
521 522 523 524 525 526 527 528 529 530
  constructor->set_prototype_or_initial_map(*prototype);
  map->SetConstructor(*constructor);
  Handle<FixedArray> computed_properties(
      class_boilerplate->instance_computed_properties(), isolate);
  Handle<NumberDictionary> elements_dictionary_template(
      NumberDictionary::cast(class_boilerplate->instance_elements_template()),
      isolate);

  Handle<Object> properties_template(
      class_boilerplate->instance_properties_template(), isolate);
531
  if (properties_template->IsNameDictionary()) {
532 533 534
    Handle<NameDictionary> properties_dictionary_template =
        Handle<NameDictionary>::cast(properties_template);

535 536
    map->set_is_dictionary_map(true);
    map->set_is_migration_target(false);
537
    map->set_may_have_interesting_symbols(true);
538
    map->set_construction_counter(Map::kNoSlackTracking);
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559

    // We care about name property only for class constructor.
    const bool install_name_accessor = false;

    return AddDescriptorsByTemplate(
        isolate, map, properties_dictionary_template,
        elements_dictionary_template, computed_properties, prototype,
        install_name_accessor, args);
  } else {
    Handle<DescriptorArray> descriptors_template =
        Handle<DescriptorArray>::cast(properties_template);

    // The size of the prototype object is known at this point.
    // So we can create it now and then add the rest instance methods to the
    // map.
    return AddDescriptorsByTemplate(isolate, map, descriptors_template,
                                    elements_dictionary_template, prototype,
                                    args);
  }
}

560 561 562 563
bool InitClassConstructor(
    Isolate* isolate, Handle<ClassBoilerplate> class_boilerplate,
    Handle<HeapObject> constructor_parent, Handle<JSFunction> constructor,
    RuntimeArguments& args) {  // NOLINT(runtime/references)
564
  Handle<Map> map(constructor->map(), isolate);
565
  map = Map::CopyDropDescriptors(isolate, map);
566 567 568
  DCHECK(map->is_prototype_map());

  if (!constructor_parent.is_null()) {
569 570
    // Set map's prototype without enabling prototype setup mode for superclass
    // because it does not make sense.
571
    Map::SetPrototype(isolate, map, constructor_parent, false);
572 573 574 575 576 577 578 579 580 581 582
  }

  Handle<NumberDictionary> elements_dictionary_template(
      NumberDictionary::cast(class_boilerplate->static_elements_template()),
      isolate);
  Handle<FixedArray> computed_properties(
      class_boilerplate->static_computed_properties(), isolate);

  Handle<Object> properties_template(
      class_boilerplate->static_properties_template(), isolate);

583
  if (properties_template->IsNameDictionary()) {
584 585 586
    Handle<NameDictionary> properties_dictionary_template =
        Handle<NameDictionary>::cast(properties_template);

587
    map->set_is_dictionary_map(true);
588 589
    map->InitializeDescriptors(isolate,
                               ReadOnlyRoots(isolate).empty_descriptor_array(),
590
                               LayoutDescriptor::FastPointerLayout());
591
    map->set_is_migration_target(false);
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
    map->set_may_have_interesting_symbols(true);
    map->set_construction_counter(Map::kNoSlackTracking);

    bool install_name_accessor =
        class_boilerplate->install_class_name_accessor() != 0;

    return AddDescriptorsByTemplate(
        isolate, map, properties_dictionary_template,
        elements_dictionary_template, computed_properties, constructor,
        install_name_accessor, args);
  } else {
    Handle<DescriptorArray> descriptors_template =
        Handle<DescriptorArray>::cast(properties_template);

    return AddDescriptorsByTemplate(isolate, map, descriptors_template,
                                    elements_dictionary_template, constructor,
                                    args);
  }
}

612 613 614
MaybeHandle<Object> DefineClass(
    Isolate* isolate, Handle<ClassBoilerplate> class_boilerplate,
    Handle<Object> super_class, Handle<JSFunction> constructor,
615
    RuntimeArguments& args) {  // NOLINT(runtime/references)
616
  Handle<Object> prototype_parent;
617
  Handle<HeapObject> constructor_parent;
618

619
  if (super_class->IsTheHole(isolate)) {
620 621
    prototype_parent = isolate->initial_object_prototype();
  } else {
622
    if (super_class->IsNull(isolate)) {
623
      prototype_parent = isolate->factory()->null_value();
624
    } else if (super_class->IsConstructor()) {
625
      DCHECK(!super_class->IsJSFunction() ||
626
             !IsResumableFunction(
627
                 Handle<JSFunction>::cast(super_class)->shared().kind()));
628
      ASSIGN_RETURN_ON_EXCEPTION(
629 630
          isolate, prototype_parent,
          Runtime::GetObjectProperty(isolate, super_class,
631
                                     isolate->factory()->prototype_string()),
632
          Object);
633 634
      if (!prototype_parent->IsNull(isolate) &&
          !prototype_parent->IsJSReceiver()) {
635
        THROW_NEW_ERROR(
636
            isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
637 638
                                  prototype_parent),
            Object);
639
      }
640 641 642
      // Create new handle to avoid |constructor_parent| corruption because of
      // |super_class| handle value overwriting via storing to
      // args[ClassBoilerplate::kPrototypeArgumentIndex] below.
643
      constructor_parent = handle(HeapObject::cast(*super_class), isolate);
644
    } else {
645 646 647 648
      THROW_NEW_ERROR(isolate,
                      NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
                                   super_class),
                      Object);
649 650 651
    }
  }

652 653
  Handle<JSObject> prototype = CreateClassPrototype(isolate);
  DCHECK_EQ(*constructor, args[ClassBoilerplate::kConstructorArgumentIndex]);
654
  args.set_at(ClassBoilerplate::kPrototypeArgumentIndex, *prototype);
655

656 657 658
  if (!InitClassConstructor(isolate, class_boilerplate, constructor_parent,
                            constructor, args) ||
      !InitClassPrototype(isolate, class_boilerplate, prototype,
659 660
                          Handle<HeapObject>::cast(prototype_parent),
                          constructor, args)) {
661 662
    DCHECK(isolate->has_pending_exception());
    return MaybeHandle<Object>();
663
  }
Camillo Bruni's avatar
Camillo Bruni committed
664
  if (FLAG_trace_maps) {
665
    Handle<Map> empty_map;
Camillo Bruni's avatar
Camillo Bruni committed
666
    LOG(isolate,
667 668 669 670 671 672
        MapEvent("InitialMap", empty_map, handle(constructor->map(), isolate),
                 "init class constructor",
                 handle(constructor->shared().DebugName(), isolate)));
    LOG(isolate,
        MapEvent("InitialMap", empty_map, handle(prototype->map(), isolate),
                 "init class prototype"));
Camillo Bruni's avatar
Camillo Bruni committed
673 674
  }

675
  return prototype;
676 677
}

678
}  // namespace
679 680 681

RUNTIME_FUNCTION(Runtime_DefineClass) {
  HandleScope scope(isolate);
682 683
  DCHECK_LE(ClassBoilerplate::kFirstDynamicArgumentIndex, args.length());
  CONVERT_ARG_HANDLE_CHECKED(ClassBoilerplate, class_boilerplate, 0);
684
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 1);
685 686
  CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 2);
  DCHECK_EQ(class_boilerplate->arguments_count(), args.length());
687

688
  RETURN_RESULT_OR_FAILURE(
689 690
      isolate,
      DefineClass(isolate, class_boilerplate, super_class, constructor, args));
691 692
}

693
namespace {
694

695 696
enum class SuperMode { kLoad, kStore };

697 698 699 700
MaybeHandle<JSReceiver> GetSuperHolder(Isolate* isolate,
                                       Handle<JSObject> home_object,
                                       SuperMode mode,
                                       LookupIterator::Key* key) {
701
  if (home_object->IsAccessCheckNeeded() &&
702
      !isolate->MayAccess(handle(isolate->context(), isolate), home_object)) {
703
    isolate->ReportFailedAccessCheck(home_object);
704
    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, JSReceiver);
705 706 707 708
  }

  PrototypeIterator iter(isolate, home_object);
  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
709
  if (!proto->IsJSReceiver()) {
710 711 712
    MessageTemplate message = mode == SuperMode::kLoad
                                  ? MessageTemplate::kNonObjectPropertyLoad
                                  : MessageTemplate::kNonObjectPropertyStore;
713
    Handle<Name> name = key->GetName(isolate);
714
    THROW_NEW_ERROR(isolate, NewTypeError(message, name, proto), JSReceiver);
715
  }
716 717
  return Handle<JSReceiver>::cast(proto);
}
718

719 720
MaybeHandle<Object> LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
                                  Handle<JSObject> home_object,
721
                                  LookupIterator::Key* key) {
722 723 724
  Handle<JSReceiver> holder;
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, holder,
725 726
      GetSuperHolder(isolate, home_object, SuperMode::kLoad, key), Object);
  LookupIterator it(isolate, receiver, *key, holder);
727
  Handle<Object> result;
728
  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
729
  return result;
730 731
}

732
}  // anonymous namespace
733

734 735
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
  HandleScope scope(isolate);
736
  DCHECK_EQ(3, args.length());
737 738 739 740
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);

741 742
  LookupIterator::Key key(isolate, name);

743
  RETURN_RESULT_OR_FAILURE(isolate,
744
                           LoadFromSuper(isolate, receiver, home_object, &key));
745 746 747 748 749
}


RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
  HandleScope scope(isolate);
750
  DCHECK_EQ(3, args.length());
751 752
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
753 754
  // TODO(ishell): To improve performance, consider performing the to-string
  // conversion of {key} before calling into the runtime.
755 756
  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);

757 758 759
  bool success;
  LookupIterator::Key lookup_key(isolate, key, &success);
  if (!success) return ReadOnlyRoots(isolate).exception();
760

761 762
  RETURN_RESULT_OR_FAILURE(
      isolate, LoadFromSuper(isolate, receiver, home_object, &lookup_key));
763 764
}

765
namespace {
766

767
MaybeHandle<Object> StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
768 769 770
                                 Handle<Object> receiver,
                                 LookupIterator::Key* key, Handle<Object> value,
                                 StoreOrigin store_origin) {
771 772 773
  Handle<JSReceiver> holder;
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, holder,
774 775 776
      GetSuperHolder(isolate, home_object, SuperMode::kStore, key), Object);
  LookupIterator it(isolate, receiver, *key, holder);
  MAYBE_RETURN(Object::SetSuperProperty(&it, value, store_origin),
777 778
               MaybeHandle<Object>());
  return value;
779 780
}

781
}  // anonymous namespace
782

783
RUNTIME_FUNCTION(Runtime_StoreToSuper) {
784
  HandleScope scope(isolate);
785
  DCHECK_EQ(4, args.length());
786 787 788 789 790
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);

791
  LookupIterator::Key key(isolate, name);
792

793 794 795
  RETURN_RESULT_OR_FAILURE(
      isolate, StoreToSuper(isolate, home_object, receiver, &key, value,
                            StoreOrigin::kNamed));
796 797
}

798
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper) {
799
  HandleScope scope(isolate);
800
  DCHECK_EQ(4, args.length());
801 802
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
803 804
  // TODO(ishell): To improve performance, consider performing the to-string
  // conversion of {key} before calling into the runtime.
805 806 807
  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);

808 809 810 811
  bool success;
  LookupIterator::Key lookup_key(isolate, key, &success);
  if (!success) return ReadOnlyRoots(isolate).exception();

812
  RETURN_RESULT_OR_FAILURE(
813 814
      isolate, StoreToSuper(isolate, home_object, receiver, &lookup_key, value,
                            StoreOrigin::kMaybeKeyed));
815
}
816

817 818
}  // namespace internal
}  // namespace v8