// 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. #include "src/runtime/runtime-utils.h" #include #include #include "src/arguments.h" #include "src/debug/debug.h" #include "src/frames-inl.h" #include "src/isolate-inl.h" #include "src/messages.h" #include "src/runtime/runtime.h" namespace v8 { namespace internal { RUNTIME_FUNCTION(Runtime_ThrowNonMethodError) { HandleScope scope(isolate); DCHECK(args.length() == 0); THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewReferenceError(MessageTemplate::kNonMethod)); } RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) { HandleScope scope(isolate); DCHECK(args.length() == 0); THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewReferenceError(MessageTemplate::kUnsupportedSuper)); } RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); Handle name(constructor->shared()->name(), isolate); THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kConstructorNonCallable, name)); } RUNTIME_FUNCTION(Runtime_ThrowArrayNotSubclassableError) { HandleScope scope(isolate); DCHECK(args.length() == 0); THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kArrayNotSubclassable)); } static Object* ThrowStaticPrototypeError(Isolate* isolate) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kStaticPrototype)); } RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) { HandleScope scope(isolate); DCHECK(args.length() == 0); return ThrowStaticPrototypeError(isolate); } RUNTIME_FUNCTION(Runtime_ThrowIfStaticPrototype) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Name, name, 0); if (Name::Equals(name, isolate->factory()->prototype_string())) { return ThrowStaticPrototypeError(isolate); } return *name; } RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) { DCHECK(args.length() == 0); return isolate->heap()->home_object_symbol(); } static MaybeHandle DefineClass(Isolate* isolate, Handle super_class, Handle constructor, int start_position, int end_position) { Handle prototype_parent; Handle constructor_parent; if (super_class->IsTheHole(isolate)) { prototype_parent = isolate->initial_object_prototype(); } else { if (super_class->IsNull(isolate)) { prototype_parent = isolate->factory()->null_value(); } else if (super_class->IsConstructor()) { DCHECK(!super_class->IsJSFunction() || !Handle::cast(super_class)->shared()->is_resumable()); ASSIGN_RETURN_ON_EXCEPTION( isolate, prototype_parent, Runtime::GetObjectProperty(isolate, super_class, isolate->factory()->prototype_string()), Object); if (!prototype_parent->IsNull(isolate) && !prototype_parent->IsJSReceiver()) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject, prototype_parent), Object); } constructor_parent = super_class; } else { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kExtendsValueNotConstructor, super_class), Object); } } Handle map = isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); map->set_is_prototype_map(true); Map::SetPrototype(map, prototype_parent); map->SetConstructor(*constructor); Handle prototype = isolate->factory()->NewJSObjectFromMap(map); if (!super_class->IsTheHole(isolate)) { // Derived classes, just like builtins, don't create implicit receivers in // [[construct]]. Instead they just set up new.target and call into the // constructor. Hence we can reuse the builtins construct stub for derived // classes. Handle stub(isolate->builtins()->JSBuiltinsConstructStubForDerived()); constructor->shared()->set_construct_stub(*stub); } JSFunction::SetPrototype(constructor, prototype); PropertyAttributes attribs = static_cast(DONT_ENUM | DONT_DELETE | READ_ONLY); RETURN_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( constructor, isolate->factory()->prototype_string(), prototype, attribs), Object); // TODO(arv): Only do this conditionally. Handle home_object_symbol(isolate->heap()->home_object_symbol()); RETURN_ON_EXCEPTION( isolate, JSObject::SetOwnPropertyIgnoreAttributes( constructor, home_object_symbol, prototype, DONT_ENUM), Object); if (!constructor_parent.is_null()) { MAYBE_RETURN_NULL(JSObject::SetPrototype(constructor, constructor_parent, false, Object::THROW_ON_ERROR)); } JSObject::AddProperty(prototype, isolate->factory()->constructor_string(), constructor, DONT_ENUM); // Install private properties that are used to construct the FunctionToString. RETURN_ON_EXCEPTION( isolate, Object::SetProperty( constructor, isolate->factory()->class_start_position_symbol(), handle(Smi::FromInt(start_position), isolate), STRICT), Object); RETURN_ON_EXCEPTION( isolate, Object::SetProperty( constructor, isolate->factory()->class_end_position_symbol(), handle(Smi::FromInt(end_position), isolate), STRICT), Object); return constructor; } RUNTIME_FUNCTION(Runtime_DefineClass) { HandleScope scope(isolate); DCHECK(args.length() == 4); 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); RETURN_RESULT_OR_FAILURE( isolate, DefineClass(isolate, super_class, constructor, start_position, end_position)); } static MaybeHandle LoadFromSuper(Isolate* isolate, Handle receiver, Handle home_object, Handle name) { if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(handle(isolate->context()), home_object)) { isolate->ReportFailedAccessCheck(home_object); RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); } PrototypeIterator iter(isolate, home_object); Handle proto = PrototypeIterator::GetCurrent(iter); if (!proto->IsJSReceiver()) { return Object::ReadAbsentProperty(isolate, proto, name); } LookupIterator it(receiver, name, Handle::cast(proto)); Handle result; ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object); return result; } static MaybeHandle LoadElementFromSuper(Isolate* isolate, Handle receiver, Handle home_object, uint32_t index) { if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(handle(isolate->context()), home_object)) { isolate->ReportFailedAccessCheck(home_object); RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); } PrototypeIterator iter(isolate, home_object); Handle proto = PrototypeIterator::GetCurrent(iter); if (!proto->IsJSReceiver()) { Handle name = isolate->factory()->NewNumberFromUint(index); return Object::ReadAbsentProperty(isolate, proto, name); } LookupIterator it(isolate, receiver, index, Handle::cast(proto)); Handle result; ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object); return result; } RUNTIME_FUNCTION(Runtime_LoadFromSuper) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1); CONVERT_ARG_HANDLE_CHECKED(Name, name, 2); RETURN_RESULT_OR_FAILURE(isolate, LoadFromSuper(isolate, receiver, home_object, name)); } RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1); CONVERT_ARG_HANDLE_CHECKED(Object, key, 2); uint32_t index = 0; if (key->ToArrayIndex(&index)) { RETURN_RESULT_OR_FAILURE( isolate, LoadElementFromSuper(isolate, receiver, home_object, index)); } Handle name; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key)); // TODO(verwaest): Unify using LookupIterator. if (name->AsArrayIndex(&index)) { RETURN_RESULT_OR_FAILURE( isolate, LoadElementFromSuper(isolate, receiver, home_object, index)); } RETURN_RESULT_OR_FAILURE(isolate, LoadFromSuper(isolate, receiver, home_object, name)); } static Object* StoreToSuper(Isolate* isolate, Handle home_object, Handle receiver, Handle name, Handle value, LanguageMode language_mode) { if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(handle(isolate->context()), home_object)) { isolate->ReportFailedAccessCheck(home_object); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); } PrototypeIterator iter(isolate, home_object); Handle proto = PrototypeIterator::GetCurrent(iter); if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value(); LookupIterator it(receiver, name, Handle::cast(proto)); MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode, Object::CERTAINLY_NOT_STORE_FROM_KEYED), isolate->heap()->exception()); return *value; } static Object* StoreElementToSuper(Isolate* isolate, Handle home_object, Handle receiver, uint32_t index, Handle value, LanguageMode language_mode) { if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(handle(isolate->context()), home_object)) { isolate->ReportFailedAccessCheck(home_object); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); } PrototypeIterator iter(isolate, home_object); Handle proto = PrototypeIterator::GetCurrent(iter); if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value(); LookupIterator it(isolate, receiver, index, Handle::cast(proto)); MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode, Object::MAY_BE_STORE_FROM_KEYED), isolate->heap()->exception()); return *value; } RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) { HandleScope scope(isolate); DCHECK(args.length() == 4); 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); return StoreToSuper(isolate, home_object, receiver, name, value, STRICT); } RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) { HandleScope scope(isolate); DCHECK(args.length() == 4); 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); return StoreToSuper(isolate, home_object, receiver, name, value, SLOPPY); } static Object* StoreKeyedToSuper(Isolate* isolate, Handle home_object, Handle receiver, Handle key, Handle value, LanguageMode language_mode) { uint32_t index = 0; if (key->ToArrayIndex(&index)) { return StoreElementToSuper(isolate, home_object, receiver, index, value, language_mode); } Handle name; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key)); // TODO(verwaest): Unify using LookupIterator. if (name->AsArrayIndex(&index)) { return StoreElementToSuper(isolate, home_object, receiver, index, value, language_mode); } return StoreToSuper(isolate, home_object, receiver, name, value, language_mode); } RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict) { HandleScope scope(isolate); DCHECK(args.length() == 4); 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); return StoreKeyedToSuper(isolate, home_object, receiver, key, value, STRICT); } RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) { HandleScope scope(isolate); DCHECK(args.length() == 4); 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); return StoreKeyedToSuper(isolate, home_object, receiver, key, value, SLOPPY); } RUNTIME_FUNCTION(Runtime_GetSuperConstructor) { SealHandleScope shs(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_CHECKED(JSFunction, active_function, 0); return active_function->map()->prototype(); } } // namespace internal } // namespace v8