runtime-classes.cc 16.1 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/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 18 19 20 21 22
#include "src/runtime/runtime.h"

namespace v8 {
namespace internal {


23 24
RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
  HandleScope scope(isolate);
25
  DCHECK_EQ(0, args.length());
26 27
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewReferenceError(MessageTemplate::kUnsupportedSuper));
28 29 30
}


31 32
RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
  HandleScope scope(isolate);
33
  DCHECK_EQ(1, args.length());
34
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
35
  Handle<String> name(constructor->shared()->name(), isolate);
36
  THROW_NEW_ERROR_RETURN_FAILURE(
37
      isolate, NewTypeError(MessageTemplate::kConstructorNonCallable, name));
38 39 40
}


41 42
RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) {
  HandleScope scope(isolate);
43
  DCHECK_EQ(0, args.length());
44 45
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewTypeError(MessageTemplate::kStaticPrototype));
46 47
}

48 49 50 51 52 53 54
RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) {
  HandleScope scope(isolate);
  DCHECK_EQ(0, args.length());
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled));
}

55 56 57 58 59 60 61
RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled) {
  HandleScope scope(isolate);
  DCHECK_EQ(0, args.length());
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewReferenceError(MessageTemplate::kSuperNotCalled));
}

62 63 64 65
namespace {

Object* ThrowNotSuperConstructor(Isolate* isolate, Handle<Object> constructor,
                                 Handle<JSFunction> function) {
66
  Handle<String> super_name;
67 68 69 70 71 72 73 74 75 76
  if (constructor->IsJSFunction()) {
    super_name = handle(Handle<JSFunction>::cast(constructor)->shared()->name(),
                        isolate);
  } else if (constructor->IsOddball()) {
    DCHECK(constructor->IsNull(isolate));
    super_name = isolate->factory()->null_string();
  } else {
    super_name = Object::NoSideEffectsToString(isolate, constructor);
  }
  // null constructor
77
  if (super_name->length() == 0) {
78 79
    super_name = isolate->factory()->null_string();
  }
80
  Handle<String> function_name(function->shared()->name(), isolate);
81
  // anonymous class
82
  if (function_name->length() == 0) {
83 84 85 86 87 88 89 90 91 92 93 94 95 96
    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);
97
  DCHECK_EQ(2, args.length());
98 99 100 101 102
  CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
  return ThrowNotSuperConstructor(isolate, constructor, function);
}

103
RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
104
  DCHECK_EQ(0, args.length());
105 106 107
  return isolate->heap()->home_object_symbol();
}

108
static MaybeHandle<Object> DefineClass(Isolate* isolate,
109 110 111
                                       Handle<Object> super_class,
                                       Handle<JSFunction> constructor,
                                       int start_position, int end_position) {
112 113 114
  Handle<Object> prototype_parent;
  Handle<Object> constructor_parent;

115
  if (super_class->IsTheHole(isolate)) {
116 117
    prototype_parent = isolate->initial_object_prototype();
  } else {
118
    if (super_class->IsNull(isolate)) {
119
      prototype_parent = isolate->factory()->null_value();
120
    } else if (super_class->IsConstructor()) {
121
      DCHECK(!super_class->IsJSFunction() ||
122 123
             !IsResumableFunction(
                 Handle<JSFunction>::cast(super_class)->shared()->kind()));
124
      ASSIGN_RETURN_ON_EXCEPTION(
125 126
          isolate, prototype_parent,
          Runtime::GetObjectProperty(isolate, super_class,
127
                                     isolate->factory()->prototype_string()),
128
          Object);
129 130
      if (!prototype_parent->IsNull(isolate) &&
          !prototype_parent->IsJSReceiver()) {
131
        THROW_NEW_ERROR(
132
            isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
133 134
                                  prototype_parent),
            Object);
135 136 137
      }
      constructor_parent = super_class;
    } else {
138 139 140 141
      THROW_NEW_ERROR(isolate,
                      NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
                                   super_class),
                      Object);
142 143 144 145 146
    }
  }

  Handle<Map> map =
      isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
147
  map->set_is_prototype_map(true);
148
  Map::SetPrototype(map, prototype_parent);
149
  map->SetConstructor(*constructor);
150 151
  Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);

152 153 154
  JSFunction::SetPrototype(constructor, prototype);
  PropertyAttributes attribs =
      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
155 156 157 158 159
  RETURN_ON_EXCEPTION(isolate,
                      JSObject::SetOwnPropertyIgnoreAttributes(
                          constructor, isolate->factory()->prototype_string(),
                          prototype, attribs),
                      Object);
160

161
  if (!constructor_parent.is_null()) {
162
    MAYBE_RETURN_NULL(JSObject::SetPrototype(constructor, constructor_parent,
163
                                             false, Object::THROW_ON_ERROR));
164 165 166
  }

  JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
167
                        constructor, DONT_ENUM);
168

169
  // Install private properties that are used to construct the FunctionToString.
170
  RETURN_ON_EXCEPTION(
171
      isolate,
172 173
      Object::SetProperty(
          constructor, isolate->factory()->class_start_position_symbol(),
174 175 176
          handle(Smi::FromInt(start_position), isolate), STRICT),
      Object);
  RETURN_ON_EXCEPTION(
177
      isolate, Object::SetProperty(
178
                   constructor, isolate->factory()->class_end_position_symbol(),
179 180 181
                   handle(Smi::FromInt(end_position), isolate), STRICT),
      Object);

182 183
  // Caller already has access to constructor, so return the prototype.
  return prototype;
184 185 186 187 188
}


RUNTIME_FUNCTION(Runtime_DefineClass) {
  HandleScope scope(isolate);
189
  DCHECK_EQ(4, args.length());
190 191 192 193
  CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 1);
  CONVERT_SMI_ARG_CHECKED(start_position, 2);
  CONVERT_SMI_ARG_CHECKED(end_position, 3);
194

195 196 197
  RETURN_RESULT_OR_FAILURE(
      isolate, DefineClass(isolate, super_class, constructor, start_position,
                           end_position));
198 199
}

200 201 202 203 204 205 206 207 208 209 210 211 212 213
namespace {
void InstallClassNameAccessor(Isolate* isolate, Handle<JSObject> object) {
  PropertyAttributes attrs =
      static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
  // Cannot fail since this should only be called when creating an object
  // literal.
  CHECK(!JSObject::SetAccessor(
             object, Accessors::FunctionNameInfo(object->GetIsolate(), attrs))
             .is_null());
}
}  // anonymous namespace

RUNTIME_FUNCTION(Runtime_InstallClassNameAccessor) {
  HandleScope scope(isolate);
214
  DCHECK_EQ(1, args.length());
215 216 217 218 219 220 221
  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
  InstallClassNameAccessor(isolate, object);
  return *object;
}

RUNTIME_FUNCTION(Runtime_InstallClassNameAccessorWithCheck) {
  HandleScope scope(isolate);
222
  DCHECK_EQ(1, args.length());
223 224 225 226 227 228 229 230 231 232 233 234 235
  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);

  // If a property named "name" is already defined, exit.
  Handle<Name> key = isolate->factory()->name_string();
  if (JSObject::HasRealNamedProperty(object, key).FromMaybe(false)) {
    return *object;
  }

  // Define the "name" accessor.
  InstallClassNameAccessor(isolate, object);
  return *object;
}

236
namespace {
237

238 239 240 241 242
enum class SuperMode { kLoad, kStore };

MaybeHandle<JSReceiver> GetSuperHolder(
    Isolate* isolate, Handle<Object> receiver, Handle<JSObject> home_object,
    SuperMode mode, MaybeHandle<Name> maybe_name, uint32_t index) {
243 244
  if (home_object->IsAccessCheckNeeded() &&
      !isolate->MayAccess(handle(isolate->context()), home_object)) {
245
    isolate->ReportFailedAccessCheck(home_object);
246
    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, JSReceiver);
247 248 249 250
  }

  PrototypeIterator iter(isolate, home_object);
  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
251
  if (!proto->IsJSReceiver()) {
252 253 254 255 256 257 258 259
    MessageTemplate::Template message =
        mode == SuperMode::kLoad ? MessageTemplate::kNonObjectPropertyLoad
                                 : MessageTemplate::kNonObjectPropertyStore;
    Handle<Name> name;
    if (!maybe_name.ToHandle(&name)) {
      name = isolate->factory()->Uint32ToString(index);
    }
    THROW_NEW_ERROR(isolate, NewTypeError(message, name, proto), JSReceiver);
260
  }
261 262
  return Handle<JSReceiver>::cast(proto);
}
263

264 265 266 267 268 269 270 271 272
MaybeHandle<Object> LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
                                  Handle<JSObject> home_object,
                                  Handle<Name> name) {
  Handle<JSReceiver> holder;
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, holder,
      GetSuperHolder(isolate, receiver, home_object, SuperMode::kLoad, name, 0),
      Object);
  LookupIterator it(receiver, name, holder);
273
  Handle<Object> result;
274
  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
275
  return result;
276 277
}

278 279 280 281 282 283 284 285 286 287 288
MaybeHandle<Object> LoadElementFromSuper(Isolate* isolate,
                                         Handle<Object> receiver,
                                         Handle<JSObject> home_object,
                                         uint32_t index) {
  Handle<JSReceiver> holder;
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, holder,
      GetSuperHolder(isolate, receiver, home_object, SuperMode::kLoad,
                     MaybeHandle<Name>(), index),
      Object);
  LookupIterator it(isolate, receiver, index, holder);
289
  Handle<Object> result;
290
  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
291
  return result;
292 293
}

294
}  // anonymous namespace
295

296 297
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
  HandleScope scope(isolate);
298
  DCHECK_EQ(3, args.length());
299 300 301 302
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);

303 304
  RETURN_RESULT_OR_FAILURE(isolate,
                           LoadFromSuper(isolate, receiver, home_object, name));
305 306 307 308 309
}


RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
  HandleScope scope(isolate);
310
  DCHECK_EQ(3, args.length());
311 312 313 314
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);

315
  uint32_t index = 0;
316

317
  if (key->ToArrayIndex(&index)) {
318 319
    RETURN_RESULT_OR_FAILURE(
        isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
320 321
  }

322 323
  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
324
                                     Object::ToName(isolate, key));
325
  // TODO(verwaest): Unify using LookupIterator.
326
  if (name->AsArrayIndex(&index)) {
327 328
    RETURN_RESULT_OR_FAILURE(
        isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
329
  }
330 331
  RETURN_RESULT_OR_FAILURE(isolate,
                           LoadFromSuper(isolate, receiver, home_object, name));
332 333
}

334
namespace {
335

336 337 338 339 340 341 342 343 344 345
MaybeHandle<Object> StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
                                 Handle<Object> receiver, Handle<Name> name,
                                 Handle<Object> value,
                                 LanguageMode language_mode) {
  Handle<JSReceiver> holder;
  ASSIGN_RETURN_ON_EXCEPTION(isolate, holder,
                             GetSuperHolder(isolate, receiver, home_object,
                                            SuperMode::kStore, name, 0),
                             Object);
  LookupIterator it(receiver, name, holder);
346 347
  MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
                                        Object::CERTAINLY_NOT_STORE_FROM_KEYED),
348 349
               MaybeHandle<Object>());
  return value;
350 351
}

352 353 354 355 356 357 358 359 360 361 362 363
MaybeHandle<Object> StoreElementToSuper(Isolate* isolate,
                                        Handle<JSObject> home_object,
                                        Handle<Object> receiver, uint32_t index,
                                        Handle<Object> value,
                                        LanguageMode language_mode) {
  Handle<JSReceiver> holder;
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, holder,
      GetSuperHolder(isolate, receiver, home_object, SuperMode::kStore,
                     MaybeHandle<Name>(), index),
      Object);
  LookupIterator it(isolate, receiver, index, holder);
364 365
  MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
                                        Object::MAY_BE_STORE_FROM_KEYED),
366 367
               MaybeHandle<Object>());
  return value;
368 369
}

370
}  // anonymous namespace
371

372 373
RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
  HandleScope scope(isolate);
374
  DCHECK_EQ(4, args.length());
375 376 377 378 379
  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);

380 381
  RETURN_RESULT_OR_FAILURE(isolate, StoreToSuper(isolate, home_object, receiver,
                                                 name, value, STRICT));
382 383 384 385 386
}


RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
  HandleScope scope(isolate);
387
  DCHECK_EQ(4, args.length());
388 389 390 391 392
  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);

393 394
  RETURN_RESULT_OR_FAILURE(isolate, StoreToSuper(isolate, home_object, receiver,
                                                 name, value, SLOPPY));
395 396
}

397 398 399
static MaybeHandle<Object> StoreKeyedToSuper(
    Isolate* isolate, Handle<JSObject> home_object, Handle<Object> receiver,
    Handle<Object> key, Handle<Object> value, LanguageMode language_mode) {
400
  uint32_t index = 0;
401 402 403

  if (key->ToArrayIndex(&index)) {
    return StoreElementToSuper(isolate, home_object, receiver, index, value,
404
                               language_mode);
405
  }
406
  Handle<Name> name;
407 408
  ASSIGN_RETURN_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key),
                             Object);
409
  // TODO(verwaest): Unify using LookupIterator.
410
  if (name->AsArrayIndex(&index)) {
411
    return StoreElementToSuper(isolate, home_object, receiver, index, value,
412
                               language_mode);
413
  }
414 415
  return StoreToSuper(isolate, home_object, receiver, name, value,
                      language_mode);
416 417 418 419 420
}


RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict) {
  HandleScope scope(isolate);
421
  DCHECK_EQ(4, args.length());
422 423 424 425 426
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);

427 428 429
  RETURN_RESULT_OR_FAILURE(
      isolate,
      StoreKeyedToSuper(isolate, home_object, receiver, key, value, STRICT));
430 431 432 433 434
}


RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) {
  HandleScope scope(isolate);
435
  DCHECK_EQ(4, args.length());
436 437 438 439 440
  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);

441 442 443
  RETURN_RESULT_OR_FAILURE(
      isolate,
      StoreKeyedToSuper(isolate, home_object, receiver, key, value, SLOPPY));
444
}
445 446


447 448 449
RUNTIME_FUNCTION(Runtime_GetSuperConstructor) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
450
  CONVERT_ARG_CHECKED(JSFunction, active_function, 0);
451 452
  Object* prototype = active_function->map()->prototype();
  if (!prototype->IsConstructor()) {
453 454 455
    HandleScope scope(isolate);
    return ThrowNotSuperConstructor(isolate, handle(prototype, isolate),
                                    handle(active_function, isolate));
456 457
  }
  return prototype;
458 459
}

460 461
}  // namespace internal
}  // namespace v8