AbstractOperations.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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/Result.h>
  9. #include <AK/TemporaryChange.h>
  10. #include <LibJS/Interpreter.h>
  11. #include <LibJS/Parser.h>
  12. #include <LibJS/Runtime/AbstractOperations.h>
  13. #include <LibJS/Runtime/ArgumentsObject.h>
  14. #include <LibJS/Runtime/Array.h>
  15. #include <LibJS/Runtime/ArrayPrototype.h>
  16. #include <LibJS/Runtime/BoundFunction.h>
  17. #include <LibJS/Runtime/DeclarativeEnvironmentRecord.h>
  18. #include <LibJS/Runtime/ErrorTypes.h>
  19. #include <LibJS/Runtime/FunctionEnvironmentRecord.h>
  20. #include <LibJS/Runtime/FunctionObject.h>
  21. #include <LibJS/Runtime/GlobalEnvironmentRecord.h>
  22. #include <LibJS/Runtime/GlobalObject.h>
  23. #include <LibJS/Runtime/Object.h>
  24. #include <LibJS/Runtime/ObjectEnvironmentRecord.h>
  25. #include <LibJS/Runtime/PropertyName.h>
  26. #include <LibJS/Runtime/ProxyObject.h>
  27. namespace JS {
  28. // Used in various abstract operations to make it obvious when a non-optional return value must be discarded.
  29. static constexpr double INVALID { 0 };
  30. // 7.2.1 RequireObjectCoercible ( argument ), https://tc39.es/ecma262/#sec-requireobjectcoercible
  31. Value require_object_coercible(GlobalObject& global_object, Value value)
  32. {
  33. auto& vm = global_object.vm();
  34. if (value.is_nullish()) {
  35. vm.throw_exception<TypeError>(global_object, ErrorType::NotObjectCoercible, value.to_string_without_side_effects());
  36. return {};
  37. }
  38. return value;
  39. }
  40. // 7.3.18 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike
  41. size_t length_of_array_like(GlobalObject& global_object, Object const& object)
  42. {
  43. auto& vm = global_object.vm();
  44. auto result = object.get(vm.names.length).value_or(js_undefined());
  45. if (vm.exception())
  46. return INVALID;
  47. return result.to_length(global_object);
  48. }
  49. // 7.3.19 CreateListFromArrayLike ( obj [ , elementTypes ] ), https://tc39.es/ecma262/#sec-createlistfromarraylike
  50. MarkedValueList create_list_from_array_like(GlobalObject& global_object, Value value, Function<Result<void, ErrorType>(Value)> check_value)
  51. {
  52. auto& vm = global_object.vm();
  53. auto& heap = global_object.heap();
  54. if (!value.is_object()) {
  55. vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects());
  56. return MarkedValueList { heap };
  57. }
  58. auto& array_like = value.as_object();
  59. auto length = length_of_array_like(global_object, array_like);
  60. if (vm.exception())
  61. return MarkedValueList { heap };
  62. auto list = MarkedValueList { heap };
  63. for (size_t i = 0; i < length; ++i) {
  64. auto index_name = String::number(i);
  65. auto next = array_like.get(index_name).value_or(js_undefined());
  66. if (vm.exception())
  67. return MarkedValueList { heap };
  68. if (check_value) {
  69. auto result = check_value(next);
  70. if (result.is_error()) {
  71. vm.throw_exception<TypeError>(global_object, result.release_error());
  72. return MarkedValueList { heap };
  73. }
  74. }
  75. list.append(next);
  76. }
  77. return list;
  78. }
  79. // 7.3.22 SpeciesConstructor ( O, defaultConstructor ), https://tc39.es/ecma262/#sec-speciesconstructor
  80. FunctionObject* species_constructor(GlobalObject& global_object, Object const& object, FunctionObject& default_constructor)
  81. {
  82. auto& vm = global_object.vm();
  83. auto constructor = object.get(vm.names.constructor).value_or(js_undefined());
  84. if (vm.exception())
  85. return nullptr;
  86. if (constructor.is_undefined())
  87. return &default_constructor;
  88. if (!constructor.is_object()) {
  89. vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, constructor.to_string_without_side_effects());
  90. return nullptr;
  91. }
  92. auto species = constructor.as_object().get(*vm.well_known_symbol_species()).value_or(js_undefined());
  93. if (species.is_nullish())
  94. return &default_constructor;
  95. if (species.is_constructor())
  96. return &species.as_function();
  97. vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, species.to_string_without_side_effects());
  98. return nullptr;
  99. }
  100. // 7.3.24 GetFunctionRealm ( obj ), https://tc39.es/ecma262/#sec-getfunctionrealm
  101. GlobalObject* get_function_realm(GlobalObject& global_object, FunctionObject const& function)
  102. {
  103. auto& vm = global_object.vm();
  104. // FIXME: not sure how to do this currently.
  105. // 2. If obj has a [[Realm]] internal slot, then
  106. // a. Return obj.[[Realm]].
  107. if (is<BoundFunction>(function)) {
  108. auto& bound_function = static_cast<BoundFunction const&>(function);
  109. auto& target = bound_function.target_function();
  110. return get_function_realm(global_object, target);
  111. }
  112. if (is<ProxyObject>(function)) {
  113. auto& proxy = static_cast<ProxyObject const&>(function);
  114. if (proxy.is_revoked()) {
  115. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  116. return nullptr;
  117. }
  118. auto& proxy_target = proxy.target();
  119. VERIFY(proxy_target.is_function());
  120. return get_function_realm(global_object, static_cast<FunctionObject const&>(proxy_target));
  121. }
  122. // 5. Return the current Realm Record.
  123. return &global_object;
  124. }
  125. // 10.1.14 GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto )
  126. Object* get_prototype_from_constructor(GlobalObject& global_object, FunctionObject const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)())
  127. {
  128. auto& vm = global_object.vm();
  129. auto prototype = constructor.get(vm.names.prototype);
  130. if (vm.exception())
  131. return nullptr;
  132. if (!prototype.is_object()) {
  133. auto* realm = get_function_realm(global_object, constructor);
  134. if (vm.exception())
  135. return nullptr;
  136. prototype = (realm->*intrinsic_default_prototype)();
  137. }
  138. return &prototype.as_object();
  139. }
  140. // 9.1.2.2 NewDeclarativeEnvironment ( E ), https://tc39.es/ecma262/#sec-newdeclarativeenvironment
  141. DeclarativeEnvironmentRecord* new_declarative_environment(EnvironmentRecord& environment_record)
  142. {
  143. auto& global_object = environment_record.global_object();
  144. return global_object.heap().allocate<DeclarativeEnvironmentRecord>(global_object, &environment_record);
  145. }
  146. // 9.1.2.3 NewObjectEnvironment ( O, W, E ), https://tc39.es/ecma262/#sec-newobjectenvironment
  147. ObjectEnvironmentRecord* new_object_environment(Object& object, bool is_with_environment, EnvironmentRecord* environment_record)
  148. {
  149. auto& global_object = object.global_object();
  150. return global_object.heap().allocate<ObjectEnvironmentRecord>(global_object, object, is_with_environment ? ObjectEnvironmentRecord::IsWithEnvironment::Yes : ObjectEnvironmentRecord::IsWithEnvironment::No, environment_record);
  151. }
  152. // 9.4.3 GetThisEnvironment ( ), https://tc39.es/ecma262/#sec-getthisenvironment
  153. EnvironmentRecord& get_this_environment(VM& vm)
  154. {
  155. for (auto* env = vm.lexical_environment(); env; env = env->outer_environment()) {
  156. if (env->has_this_binding())
  157. return *env;
  158. }
  159. VERIFY_NOT_REACHED();
  160. }
  161. // 13.3.7.2 GetSuperConstructor ( ), https://tc39.es/ecma262/#sec-getsuperconstructor
  162. Object* get_super_constructor(VM& vm)
  163. {
  164. auto& env = get_this_environment(vm);
  165. auto& active_function = verify_cast<FunctionEnvironmentRecord>(env).function_object();
  166. auto* super_constructor = active_function.prototype();
  167. return super_constructor;
  168. }
  169. // 19.2.1.1 PerformEval ( x, callerRealm, strictCaller, direct ), https://tc39.es/ecma262/#sec-performeval
  170. Value perform_eval(Value x, GlobalObject& caller_realm, CallerMode strict_caller, EvalMode direct)
  171. {
  172. VERIFY(direct == EvalMode::Direct || strict_caller == CallerMode::NonStrict);
  173. if (!x.is_string())
  174. return x;
  175. auto& vm = caller_realm.vm();
  176. auto& code_string = x.as_string();
  177. Parser parser { Lexer { code_string.string() } };
  178. auto program = parser.parse_program(strict_caller == CallerMode::Strict);
  179. if (parser.has_errors()) {
  180. auto& error = parser.errors()[0];
  181. vm.throw_exception<SyntaxError>(caller_realm, error.to_string());
  182. return {};
  183. }
  184. auto& interpreter = vm.interpreter();
  185. if (direct == EvalMode::Direct)
  186. return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
  187. TemporaryChange scope_change(vm.running_execution_context().lexical_environment, static_cast<EnvironmentRecord*>(&caller_realm.environment_record()));
  188. return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
  189. }
  190. // 10.4.4.6 CreateUnmappedArgumentsObject ( argumentsList ), https://tc39.es/ecma262/#sec-createunmappedargumentsobject
  191. Object* create_unmapped_arguments_object(GlobalObject& global_object, Vector<Value> const& arguments)
  192. {
  193. auto& vm = global_object.vm();
  194. auto* object = Object::create(global_object, global_object.object_prototype());
  195. if (vm.exception())
  196. return nullptr;
  197. for (auto& argument : arguments)
  198. object->indexed_properties().append(argument);
  199. // 4. Perform DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  200. auto length = arguments.size();
  201. object->define_property(vm.names.length, Value(length), Attribute::Writable | Attribute::Configurable);
  202. if (vm.exception())
  203. return nullptr;
  204. object->define_property(*vm.well_known_symbol_iterator(), global_object.array_prototype()->get(vm.names.values), Attribute::Writable | Attribute::Configurable);
  205. // 8. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { [[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false }).
  206. object->define_accessor(vm.names.callee, global_object.throw_type_error_function(), global_object.throw_type_error_function(), 0);
  207. if (vm.exception())
  208. return nullptr;
  209. return object;
  210. }
  211. // 10.4.4.7 CreateMappedArgumentsObject ( func, formals, argumentsList, env ), https://tc39.es/ecma262/#sec-createmappedargumentsobject
  212. Object* create_mapped_arguments_object(GlobalObject& global_object, FunctionObject& function, Vector<FunctionNode::Parameter> const& formals, Vector<Value> const& arguments, EnvironmentRecord&)
  213. {
  214. // FIXME: This implementation is incomplete and doesn't support the actual identifier mappings yet.
  215. (void)formals;
  216. auto& vm = global_object.vm();
  217. auto* object = vm.heap().allocate<ArgumentsObject>(global_object, global_object);
  218. if (vm.exception())
  219. return nullptr;
  220. // 14. Let index be 0.
  221. // 15. Repeat, while index < len,
  222. // a. Let val be argumentsList[index].
  223. // b . Perform ! CreateDataPropertyOrThrow(obj, ! ToString(𝔽(index)), val).
  224. // c. Set index to index + 1.
  225. for (auto& argument : arguments)
  226. object->indexed_properties().append(argument);
  227. // 16. Perform ! DefinePropertyOrThrow(obj, "length", PropertyDescriptor { [[Value]]: 𝔽(len), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  228. auto length = arguments.size();
  229. object->define_property(vm.names.length, Value(length), Attribute::Writable | Attribute::Configurable);
  230. if (vm.exception())
  231. return nullptr;
  232. // 20. Perform ! DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor { [[Value]]: %Array.prototype.values%, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  233. object->define_property(*vm.well_known_symbol_iterator(), global_object.array_prototype()->get(vm.names.values), Attribute::Writable | Attribute::Configurable);
  234. // 21. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { [[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }).
  235. object->define_property(vm.names.callee, Value(&function), Attribute::Writable | Attribute::Configurable);
  236. if (vm.exception())
  237. return nullptr;
  238. return object;
  239. }
  240. }