Home | History | Annotate | Download | only in runtime
      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.h"
     12 #include "src/debug/debug.h"
     13 #include "src/elements.h"
     14 #include "src/frames-inl.h"
     15 #include "src/isolate-inl.h"
     16 #include "src/messages.h"
     17 #include "src/runtime/runtime.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 
     22 
     23 RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
     24   HandleScope scope(isolate);
     25   DCHECK_EQ(0, args.length());
     26   THROW_NEW_ERROR_RETURN_FAILURE(
     27       isolate, NewReferenceError(MessageTemplate::kUnsupportedSuper));
     28 }
     29 
     30 
     31 RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
     32   HandleScope scope(isolate);
     33   DCHECK_EQ(1, args.length());
     34   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
     35   Handle<Object> name(constructor->shared()->name(), isolate);
     36   THROW_NEW_ERROR_RETURN_FAILURE(
     37       isolate, NewTypeError(MessageTemplate::kConstructorNonCallable, name));
     38 }
     39 
     40 
     41 RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) {
     42   HandleScope scope(isolate);
     43   DCHECK_EQ(0, args.length());
     44   THROW_NEW_ERROR_RETURN_FAILURE(
     45       isolate, NewTypeError(MessageTemplate::kStaticPrototype));
     46 }
     47 
     48 RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) {
     49   HandleScope scope(isolate);
     50   DCHECK_EQ(0, args.length());
     51   THROW_NEW_ERROR_RETURN_FAILURE(
     52       isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled));
     53 }
     54 
     55 namespace {
     56 
     57 Object* ThrowNotSuperConstructor(Isolate* isolate, Handle<Object> constructor,
     58                                  Handle<JSFunction> function) {
     59   Handle<Object> super_name;
     60   if (constructor->IsJSFunction()) {
     61     super_name = handle(Handle<JSFunction>::cast(constructor)->shared()->name(),
     62                         isolate);
     63   } else if (constructor->IsOddball()) {
     64     DCHECK(constructor->IsNull(isolate));
     65     super_name = isolate->factory()->null_string();
     66   } else {
     67     super_name = Object::NoSideEffectsToString(isolate, constructor);
     68   }
     69   // null constructor
     70   if (Handle<String>::cast(super_name)->length() == 0) {
     71     super_name = isolate->factory()->null_string();
     72   }
     73   Handle<Object> function_name(function->shared()->name(), isolate);
     74   // anonymous class
     75   if (Handle<String>::cast(function_name)->length() == 0) {
     76     THROW_NEW_ERROR_RETURN_FAILURE(
     77         isolate,
     78         NewTypeError(MessageTemplate::kNotSuperConstructorAnonymousClass,
     79                      super_name));
     80   }
     81   THROW_NEW_ERROR_RETURN_FAILURE(
     82       isolate, NewTypeError(MessageTemplate::kNotSuperConstructor, super_name,
     83                             function_name));
     84 }
     85 
     86 }  // namespace
     87 
     88 RUNTIME_FUNCTION(Runtime_ThrowNotSuperConstructor) {
     89   HandleScope scope(isolate);
     90   DCHECK_EQ(2, args.length());
     91   CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
     92   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
     93   return ThrowNotSuperConstructor(isolate, constructor, function);
     94 }
     95 
     96 RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
     97   DCHECK_EQ(0, args.length());
     98   return isolate->heap()->home_object_symbol();
     99 }
    100 
    101 static MaybeHandle<Object> DefineClass(Isolate* isolate,
    102                                        Handle<Object> super_class,
    103                                        Handle<JSFunction> constructor,
    104                                        int start_position, int end_position) {
    105   Handle<Object> prototype_parent;
    106   Handle<Object> constructor_parent;
    107 
    108   if (super_class->IsTheHole(isolate)) {
    109     prototype_parent = isolate->initial_object_prototype();
    110   } else {
    111     if (super_class->IsNull(isolate)) {
    112       prototype_parent = isolate->factory()->null_value();
    113     } else if (super_class->IsConstructor()) {
    114       DCHECK(!super_class->IsJSFunction() ||
    115              !IsResumableFunction(
    116                  Handle<JSFunction>::cast(super_class)->shared()->kind()));
    117       ASSIGN_RETURN_ON_EXCEPTION(
    118           isolate, prototype_parent,
    119           Runtime::GetObjectProperty(isolate, super_class,
    120                                      isolate->factory()->prototype_string()),
    121           Object);
    122       if (!prototype_parent->IsNull(isolate) &&
    123           !prototype_parent->IsJSReceiver()) {
    124         THROW_NEW_ERROR(
    125             isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
    126                                   prototype_parent),
    127             Object);
    128       }
    129       constructor_parent = super_class;
    130     } else {
    131       THROW_NEW_ERROR(isolate,
    132                       NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
    133                                    super_class),
    134                       Object);
    135     }
    136   }
    137 
    138   Handle<Map> map =
    139       isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
    140   map->set_is_prototype_map(true);
    141   Map::SetPrototype(map, prototype_parent);
    142   map->SetConstructor(*constructor);
    143   Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);
    144 
    145   if (!super_class->IsTheHole(isolate)) {
    146     // Derived classes, just like builtins, don't create implicit receivers in
    147     // [[construct]]. Instead they just set up new.target and call into the
    148     // constructor. Hence we can reuse the builtins construct stub for derived
    149     // classes.
    150     Handle<Code> stub(isolate->builtins()->JSBuiltinsConstructStubForDerived());
    151     constructor->shared()->SetConstructStub(*stub);
    152   }
    153 
    154   JSFunction::SetPrototype(constructor, prototype);
    155   PropertyAttributes attribs =
    156       static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
    157   RETURN_ON_EXCEPTION(isolate,
    158                       JSObject::SetOwnPropertyIgnoreAttributes(
    159                           constructor, isolate->factory()->prototype_string(),
    160                           prototype, attribs),
    161                       Object);
    162 
    163   if (!constructor_parent.is_null()) {
    164     MAYBE_RETURN_NULL(JSObject::SetPrototype(constructor, constructor_parent,
    165                                              false, Object::THROW_ON_ERROR));
    166   }
    167 
    168   JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
    169                         constructor, DONT_ENUM);
    170 
    171   // Install private properties that are used to construct the FunctionToString.
    172   RETURN_ON_EXCEPTION(
    173       isolate,
    174       Object::SetProperty(
    175           constructor, isolate->factory()->class_start_position_symbol(),
    176           handle(Smi::FromInt(start_position), isolate), STRICT),
    177       Object);
    178   RETURN_ON_EXCEPTION(
    179       isolate, Object::SetProperty(
    180                    constructor, isolate->factory()->class_end_position_symbol(),
    181                    handle(Smi::FromInt(end_position), isolate), STRICT),
    182       Object);
    183 
    184   // Caller already has access to constructor, so return the prototype.
    185   return prototype;
    186 }
    187 
    188 
    189 RUNTIME_FUNCTION(Runtime_DefineClass) {
    190   HandleScope scope(isolate);
    191   DCHECK_EQ(4, args.length());
    192   CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 0);
    193   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 1);
    194   CONVERT_SMI_ARG_CHECKED(start_position, 2);
    195   CONVERT_SMI_ARG_CHECKED(end_position, 3);
    196 
    197   RETURN_RESULT_OR_FAILURE(
    198       isolate, DefineClass(isolate, super_class, constructor, start_position,
    199                            end_position));
    200 }
    201 
    202 namespace {
    203 void InstallClassNameAccessor(Isolate* isolate, Handle<JSObject> object) {
    204   PropertyAttributes attrs =
    205       static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
    206   // Cannot fail since this should only be called when creating an object
    207   // literal.
    208   CHECK(!JSObject::SetAccessor(
    209              object, Accessors::FunctionNameInfo(object->GetIsolate(), attrs))
    210              .is_null());
    211 }
    212 }  // anonymous namespace
    213 
    214 RUNTIME_FUNCTION(Runtime_InstallClassNameAccessor) {
    215   HandleScope scope(isolate);
    216   DCHECK_EQ(1, args.length());
    217   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
    218   InstallClassNameAccessor(isolate, object);
    219   return *object;
    220 }
    221 
    222 RUNTIME_FUNCTION(Runtime_InstallClassNameAccessorWithCheck) {
    223   HandleScope scope(isolate);
    224   DCHECK_EQ(1, args.length());
    225   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
    226 
    227   // If a property named "name" is already defined, exit.
    228   Handle<Name> key = isolate->factory()->name_string();
    229   if (JSObject::HasRealNamedProperty(object, key).FromMaybe(false)) {
    230     return *object;
    231   }
    232 
    233   // Define the "name" accessor.
    234   InstallClassNameAccessor(isolate, object);
    235   return *object;
    236 }
    237 
    238 namespace {
    239 
    240 enum class SuperMode { kLoad, kStore };
    241 
    242 MaybeHandle<JSReceiver> GetSuperHolder(
    243     Isolate* isolate, Handle<Object> receiver, Handle<JSObject> home_object,
    244     SuperMode mode, MaybeHandle<Name> maybe_name, uint32_t index) {
    245   if (home_object->IsAccessCheckNeeded() &&
    246       !isolate->MayAccess(handle(isolate->context()), home_object)) {
    247     isolate->ReportFailedAccessCheck(home_object);
    248     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, JSReceiver);
    249   }
    250 
    251   PrototypeIterator iter(isolate, home_object);
    252   Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
    253   if (!proto->IsJSReceiver()) {
    254     MessageTemplate::Template message =
    255         mode == SuperMode::kLoad ? MessageTemplate::kNonObjectPropertyLoad
    256                                  : MessageTemplate::kNonObjectPropertyStore;
    257     Handle<Name> name;
    258     if (!maybe_name.ToHandle(&name)) {
    259       name = isolate->factory()->Uint32ToString(index);
    260     }
    261     THROW_NEW_ERROR(isolate, NewTypeError(message, name, proto), JSReceiver);
    262   }
    263   return Handle<JSReceiver>::cast(proto);
    264 }
    265 
    266 MaybeHandle<Object> LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
    267                                   Handle<JSObject> home_object,
    268                                   Handle<Name> name) {
    269   Handle<JSReceiver> holder;
    270   ASSIGN_RETURN_ON_EXCEPTION(
    271       isolate, holder,
    272       GetSuperHolder(isolate, receiver, home_object, SuperMode::kLoad, name, 0),
    273       Object);
    274   LookupIterator it(receiver, name, holder);
    275   Handle<Object> result;
    276   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
    277   return result;
    278 }
    279 
    280 MaybeHandle<Object> LoadElementFromSuper(Isolate* isolate,
    281                                          Handle<Object> receiver,
    282                                          Handle<JSObject> home_object,
    283                                          uint32_t index) {
    284   Handle<JSReceiver> holder;
    285   ASSIGN_RETURN_ON_EXCEPTION(
    286       isolate, holder,
    287       GetSuperHolder(isolate, receiver, home_object, SuperMode::kLoad,
    288                      MaybeHandle<Name>(), index),
    289       Object);
    290   LookupIterator it(isolate, receiver, index, holder);
    291   Handle<Object> result;
    292   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
    293   return result;
    294 }
    295 
    296 }  // anonymous namespace
    297 
    298 RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
    299   HandleScope scope(isolate);
    300   DCHECK_EQ(3, args.length());
    301   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
    302   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
    303   CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
    304 
    305   RETURN_RESULT_OR_FAILURE(isolate,
    306                            LoadFromSuper(isolate, receiver, home_object, name));
    307 }
    308 
    309 
    310 RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
    311   HandleScope scope(isolate);
    312   DCHECK_EQ(3, args.length());
    313   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
    314   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
    315   CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
    316 
    317   uint32_t index = 0;
    318 
    319   if (key->ToArrayIndex(&index)) {
    320     RETURN_RESULT_OR_FAILURE(
    321         isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
    322   }
    323 
    324   Handle<Name> name;
    325   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
    326                                      Object::ToName(isolate, key));
    327   // TODO(verwaest): Unify using LookupIterator.
    328   if (name->AsArrayIndex(&index)) {
    329     RETURN_RESULT_OR_FAILURE(
    330         isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
    331   }
    332   RETURN_RESULT_OR_FAILURE(isolate,
    333                            LoadFromSuper(isolate, receiver, home_object, name));
    334 }
    335 
    336 namespace {
    337 
    338 MaybeHandle<Object> StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
    339                                  Handle<Object> receiver, Handle<Name> name,
    340                                  Handle<Object> value,
    341                                  LanguageMode language_mode) {
    342   Handle<JSReceiver> holder;
    343   ASSIGN_RETURN_ON_EXCEPTION(isolate, holder,
    344                              GetSuperHolder(isolate, receiver, home_object,
    345                                             SuperMode::kStore, name, 0),
    346                              Object);
    347   LookupIterator it(receiver, name, holder);
    348   MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
    349                                         Object::CERTAINLY_NOT_STORE_FROM_KEYED),
    350                MaybeHandle<Object>());
    351   return value;
    352 }
    353 
    354 MaybeHandle<Object> StoreElementToSuper(Isolate* isolate,
    355                                         Handle<JSObject> home_object,
    356                                         Handle<Object> receiver, uint32_t index,
    357                                         Handle<Object> value,
    358                                         LanguageMode language_mode) {
    359   Handle<JSReceiver> holder;
    360   ASSIGN_RETURN_ON_EXCEPTION(
    361       isolate, holder,
    362       GetSuperHolder(isolate, receiver, home_object, SuperMode::kStore,
    363                      MaybeHandle<Name>(), index),
    364       Object);
    365   LookupIterator it(isolate, receiver, index, holder);
    366   MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
    367                                         Object::MAY_BE_STORE_FROM_KEYED),
    368                MaybeHandle<Object>());
    369   return value;
    370 }
    371 
    372 }  // anonymous namespace
    373 
    374 RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
    375   HandleScope scope(isolate);
    376   DCHECK_EQ(4, args.length());
    377   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
    378   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
    379   CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
    380   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
    381 
    382   RETURN_RESULT_OR_FAILURE(isolate, StoreToSuper(isolate, home_object, receiver,
    383                                                  name, value, STRICT));
    384 }
    385 
    386 
    387 RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
    388   HandleScope scope(isolate);
    389   DCHECK_EQ(4, args.length());
    390   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
    391   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
    392   CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
    393   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
    394 
    395   RETURN_RESULT_OR_FAILURE(isolate, StoreToSuper(isolate, home_object, receiver,
    396                                                  name, value, SLOPPY));
    397 }
    398 
    399 static MaybeHandle<Object> StoreKeyedToSuper(
    400     Isolate* isolate, Handle<JSObject> home_object, Handle<Object> receiver,
    401     Handle<Object> key, Handle<Object> value, LanguageMode language_mode) {
    402   uint32_t index = 0;
    403 
    404   if (key->ToArrayIndex(&index)) {
    405     return StoreElementToSuper(isolate, home_object, receiver, index, value,
    406                                language_mode);
    407   }
    408   Handle<Name> name;
    409   ASSIGN_RETURN_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key),
    410                              Object);
    411   // TODO(verwaest): Unify using LookupIterator.
    412   if (name->AsArrayIndex(&index)) {
    413     return StoreElementToSuper(isolate, home_object, receiver, index, value,
    414                                language_mode);
    415   }
    416   return StoreToSuper(isolate, home_object, receiver, name, value,
    417                       language_mode);
    418 }
    419 
    420 
    421 RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict) {
    422   HandleScope scope(isolate);
    423   DCHECK_EQ(4, args.length());
    424   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
    425   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
    426   CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
    427   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
    428 
    429   RETURN_RESULT_OR_FAILURE(
    430       isolate,
    431       StoreKeyedToSuper(isolate, home_object, receiver, key, value, STRICT));
    432 }
    433 
    434 
    435 RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) {
    436   HandleScope scope(isolate);
    437   DCHECK_EQ(4, args.length());
    438   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
    439   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
    440   CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
    441   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
    442 
    443   RETURN_RESULT_OR_FAILURE(
    444       isolate,
    445       StoreKeyedToSuper(isolate, home_object, receiver, key, value, SLOPPY));
    446 }
    447 
    448 
    449 RUNTIME_FUNCTION(Runtime_GetSuperConstructor) {
    450   SealHandleScope shs(isolate);
    451   DCHECK_EQ(1, args.length());
    452   CONVERT_ARG_CHECKED(JSFunction, active_function, 0);
    453   Object* prototype = active_function->map()->prototype();
    454   if (!prototype->IsConstructor()) {
    455     HandleScope scope(isolate);
    456     return ThrowNotSuperConstructor(isolate, handle(prototype, isolate),
    457                                     handle(active_function, isolate));
    458   }
    459   return prototype;
    460 }
    461 
    462 }  // namespace internal
    463 }  // namespace v8
    464