AbstractOperations.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /*
  2. * Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/Function.h>
  8. #include <AK/Optional.h>
  9. #include <AK/Result.h>
  10. #include <AK/TemporaryChange.h>
  11. #include <LibJS/Interpreter.h>
  12. #include <LibJS/Parser.h>
  13. #include <LibJS/Runtime/AbstractOperations.h>
  14. #include <LibJS/Runtime/Accessor.h>
  15. #include <LibJS/Runtime/ArgumentsObject.h>
  16. #include <LibJS/Runtime/Array.h>
  17. #include <LibJS/Runtime/BoundFunction.h>
  18. #include <LibJS/Runtime/DeclarativeEnvironment.h>
  19. #include <LibJS/Runtime/ErrorTypes.h>
  20. #include <LibJS/Runtime/FunctionEnvironment.h>
  21. #include <LibJS/Runtime/FunctionObject.h>
  22. #include <LibJS/Runtime/GlobalEnvironment.h>
  23. #include <LibJS/Runtime/GlobalObject.h>
  24. #include <LibJS/Runtime/Object.h>
  25. #include <LibJS/Runtime/ObjectEnvironment.h>
  26. #include <LibJS/Runtime/PropertyDescriptor.h>
  27. #include <LibJS/Runtime/PropertyName.h>
  28. #include <LibJS/Runtime/ProxyObject.h>
  29. #include <LibJS/Runtime/Reference.h>
  30. namespace JS {
  31. // Used in various abstract operations to make it obvious when a non-optional return value must be discarded.
  32. static constexpr double INVALID { 0 };
  33. // 7.2.1 RequireObjectCoercible ( argument ), https://tc39.es/ecma262/#sec-requireobjectcoercible
  34. Value require_object_coercible(GlobalObject& global_object, Value value)
  35. {
  36. auto& vm = global_object.vm();
  37. if (value.is_nullish()) {
  38. vm.throw_exception<TypeError>(global_object, ErrorType::NotObjectCoercible, value.to_string_without_side_effects());
  39. return {};
  40. }
  41. return value;
  42. }
  43. // 7.3.18 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike
  44. size_t length_of_array_like(GlobalObject& global_object, Object const& object)
  45. {
  46. auto& vm = global_object.vm();
  47. auto result = object.get(vm.names.length);
  48. if (vm.exception())
  49. return INVALID;
  50. return result.to_length(global_object);
  51. }
  52. // 7.3.19 CreateListFromArrayLike ( obj [ , elementTypes ] ), https://tc39.es/ecma262/#sec-createlistfromarraylike
  53. MarkedValueList create_list_from_array_like(GlobalObject& global_object, Value value, Function<Result<void, ErrorType>(Value)> check_value)
  54. {
  55. auto& vm = global_object.vm();
  56. auto& heap = global_object.heap();
  57. if (!value.is_object()) {
  58. vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects());
  59. return MarkedValueList { heap };
  60. }
  61. auto& array_like = value.as_object();
  62. auto length = length_of_array_like(global_object, array_like);
  63. if (vm.exception())
  64. return MarkedValueList { heap };
  65. auto list = MarkedValueList { heap };
  66. for (size_t i = 0; i < length; ++i) {
  67. auto index_name = String::number(i);
  68. auto next = array_like.get(index_name);
  69. if (vm.exception())
  70. return MarkedValueList { heap };
  71. if (check_value) {
  72. auto result = check_value(next);
  73. if (result.is_error()) {
  74. vm.throw_exception<TypeError>(global_object, result.release_error());
  75. return MarkedValueList { heap };
  76. }
  77. }
  78. list.append(next);
  79. }
  80. return list;
  81. }
  82. // 7.3.22 SpeciesConstructor ( O, defaultConstructor ), https://tc39.es/ecma262/#sec-speciesconstructor
  83. FunctionObject* species_constructor(GlobalObject& global_object, Object const& object, FunctionObject& default_constructor)
  84. {
  85. auto& vm = global_object.vm();
  86. auto constructor = object.get(vm.names.constructor);
  87. if (vm.exception())
  88. return nullptr;
  89. if (constructor.is_undefined())
  90. return &default_constructor;
  91. if (!constructor.is_object()) {
  92. vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, constructor.to_string_without_side_effects());
  93. return nullptr;
  94. }
  95. auto species = constructor.as_object().get(*vm.well_known_symbol_species());
  96. if (species.is_nullish())
  97. return &default_constructor;
  98. if (species.is_constructor())
  99. return &species.as_function();
  100. vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, species.to_string_without_side_effects());
  101. return nullptr;
  102. }
  103. // 7.3.24 GetFunctionRealm ( obj ), https://tc39.es/ecma262/#sec-getfunctionrealm
  104. GlobalObject* get_function_realm(GlobalObject& global_object, FunctionObject const& function)
  105. {
  106. auto& vm = global_object.vm();
  107. // 1. Assert: ! IsCallable(obj) is true.
  108. // 2. If obj has a [[Realm]] internal slot, then
  109. if (function.realm()) {
  110. // a. Return obj.[[Realm]].
  111. return function.realm();
  112. }
  113. // 3. If obj is a bound function exotic object, then
  114. if (is<BoundFunction>(function)) {
  115. auto& bound_function = static_cast<BoundFunction const&>(function);
  116. // a. Let target be obj.[[BoundTargetFunction]].
  117. auto& target = bound_function.target_function();
  118. // b. Return ? GetFunctionRealm(target).
  119. return get_function_realm(global_object, target);
  120. }
  121. // 4. If obj is a Proxy exotic object, then
  122. if (is<ProxyObject>(function)) {
  123. auto& proxy = static_cast<ProxyObject const&>(function);
  124. // a. If obj.[[ProxyHandler]] is null, throw a TypeError exception.
  125. if (proxy.is_revoked()) {
  126. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  127. return nullptr;
  128. }
  129. // b. Let proxyTarget be obj.[[ProxyTarget]].
  130. auto& proxy_target = proxy.target();
  131. // c. Return ? GetFunctionRealm(proxyTarget).
  132. VERIFY(proxy_target.is_function());
  133. return get_function_realm(global_object, static_cast<FunctionObject const&>(proxy_target));
  134. }
  135. // 5. Return the current Realm Record.
  136. return &global_object;
  137. }
  138. // 10.1.6.2 IsCompatiblePropertyDescriptor ( Extensible, Desc, Current ), https://tc39.es/ecma262/#sec-iscompatiblepropertydescriptor
  139. bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor const& descriptor, Optional<PropertyDescriptor> const& current)
  140. {
  141. // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, Extensible, Desc, Current).
  142. return validate_and_apply_property_descriptor(nullptr, {}, extensible, descriptor, current);
  143. }
  144. // 10.1.6.3 ValidateAndApplyPropertyDescriptor ( O, P, extensible, Desc, current ),
  145. bool validate_and_apply_property_descriptor(Object* object, PropertyName const& property_name, bool extensible, PropertyDescriptor const& descriptor, Optional<PropertyDescriptor> const& current)
  146. {
  147. // 1. Assert: If O is not undefined, then IsPropertyKey(P) is true.
  148. if (object)
  149. VERIFY(property_name.is_valid());
  150. // 2. If current is undefined, then
  151. if (!current.has_value()) {
  152. // a. If extensible is false, return false.
  153. if (!extensible)
  154. return false;
  155. // b. Assert: extensible is true.
  156. // c. If IsGenericDescriptor(Desc) is true or IsDataDescriptor(Desc) is true, then
  157. if (descriptor.is_generic_descriptor() || descriptor.is_data_descriptor()) {
  158. // i. If O is not undefined, create an own data property named P of object O whose [[Value]], [[Writable]],
  159. // [[Enumerable]], and [[Configurable]] attribute values are described by Desc.
  160. // If the value of an attribute field of Desc is absent, the attribute of the newly created property is set
  161. // to its default value.
  162. if (object) {
  163. auto value = descriptor.value.value_or(js_undefined());
  164. object->storage_set(property_name, { value, descriptor.attributes() });
  165. }
  166. }
  167. // d. Else,
  168. else {
  169. // i. Assert: ! IsAccessorDescriptor(Desc) is true.
  170. VERIFY(descriptor.is_accessor_descriptor());
  171. // ii. If O is not undefined, create an own accessor property named P of object O whose [[Get]], [[Set]],
  172. // [[Enumerable]], and [[Configurable]] attribute values are described by Desc.
  173. // If the value of an attribute field of Desc is absent, the attribute of the newly created property is set
  174. // to its default value.
  175. if (object) {
  176. auto accessor = Accessor::create(object->vm(), descriptor.get.value_or(nullptr), descriptor.set.value_or(nullptr));
  177. object->storage_set(property_name, { accessor, descriptor.attributes() });
  178. }
  179. }
  180. // e. Return true.
  181. return true;
  182. }
  183. // 3. If every field in Desc is absent, return true.
  184. if (descriptor.is_empty())
  185. return true;
  186. // 4. If current.[[Configurable]] is false, then
  187. if (!*current->configurable) {
  188. // a. If Desc.[[Configurable]] is present and its value is true, return false.
  189. if (descriptor.configurable.has_value() && *descriptor.configurable)
  190. return false;
  191. // b. If Desc.[[Enumerable]] is present and ! SameValue(Desc.[[Enumerable]], current.[[Enumerable]]) is false, return false.
  192. if (descriptor.enumerable.has_value() && *descriptor.enumerable != *current->enumerable)
  193. return false;
  194. }
  195. // 5. If ! IsGenericDescriptor(Desc) is true, then
  196. if (descriptor.is_generic_descriptor()) {
  197. // a. NOTE: No further validation is required.
  198. }
  199. // 6. Else if ! SameValue(! IsDataDescriptor(current), ! IsDataDescriptor(Desc)) is false, then
  200. else if (current->is_data_descriptor() != descriptor.is_data_descriptor()) {
  201. // a. If current.[[Configurable]] is false, return false.
  202. if (!*current->configurable)
  203. return false;
  204. // b. If IsDataDescriptor(current) is true, then
  205. if (current->is_data_descriptor()) {
  206. // If O is not undefined, convert the property named P of object O from a data property to an accessor property.
  207. // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]] attributes and
  208. // set the rest of the property's attributes to their default values.
  209. if (object) {
  210. auto accessor = Accessor::create(object->vm(), nullptr, nullptr);
  211. object->storage_set(property_name, { accessor, current->attributes() });
  212. }
  213. }
  214. // c. Else,
  215. else {
  216. // If O is not undefined, convert the property named P of object O from an accessor property to a data property.
  217. // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]] attributes and
  218. // set the rest of the property's attributes to their default values.
  219. if (object) {
  220. auto value = js_undefined();
  221. object->storage_set(property_name, { value, current->attributes() });
  222. }
  223. }
  224. }
  225. // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
  226. else if (current->is_data_descriptor() && descriptor.is_data_descriptor()) {
  227. // a. If current.[[Configurable]] is false and current.[[Writable]] is false, then
  228. if (!*current->configurable && !*current->writable) {
  229. // i. If Desc.[[Writable]] is present and Desc.[[Writable]] is true, return false.
  230. if (descriptor.writable.has_value() && *descriptor.writable)
  231. return false;
  232. // ii. If Desc.[[Value]] is present and SameValue(Desc.[[Value]], current.[[Value]]) is false, return false.
  233. if (descriptor.value.has_value() && !same_value(*descriptor.value, *current->value))
  234. return false;
  235. // iii. Return true.
  236. return true;
  237. }
  238. }
  239. // 8. Else,
  240. else {
  241. // a. Assert: ! IsAccessorDescriptor(current) and ! IsAccessorDescriptor(Desc) are both true.
  242. VERIFY(current->is_accessor_descriptor());
  243. VERIFY(descriptor.is_accessor_descriptor());
  244. // b. If current.[[Configurable]] is false, then
  245. if (!*current->configurable) {
  246. // i. If Desc.[[Set]] is present and SameValue(Desc.[[Set]], current.[[Set]]) is false, return false.
  247. if (descriptor.set.has_value() && *descriptor.set != *current->set)
  248. return false;
  249. // ii. If Desc.[[Get]] is present and SameValue(Desc.[[Get]], current.[[Get]]) is false, return false.
  250. if (descriptor.get.has_value() && *descriptor.get != *current->get)
  251. return false;
  252. // iii. Return true.
  253. return true;
  254. }
  255. }
  256. // 9. If O is not undefined, then
  257. if (object) {
  258. // a. For each field of Desc that is present, set the corresponding attribute of the property named P of object O to the value of the field.
  259. Value value;
  260. if (descriptor.is_accessor_descriptor() || (current->is_accessor_descriptor() && !descriptor.is_data_descriptor())) {
  261. auto* getter = descriptor.get.value_or(current->get.value_or(nullptr));
  262. auto* setter = descriptor.set.value_or(current->set.value_or(nullptr));
  263. value = Accessor::create(object->vm(), getter, setter);
  264. } else {
  265. value = descriptor.value.value_or(current->value.value_or({}));
  266. }
  267. PropertyAttributes attributes;
  268. attributes.set_writable(descriptor.writable.value_or(current->writable.value_or(false)));
  269. attributes.set_enumerable(descriptor.enumerable.value_or(current->enumerable.value_or(false)));
  270. attributes.set_configurable(descriptor.configurable.value_or(current->configurable.value_or(false)));
  271. object->storage_set(property_name, { value, attributes });
  272. }
  273. // 10. Return true.
  274. return true;
  275. }
  276. // 10.1.14 GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto )
  277. Object* get_prototype_from_constructor(GlobalObject& global_object, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)())
  278. {
  279. auto& vm = global_object.vm();
  280. auto prototype = constructor.get(vm.names.prototype);
  281. if (vm.exception())
  282. return nullptr;
  283. if (!prototype.is_object()) {
  284. auto* realm = get_function_realm(global_object, constructor);
  285. if (vm.exception())
  286. return nullptr;
  287. prototype = (realm->*intrinsic_default_prototype)();
  288. }
  289. return &prototype.as_object();
  290. }
  291. // 9.1.2.2 NewDeclarativeEnvironment ( E ), https://tc39.es/ecma262/#sec-newdeclarativeenvironment
  292. DeclarativeEnvironment* new_declarative_environment(Environment& environment)
  293. {
  294. auto& global_object = environment.global_object();
  295. return global_object.heap().allocate<DeclarativeEnvironment>(global_object, &environment);
  296. }
  297. // 9.1.2.3 NewObjectEnvironment ( O, W, E ), https://tc39.es/ecma262/#sec-newobjectenvironment
  298. ObjectEnvironment* new_object_environment(Object& object, bool is_with_environment, Environment* environment)
  299. {
  300. auto& global_object = object.global_object();
  301. return global_object.heap().allocate<ObjectEnvironment>(global_object, object, is_with_environment ? ObjectEnvironment::IsWithEnvironment::Yes : ObjectEnvironment::IsWithEnvironment::No, environment);
  302. }
  303. // 9.4.3 GetThisEnvironment ( ), https://tc39.es/ecma262/#sec-getthisenvironment
  304. Environment& get_this_environment(VM& vm)
  305. {
  306. for (auto* env = vm.lexical_environment(); env; env = env->outer_environment()) {
  307. if (env->has_this_binding())
  308. return *env;
  309. }
  310. VERIFY_NOT_REACHED();
  311. }
  312. // 13.3.7.2 GetSuperConstructor ( ), https://tc39.es/ecma262/#sec-getsuperconstructor
  313. Object* get_super_constructor(VM& vm)
  314. {
  315. auto& env = get_this_environment(vm);
  316. auto& active_function = verify_cast<FunctionEnvironment>(env).function_object();
  317. auto* super_constructor = active_function.internal_get_prototype_of();
  318. return super_constructor;
  319. }
  320. // 13.3.7.3 MakeSuperPropertyReference ( actualThis, propertyKey, strict )
  321. Reference make_super_property_reference(GlobalObject& global_object, Value actual_this, StringOrSymbol const& property_key, bool strict)
  322. {
  323. auto& vm = global_object.vm();
  324. // 1. Let env be GetThisEnvironment().
  325. auto& env = verify_cast<FunctionEnvironment>(get_this_environment(vm));
  326. // 2. Assert: env.HasSuperBinding() is true.
  327. VERIFY(env.has_super_binding());
  328. // 3. Let baseValue be ? env.GetSuperBase().
  329. auto base_value = env.get_super_base();
  330. // 4. Let bv be ? RequireObjectCoercible(baseValue).
  331. auto bv = require_object_coercible(global_object, base_value);
  332. if (vm.exception())
  333. return {};
  334. // 5. Return the Reference Record { [[Base]]: bv, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
  335. // 6. NOTE: This returns a Super Reference Record.
  336. return Reference { bv, property_key, actual_this, strict };
  337. }
  338. // 19.2.1.1 PerformEval ( x, callerRealm, strictCaller, direct ), https://tc39.es/ecma262/#sec-performeval
  339. Value perform_eval(Value x, GlobalObject& caller_realm, CallerMode strict_caller, EvalMode direct)
  340. {
  341. VERIFY(direct == EvalMode::Direct || strict_caller == CallerMode::NonStrict);
  342. if (!x.is_string())
  343. return x;
  344. auto& vm = caller_realm.vm();
  345. auto& code_string = x.as_string();
  346. Parser parser { Lexer { code_string.string() } };
  347. auto program = parser.parse_program(strict_caller == CallerMode::Strict);
  348. if (parser.has_errors()) {
  349. auto& error = parser.errors()[0];
  350. vm.throw_exception<SyntaxError>(caller_realm, error.to_string());
  351. return {};
  352. }
  353. auto& interpreter = vm.interpreter();
  354. if (direct == EvalMode::Direct)
  355. return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
  356. TemporaryChange scope_change(vm.running_execution_context().lexical_environment, static_cast<Environment*>(&caller_realm.environment()));
  357. return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
  358. }
  359. // 10.4.4.6 CreateUnmappedArgumentsObject ( argumentsList ), https://tc39.es/ecma262/#sec-createunmappedargumentsobject
  360. Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector<Value> const& arguments)
  361. {
  362. auto& vm = global_object.vm();
  363. // 1. Let len be the number of elements in argumentsList.
  364. auto length = arguments.size();
  365. // 2. Let obj be ! OrdinaryObjectCreate(%Object.prototype%, « [[ParameterMap]] »).
  366. // 3. Set obj.[[ParameterMap]] to undefined.
  367. auto* object = Object::create(global_object, global_object.object_prototype());
  368. // 4. Perform DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  369. object->define_property_or_throw(vm.names.length, { .value = Value(length), .writable = true, .enumerable = false, .configurable = true });
  370. VERIFY(!vm.exception());
  371. // 5. Let index be 0.
  372. // 6. Repeat, while index < len,
  373. for (size_t index = 0; index < length; ++index) {
  374. // a. Let val be argumentsList[index].
  375. auto value = arguments[index];
  376. // b. Perform ! CreateDataPropertyOrThrow(obj, ! ToString(𝔽(index)), val).
  377. object->create_data_property_or_throw(index, value);
  378. VERIFY(!vm.exception());
  379. // c. Set index to index + 1.
  380. }
  381. // 7. Perform ! DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor { [[Value]]: %Array.prototype.values%, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  382. // FIXME: This is not guaranteed to be %Array.prototype.values%!
  383. auto array_prototype_values = global_object.array_prototype()->get(vm.names.values);
  384. if (vm.exception())
  385. return {};
  386. object->define_property_or_throw(*vm.well_known_symbol_iterator(), { .value = array_prototype_values, .writable = true, .enumerable = false, .configurable = true });
  387. VERIFY(!vm.exception());
  388. // 8. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { [[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false }).
  389. auto* throw_type_error = global_object.throw_type_error_function();
  390. object->define_property_or_throw(vm.names.callee, { .get = throw_type_error, .set = throw_type_error, .enumerable = false, .configurable = false });
  391. VERIFY(!vm.exception());
  392. // 9. Return obj.
  393. return object;
  394. }
  395. // 10.4.4.7 CreateMappedArgumentsObject ( func, formals, argumentsList, env ), https://tc39.es/ecma262/#sec-createmappedargumentsobject
  396. Object* create_mapped_arguments_object(GlobalObject& global_object, FunctionObject& function, Vector<FunctionNode::Parameter> const& formals, Vector<Value> const& arguments, Environment&)
  397. {
  398. // FIXME: This implementation is incomplete and doesn't support the actual identifier mappings yet.
  399. (void)formals;
  400. auto& vm = global_object.vm();
  401. // 1. Assert: formals does not contain a rest parameter, any binding patterns, or any initializers. It may contain duplicate identifiers.
  402. // 2. Let len be the number of elements in argumentsList.
  403. auto length = arguments.size();
  404. // 3. Let obj be ! MakeBasicObject(« [[Prototype]], [[Extensible]], [[ParameterMap]] »).
  405. auto* object = vm.heap().allocate<ArgumentsObject>(global_object, global_object);
  406. VERIFY(!vm.exception());
  407. // 4. Set obj.[[GetOwnProperty]] as specified in 10.4.4.1.
  408. // 5. Set obj.[[DefineOwnProperty]] as specified in 10.4.4.2.
  409. // 6. Set obj.[[Get]] as specified in 10.4.4.3.
  410. // 7. Set obj.[[Set]] as specified in 10.4.4.4.
  411. // 8. Set obj.[[Delete]] as specified in 10.4.4.5.
  412. // 9. Set obj.[[Prototype]] to %Object.prototype%.
  413. // 14. Let index be 0.
  414. // 15. Repeat, while index < len,
  415. for (size_t index = 0; index < length; ++index) {
  416. // a. Let val be argumentsList[index].
  417. auto value = arguments[index];
  418. // b. Perform ! CreateDataPropertyOrThrow(obj, ! ToString(𝔽(index)), val).
  419. object->create_data_property_or_throw(index, value);
  420. VERIFY(!vm.exception());
  421. // c. Set index to index + 1.
  422. }
  423. // 16. Perform ! DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  424. object->define_property_or_throw(vm.names.length, { .value = Value(length), .writable = true, .enumerable = false, .configurable = true });
  425. VERIFY(!vm.exception());
  426. // 20. Perform ! DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor { [[Value]]: %Array.prototype.values%, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  427. // FIXME: This is not guaranteed to be %Array.prototype.values%!
  428. auto array_prototype_values = global_object.array_prototype()->get(vm.names.values);
  429. if (vm.exception())
  430. return {};
  431. object->define_property_or_throw(*vm.well_known_symbol_iterator(), { .value = array_prototype_values, .writable = true, .enumerable = false, .configurable = true });
  432. VERIFY(!vm.exception());
  433. // 21. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { [[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  434. object->define_property_or_throw(vm.names.callee, { .value = &function, .writable = true, .enumerable = false, .configurable = true });
  435. VERIFY(!vm.exception());
  436. // 22. Return obj.
  437. return object;
  438. }
  439. // 7.1.21 CanonicalNumericIndexString ( argument ), https://tc39.es/ecma262/#sec-canonicalnumericindexstring
  440. Value canonical_numeric_index_string(GlobalObject& global_object, Value argument)
  441. {
  442. // 1. Assert: Type(argument) is String.
  443. VERIFY(argument.is_string());
  444. // 2. If argument is "-0", return -0𝔽.
  445. if (argument.as_string().string() == "-0")
  446. return Value(-0.0);
  447. // 3. Let n be ! ToNumber(argument).
  448. auto n = argument.to_number(global_object);
  449. // 4. If SameValue(! ToString(n), argument) is false, return undefined.
  450. if (!same_value(n.to_primitive_string(global_object), argument))
  451. return js_undefined();
  452. // 5. Return n.
  453. return n;
  454. }
  455. }