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