#include <stdlib.h>
#include <limits>
#include "src/builtins/accessors.h"
#include "src/common/globals.h"
#include "src/common/message-template.h"
#include "src/execution/arguments-inl.h"
#include "src/execution/isolate-inl.h"
#include "src/logging/log.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/lookup-inl.h"
#include "src/objects/smi.h"
#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewReferenceError(MessageTemplate::kUnsupportedSuper));
}
RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
DirectHandle<JSFunction> constructor = args.at<JSFunction>(0);
DirectHandle<String> name(constructor->shared()->Name(), isolate);
DirectHandle<Context> context(constructor->native_context(), isolate);
DCHECK(IsNativeContext(*context));
DirectHandle<JSFunction> realm_type_error_function(
Cast<JSFunction>(context->GetNoCell(Context::TYPE_ERROR_FUNCTION_INDEX)),
isolate);
if (name->length() == 0) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewError(realm_type_error_function,
MessageTemplate::kAnonymousConstructorNonCallable));
}
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewError(realm_type_error_function,
MessageTemplate::kConstructorNonCallable, name));
}
RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kStaticPrototype));
}
RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled));
}
RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewReferenceError(MessageTemplate::kSuperNotCalled));
}
namespace {
Tagged<Object> ThrowNotSuperConstructor(Isolate* isolate,
DirectHandle<Object> constructor,
DirectHandle<JSFunction> function) {
DirectHandle<String> super_name;
if (IsJSFunction(*constructor)) {
super_name =
direct_handle(Cast<JSFunction>(constructor)->shared()->Name(), isolate);
} else if (IsOddball(*constructor)) {
DCHECK(IsNull(*constructor, isolate));
super_name = isolate->factory()->null_string();
} else {
super_name = Object::NoSideEffectsToString(isolate, constructor);
}
if (super_name->length() == 0) {
super_name = isolate->factory()->null_string();
}
Handle<String> function_name(function->shared()->Name(), isolate);
if (function_name->length() == 0) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(MessageTemplate::kNotSuperConstructorAnonymousClass,
super_name));
}
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kNotSuperConstructor, super_name,
function_name));
}
}
RUNTIME_FUNCTION(Runtime_ThrowNotSuperConstructor) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
DirectHandle<Object> constructor = args.at(0);
DirectHandle<JSFunction> function = args.at<JSFunction>(1);
return ThrowNotSuperConstructor(isolate, constructor, function);
}
namespace {
template <typename Dictionary>
Handle<Name> KeyToName(Isolate* isolate, Handle<Object> key) {
static_assert((std::is_same_v<Dictionary, SwissNameDictionary> ||
std::is_same_v<Dictionary, NameDictionary>));
DCHECK(IsName(*key));
return Cast<Name>(key);
}
template <>
Handle<Name> KeyToName<NumberDictionary>(Isolate* isolate, Handle<Object> key) {
DCHECK(IsNumber(*key));
return isolate->factory()->NumberToString(key);
}
template <typename Dictionary>
MaybeDirectHandle<Object> GetMethodAndSetName(Isolate* isolate,
RuntimeArguments& args,
Tagged<Smi> index,
DirectHandle<String> name_prefix,
Handle<Object> key) {
int int_index = index.value();
if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
return args.at<Object>(int_index);
}
DirectHandle<JSFunction> method = args.at<JSFunction>(int_index);
if (!method->shared()->HasSharedName()) {
DirectHandle<Name> name = KeyToName<Dictionary>(isolate, key);
if (!JSFunction::SetName(isolate, method, name, name_prefix)) {
return MaybeDirectHandle<Object>();
}
}
return method;
}
Tagged<Object> GetMethodWithSharedName(Isolate* isolate, RuntimeArguments& args,
Tagged<Object> index) {
DisallowGarbageCollection no_gc;
int int_index = Smi::ToInt(index);
if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
return args[int_index];
}
DirectHandle<JSFunction> method = args.at<JSFunction>(int_index);
DCHECK(method->shared()->HasSharedName());
return *method;
}
template <typename Dictionary>
Handle<Dictionary> ShallowCopyDictionaryTemplate(
Isolate* isolate, DirectHandle<Dictionary> dictionary_template) {
Handle<Dictionary> dictionary =
Dictionary::ShallowCopy(isolate, dictionary_template);
for (InternalIndex i : dictionary->IterateEntries()) {
Tagged<Object> value = dictionary->ValueAt(i);
if (IsAccessorPair(value)) {
DirectHandle<AccessorPair> pair(Cast<AccessorPair>(value), isolate);
pair = AccessorPair::Copy(isolate, pair);
dictionary->ValueAtPut(i, *pair);
}
}
return dictionary;
}
template <typename Dictionary>
bool SubstituteValues(Isolate* isolate, DirectHandle<Dictionary> dictionary,
RuntimeArguments& args) {
ReadOnlyRoots roots(isolate);
for (InternalIndex i : dictionary->IterateEntries()) {
Tagged<Object> maybe_key = dictionary->KeyAt(i);
if (!Dictionary::IsKey(roots, maybe_key)) continue;
Handle<Object> key(maybe_key, isolate);
Handle<Object> value(dictionary->ValueAt(i), isolate);
if (IsAccessorPair(*value)) {
auto pair = Cast<AccessorPair>(value);
Tagged<Object> tmp = pair->getter();
if (IsSmi(tmp)) {
DirectHandle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result,
GetMethodAndSetName<Dictionary>(isolate, args, Cast<Smi>(tmp),
isolate->factory()->get_string(),
key),
false);
pair->set_getter(*result);
}
tmp = pair->setter();
if (IsSmi(tmp)) {
DirectHandle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result,
GetMethodAndSetName<Dictionary>(isolate, args, Cast<Smi>(tmp),
isolate->factory()->set_string(),
key),
false);
pair->set_setter(*result);
}
} else if (IsSmi(*value)) {
DirectHandle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result,
GetMethodAndSetName<Dictionary>(isolate, args, Cast<Smi>(*value),
isolate->factory()->empty_string(),
key),
false);
dictionary->ValueAtPut(i, *result);
}
}
return true;
}
template <typename Dictionary>
void UpdateProtectors(Isolate* isolate, DirectHandle<JSObject> receiver,
DirectHandle<Dictionary> properties_dictionary) {
ReadOnlyRoots roots(isolate);
for (InternalIndex i : properties_dictionary->IterateEntries()) {
Tagged<Object> maybe_key = properties_dictionary->KeyAt(i);
if (!Dictionary::IsKey(roots, maybe_key)) continue;
DirectHandle<Name> name(Cast<Name>(maybe_key), isolate);
LookupIterator::UpdateProtector(isolate, receiver, name);
}
}
void UpdateProtectors(Isolate* isolate, DirectHandle<JSObject> receiver,
DirectHandle<DescriptorArray> properties_template) {
int nof_descriptors = properties_template->number_of_descriptors();
for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
DirectHandle<Name> name(properties_template->GetKey(i), isolate);
LookupIterator::UpdateProtector(isolate, receiver, name);
}
}
bool AddDescriptorsByTemplate(
Isolate* isolate, DirectHandle<Map> map,
DirectHandle<DescriptorArray> descriptors_template,
DirectHandle<NumberDictionary> elements_dictionary_template,
DirectHandle<JSObject> receiver, RuntimeArguments& args) {
int nof_descriptors = descriptors_template->number_of_descriptors();
DirectHandle<DescriptorArray> descriptors =
DescriptorArray::Allocate(isolate, nof_descriptors, 0);
DirectHandle<NumberDictionary> elements_dictionary =
*elements_dictionary_template ==
ReadOnlyRoots(isolate).empty_slow_element_dictionary()
? elements_dictionary_template
: ShallowCopyDictionaryTemplate(isolate,
elements_dictionary_template);
int count = 0;
for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
PropertyDetails details = descriptors_template->GetDetails(i);
if (details.location() == PropertyLocation::kDescriptor &&
details.kind() == PropertyKind::kData) {
count++;
}
}
DirectHandle<PropertyArray> property_array =
isolate->factory()->NewPropertyArray(count);
int field_index = 0;
for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
Tagged<Object> value = descriptors_template->GetStrongValue(i);
if (IsAccessorPair(value)) {
DirectHandle<AccessorPair> pair = AccessorPair::Copy(
isolate, direct_handle(Cast<AccessorPair>(value), isolate));
value = *pair;
}
DisallowGarbageCollection no_gc;
Tagged<Name> name = descriptors_template->GetKey(i);
if (name->IsInteresting(isolate)) {
map->set_may_have_interesting_properties(true);
}
DCHECK(IsUniqueName(name));
PropertyDetails details = descriptors_template->GetDetails(i);
if (details.location() == PropertyLocation::kDescriptor) {
if (details.kind() == PropertyKind::kData) {
if (IsSmi(value)) {
value = GetMethodWithSharedName(isolate, args, value);
}
details = details.CopyWithRepresentation(
Object::OptimalRepresentation(value, isolate));
} else {
DCHECK_EQ(PropertyKind::kAccessor, details.kind());
if (IsAccessorPair(value)) {
Tagged<AccessorPair> pair = Cast<AccessorPair>(value);
Tagged<Object> tmp = pair->getter();
if (IsSmi(tmp)) {
pair->set_getter(GetMethodWithSharedName(isolate, args, tmp));
}
tmp = pair->setter();
if (IsSmi(tmp)) {
pair->set_setter(GetMethodWithSharedName(isolate, args, tmp));
}
}
}
} else {
UNREACHABLE();
}
DCHECK(Object::FitsRepresentation(value, details.representation()));
if (details.location() == PropertyLocation::kDescriptor &&
details.kind() == PropertyKind::kData) {
details =
PropertyDetails(details.kind(), details.attributes(),
PropertyLocation::kField, PropertyConstness::kConst,
details.representation(), field_index)
.set_pointer(details.pointer());
property_array->set(field_index, value);
field_index++;
descriptors->Set(i, name, FieldType::Any(), details);
} else {
descriptors->Set(i, name, value, details);
}
}
UpdateProtectors(isolate, receiver, descriptors_template);
map->InitializeDescriptors(isolate, *descriptors);
if (elements_dictionary->NumberOfElements() > 0) {
if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
args)) {
return false;
}
map->set_elements_kind(DICTIONARY_ELEMENTS);
}
receiver->set_map(isolate, *map, kReleaseStore);
if (elements_dictionary->NumberOfElements() > 0) {
receiver->set_elements(*elements_dictionary);
}
if (property_array->length() > 0) {
receiver->SetProperties(*property_array);
}
return true;
}
template <typename T>
DirectHandle<T> ToHandle(Handle<T> h) {
return h;
}
template <typename T>
DirectHandle<T> ToHandle(MaybeHandle<T> h) {
return h.ToHandleChecked();
}
template <typename Dictionary>
bool AddDescriptorsByTemplate(
Isolate* isolate, DirectHandle<Map> map,
DirectHandle<Dictionary> properties_dictionary_template,
DirectHandle<NumberDictionary> elements_dictionary_template,
DirectHandle<FixedArray> computed_properties,
DirectHandle<JSObject> receiver, RuntimeArguments& args) {
int computed_properties_length = computed_properties->length();
Handle<Dictionary> properties_dictionary =
ShallowCopyDictionaryTemplate(isolate, properties_dictionary_template);
Handle<NumberDictionary> elements_dictionary =
ShallowCopyDictionaryTemplate(isolate, elements_dictionary_template);
using ValueKind = ClassBoilerplate::ValueKind;
using ComputedEntryFlags = ClassBoilerplate::ComputedEntryFlags;
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);
Tagged<Smi> value = Smi::FromInt(key_index + 1);
Handle<Object> key = args.at(key_index);
DCHECK(IsName(*key));
uint32_t element;
Handle<Name> name = Cast<Name>(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);
if (name->IsInteresting(isolate)) {
if constexpr (!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
properties_dictionary->set_may_have_interesting_properties(true);
}
}
}
}
if (!SubstituteValues<Dictionary>(isolate, properties_dictionary, args)) {
return false;
}
UpdateProtectors(isolate, receiver,
DirectHandle<Dictionary>(properties_dictionary));
if (elements_dictionary->NumberOfElements() > 0) {
if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
args)) {
return false;
}
map->set_elements_kind(DICTIONARY_ELEMENTS);
}
receiver->set_map(isolate, *map, kReleaseStore);
receiver->set_raw_properties_or_hash(*properties_dictionary, kRelaxedStore);
if (elements_dictionary->NumberOfElements() > 0) {
receiver->set_elements(*elements_dictionary);
}
return true;
}
DirectHandle<JSObject> CreateClassPrototype(Isolate* isolate) {
DirectHandle<Map> map = Map::Create(isolate, 0);
return isolate->factory()->NewJSObjectFromMap(map);
}
bool InitClassPrototype(Isolate* isolate,
DirectHandle<ClassBoilerplate> class_boilerplate,
DirectHandle<JSObject> prototype,
DirectHandle<JSPrototype> prototype_parent,
DirectHandle<JSFunction> constructor,
RuntimeArguments& args) {
DirectHandle<Map> map(prototype->map(), isolate);
map = Map::CopyDropDescriptors(isolate, map);
map->set_is_prototype_map(true);
Map::SetPrototype(isolate, map, prototype_parent);
isolate->UpdateProtectorsOnSetPrototype(prototype, prototype_parent);
constructor->set_prototype_or_initial_map(*prototype, kReleaseStore);
map->SetConstructor(*constructor);
DirectHandle<FixedArray> computed_properties(
class_boilerplate->instance_computed_properties(), isolate);
DirectHandle<NumberDictionary> elements_dictionary_template(
Cast<NumberDictionary>(class_boilerplate->instance_elements_template()),
isolate);
Handle<Object> properties_template(
class_boilerplate->instance_properties_template(), isolate);
if (IsDescriptorArray(*properties_template)) {
auto descriptors_template = Cast<DescriptorArray>(properties_template);
return AddDescriptorsByTemplate(isolate, map, descriptors_template,
elements_dictionary_template, prototype,
args);
} else {
map->set_is_dictionary_map(true);
map->set_is_migration_target(false);
map->set_may_have_interesting_properties(true);
map->set_construction_counter(Map::kNoSlackTracking);
DirectHandle<PropertyDictionary> properties_dictionary_template =
Cast<PropertyDictionary>(properties_template);
return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, prototype, args);
}
}
bool InitClassConstructor(Isolate* isolate,
DirectHandle<ClassBoilerplate> class_boilerplate,
DirectHandle<JSPrototype> constructor_parent,
DirectHandle<JSFunction> constructor,
RuntimeArguments& args) {
DirectHandle<Map> map(constructor->map(), isolate);
map = Map::CopyDropDescriptors(isolate, map);
DCHECK(map->is_prototype_map());
if (!constructor_parent.is_null()) {
Map::SetPrototype(isolate, map, constructor_parent, false);
JSObject::MakePrototypesFast(constructor_parent, kStartAtReceiver, isolate);
}
DirectHandle<NumberDictionary> elements_dictionary_template(
Cast<NumberDictionary>(class_boilerplate->static_elements_template()),
isolate);
DirectHandle<FixedArray> computed_properties(
class_boilerplate->static_computed_properties(), isolate);
Handle<Object> properties_template(
class_boilerplate->static_properties_template(), isolate);
if (IsDescriptorArray(*properties_template)) {
auto descriptors_template = Cast<DescriptorArray>(properties_template);
return AddDescriptorsByTemplate(isolate, map, descriptors_template,
elements_dictionary_template, constructor,
args);
} else {
map->set_is_dictionary_map(true);
map->InitializeDescriptors(isolate,
ReadOnlyRoots(isolate).empty_descriptor_array());
map->set_is_migration_target(false);
map->set_may_have_interesting_properties(true);
map->set_construction_counter(Map::kNoSlackTracking);
if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
DirectHandle<SwissNameDictionary> properties_dictionary_template =
Cast<SwissNameDictionary>(properties_template);
return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, constructor, args);
} else {
DirectHandle<NameDictionary> properties_dictionary_template =
Cast<NameDictionary>(properties_template);
return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, constructor, args);
}
}
}
MaybeDirectHandle<Object> DefineClass(
Isolate* isolate, DirectHandle<ClassBoilerplate> class_boilerplate,
DirectHandle<Object> super_class, DirectHandle<JSFunction> constructor,
RuntimeArguments& args) {
DirectHandle<JSPrototype> prototype_parent;
DirectHandle<JSPrototype> constructor_parent;
if (IsTheHole(*super_class, isolate)) {
prototype_parent = isolate->initial_object_prototype();
} else {
if (IsNull(*super_class, isolate)) {
prototype_parent = isolate->factory()->null_value();
} else if (IsConstructor(*super_class)) {
DCHECK(!IsJSFunction(*super_class) ||
!IsResumableFunction(
Cast<JSFunction>(super_class)->shared()->kind()));
DirectHandle<Object> maybe_prototype_parent;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, maybe_prototype_parent,
Runtime::GetObjectProperty(isolate, Cast<JSAny>(super_class),
isolate->factory()->prototype_string()));
if (!TryCast(maybe_prototype_parent, &prototype_parent)) {
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
maybe_prototype_parent));
}
constructor_parent =
direct_handle(Cast<JSPrototype>(*super_class), isolate);
} else {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
super_class));
}
}
DirectHandle<JSObject> prototype = CreateClassPrototype(isolate);
DCHECK_EQ(*constructor, args[ClassBoilerplate::kConstructorArgumentIndex]);
RuntimeArguments::ChangeValueScope set_prototype_value_scope(
isolate, &args, ClassBoilerplate::kPrototypeArgumentIndex, *prototype);
if (!InitClassConstructor(isolate, class_boilerplate, constructor_parent,
constructor, args) ||
!InitClassPrototype(isolate, class_boilerplate, prototype,
prototype_parent, constructor, args)) {
DCHECK(isolate->has_exception());
return MaybeDirectHandle<Object>();
}
if (v8_flags.log_maps) {
DirectHandle<Map> empty_map;
LOG(isolate,
MapEvent("InitialMap", empty_map,
direct_handle(constructor->map(), isolate),
"init class constructor",
SharedFunctionInfo::DebugName(
isolate, direct_handle(constructor->shared(), isolate))));
LOG(isolate, MapEvent("InitialMap", empty_map,
direct_handle(prototype->map(), isolate),
"init class prototype"));
}
return prototype;
}
}
RUNTIME_FUNCTION(Runtime_DefineClass) {
HandleScope scope(isolate);
DCHECK_LE(ClassBoilerplate::kFirstDynamicArgumentIndex, args.length());
DirectHandle<ClassBoilerplate> class_boilerplate =
args.at<ClassBoilerplate>(0);
DirectHandle<JSFunction> constructor = args.at<JSFunction>(1);
DirectHandle<Object> super_class = args.at(2);
DCHECK_EQ(class_boilerplate->arguments_count(), args.length());
RETURN_RESULT_OR_FAILURE(
isolate,
DefineClass(isolate, class_boilerplate, super_class, constructor, args));
}
namespace {
enum class SuperMode { kLoad, kStore };
MaybeDirectHandle<JSReceiver> GetSuperHolder(
Isolate* isolate, DirectHandle<Object> home_object_proto, SuperMode mode,
PropertyKey* key) {
if (!IsJSReceiver(*home_object_proto)) {
MessageTemplate message =
mode == SuperMode::kLoad
? MessageTemplate::kNonObjectPropertyLoadWithProperty
: MessageTemplate::kNonObjectPropertyStoreWithProperty;
DirectHandle<Name> name = key->GetName(isolate);
THROW_NEW_ERROR(isolate, NewTypeError(message, home_object_proto, name));
}
return Cast<JSReceiver>(home_object_proto);
}
MaybeDirectHandle<Object> LoadFromSuper(Isolate* isolate,
DirectHandle<JSAny> receiver,
DirectHandle<Object> home_object_proto,
PropertyKey* key) {
DirectHandle<JSReceiver> holder;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, holder,
GetSuperHolder(isolate, home_object_proto, SuperMode::kLoad, key));
LookupIterator it(isolate, receiver, *key, holder);
DirectHandle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
return result;
}
}
static MaybeDirectHandle<Object> GetHomeObjectPrototype(
Isolate* isolate, DirectHandle<JSObject> home_object) {
if (IsAccessCheckNeeded(*home_object) &&
!isolate->MayAccess(isolate->native_context(), home_object)) {
RETURN_ON_EXCEPTION(isolate, isolate->ReportFailedAccessCheck(home_object));
UNREACHABLE();
}
PrototypeIterator iter(isolate, home_object);
return PrototypeIterator::GetCurrent(iter);
}
RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
DirectHandle<JSAny> receiver = args.at<JSAny>(0);
DirectHandle<JSObject> home_object = args.at<JSObject>(1);
DirectHandle<Name> name = args.at<Name>(2);
DirectHandle<Object> home_object_proto;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, home_object_proto, GetHomeObjectPrototype(isolate, home_object));
PropertyKey key(isolate, name);
RETURN_RESULT_OR_FAILURE(
isolate, LoadFromSuper(isolate, receiver, home_object_proto, &key));
}
RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
DirectHandle<JSAny> receiver = args.at<JSAny>(0);
DirectHandle<JSObject> home_object = args.at<JSObject>(1);
DirectHandle<Object> key = args.at(2);
DirectHandle<Object> home_object_proto;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, home_object_proto, GetHomeObjectPrototype(isolate, home_object));
bool success;
PropertyKey lookup_key(isolate, key, &success);
if (!success) return ReadOnlyRoots(isolate).exception();
RETURN_RESULT_OR_FAILURE(
isolate,
LoadFromSuper(isolate, receiver, home_object_proto, &lookup_key));
}
namespace {
MaybeDirectHandle<Object> StoreToSuper(Isolate* isolate,
DirectHandle<Object> home_object_proto,
DirectHandle<JSAny> receiver,
PropertyKey* key,
DirectHandle<Object> value,
StoreOrigin store_origin) {
DirectHandle<JSReceiver> holder;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, holder,
GetSuperHolder(isolate, home_object_proto, SuperMode::kStore, key));
LookupIterator it(isolate, receiver, *key, holder);
MAYBE_RETURN(Object::SetSuperProperty(&it, value, store_origin),
MaybeDirectHandle<Object>());
return value;
}
}
RUNTIME_FUNCTION(Runtime_StoreToSuper) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
DirectHandle<JSAny> receiver = args.at<JSAny>(0);
DirectHandle<JSObject> home_object = args.at<JSObject>(1);
DirectHandle<Name> name = args.at<Name>(2);
DirectHandle<Object> value = args.at(3);
DirectHandle<Object> home_object_proto;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, home_object_proto, GetHomeObjectPrototype(isolate, home_object));
PropertyKey key(isolate, name);
RETURN_RESULT_OR_FAILURE(
isolate, StoreToSuper(isolate, home_object_proto, receiver, &key, value,
StoreOrigin::kNamed));
}
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
DirectHandle<JSAny> receiver = args.at<JSAny>(0);
DirectHandle<JSObject> home_object = args.at<JSObject>(1);
DirectHandle<Object> key = args.at(2);
DirectHandle<Object> value = args.at(3);
DirectHandle<Object> home_object_proto;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, home_object_proto, GetHomeObjectPrototype(isolate, home_object));
bool success;
PropertyKey lookup_key(isolate, key, &success);
if (!success) return ReadOnlyRoots(isolate).exception();
RETURN_RESULT_OR_FAILURE(
isolate, StoreToSuper(isolate, home_object_proto, receiver, &lookup_key,
value, StoreOrigin::kMaybeKeyed));
}
}
}