| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 21:29:22 +01:00
										 |  |  | #include <AK/Badge.h>
 | 
					
						
							| 
									
										
										
										
											2020-05-04 12:34:49 +02:00
										 |  |  | #include <AK/StringBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | #include <LibJS/AST.h>
 | 
					
						
							|  |  |  | #include <LibJS/Interpreter.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-24 14:37:39 +01:00
										 |  |  | #include <LibJS/Runtime/Error.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 14:20:30 +01:00
										 |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-15 21:58:22 +02:00
										 |  |  | #include <LibJS/Runtime/LexicalEnvironment.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-19 17:24:56 +02:00
										 |  |  | #include <LibJS/Runtime/MarkedValueList.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 14:20:30 +01:00
										 |  |  | #include <LibJS/Runtime/NativeFunction.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Object.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-27 12:37:27 +02:00
										 |  |  | #include <LibJS/Runtime/Reference.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-04 14:48:36 +02:00
										 |  |  | #include <LibJS/Runtime/ScriptFunction.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-02 19:32:21 +02:00
										 |  |  | #include <LibJS/Runtime/Shape.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-29 23:25:21 -07:00
										 |  |  | #include <LibJS/Runtime/SymbolObject.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 14:20:30 +01:00
										 |  |  | #include <LibJS/Runtime/Value.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 18:01:09 -07:00
										 |  |  | //#define INTERPRETER_DEBUG
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | namespace JS { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Interpreter::Interpreter() | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  |     : m_heap(*this) | 
					
						
							| 
									
										
										
										
											2020-05-01 14:40:43 +02:00
										 |  |  |     , m_console(*this) | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-09 15:34:20 -07:00
										 |  |  | #define __JS_ENUMERATE(SymbolName, snake_name) \
 | 
					
						
							|  |  |  |     m_well_known_symbol_##snake_name = js_symbol(*this, "Symbol." #SymbolName, false); | 
					
						
							|  |  |  |     JS_ENUMERATE_WELL_KNOWN_SYMBOLS | 
					
						
							|  |  |  | #undef __JS_ENUMERATE
 | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Interpreter::~Interpreter() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-11 22:47:43 +01:00
										 |  |  | Value Interpreter::run(GlobalObject& global_object, const Program& program) | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-08-11 17:45:57 +02:00
										 |  |  |     ASSERT(!exception()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-11 22:47:43 +01:00
										 |  |  |     if (m_call_stack.is_empty()) { | 
					
						
							|  |  |  |         CallFrame global_call_frame; | 
					
						
							|  |  |  |         global_call_frame.this_value = &global_object; | 
					
						
							|  |  |  |         global_call_frame.function_name = "(global execution context)"; | 
					
						
							|  |  |  |         global_call_frame.environment = heap().allocate<LexicalEnvironment>(global_object, LexicalEnvironment::EnvironmentRecordType::Global); | 
					
						
							|  |  |  |         global_call_frame.environment->bind_this_value(&global_object); | 
					
						
							|  |  |  |         if (exception()) | 
					
						
							|  |  |  |             return {}; | 
					
						
							|  |  |  |         m_call_stack.append(move(global_call_frame)); | 
					
						
							| 
									
										
										
										
											2020-04-15 21:58:22 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-11 22:47:43 +01:00
										 |  |  |     return program.execute(*this, global_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Value Interpreter::execute_statement(GlobalObject& global_object, const Statement& statement, ArgumentVector arguments, ScopeType scope_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-23 16:46:41 +01:00
										 |  |  |     if (!statement.is_scope_node()) | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  |         return statement.execute(*this, global_object); | 
					
						
							| 
									
										
										
										
											2020-03-23 16:46:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 09:53:27 +02:00
										 |  |  |     auto& block = static_cast<const ScopeNode&>(statement); | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  |     enter_scope(block, move(arguments), scope_type, global_object); | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 12:08:35 +01:00
										 |  |  |     if (block.children().is_empty()) | 
					
						
							|  |  |  |         m_last_value = js_undefined(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-23 16:46:41 +01:00
										 |  |  |     for (auto& node : block.children()) { | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  |         m_last_value = node.execute(*this, global_object); | 
					
						
							| 
									
										
										
										
											2020-05-28 13:36:59 -07:00
										 |  |  |         if (should_unwind()) { | 
					
						
							| 
									
										
										
										
											2020-08-28 21:22:22 +04:30
										 |  |  |             if (!block.label().is_null() && should_unwind_until(ScopeType::Breakable, block.label())) | 
					
						
							| 
									
										
										
										
											2020-05-28 13:36:59 -07:00
										 |  |  |                 stop_unwind(); | 
					
						
							| 
									
										
										
										
											2020-03-23 19:19:03 +01:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2020-05-28 13:36:59 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 23:45:13 +02:00
										 |  |  |     bool did_return = m_unwind_until == ScopeType::Function; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-23 19:19:03 +01:00
										 |  |  |     if (m_unwind_until == scope_type) | 
					
						
							|  |  |  |         m_unwind_until = ScopeType::None; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-23 16:46:41 +01:00
										 |  |  |     exit_scope(block); | 
					
						
							| 
									
										
										
										
											2020-04-04 23:45:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return did_return ? m_last_value : js_undefined(); | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  | void Interpreter::enter_scope(const ScopeNode& scope_node, ArgumentVector arguments, ScopeType scope_type, GlobalObject& global_object) | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-04 14:48:36 +02:00
										 |  |  |     for (auto& declaration : scope_node.functions()) { | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  |         auto* function = ScriptFunction::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), current_environment()); | 
					
						
							|  |  |  |         set_variable(declaration.name(), function, global_object); | 
					
						
							| 
									
										
										
										
											2020-06-04 14:48:36 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 21:58:22 +02:00
										 |  |  |     if (scope_type == ScopeType::Function) { | 
					
						
							|  |  |  |         m_scope_stack.append({ scope_type, scope_node, false }); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 11:59:18 +02:00
										 |  |  |     HashMap<FlyString, Variable> scope_variables_with_declaration_kind; | 
					
						
							| 
									
										
										
										
											2020-04-13 17:23:42 +02:00
										 |  |  |     scope_variables_with_declaration_kind.ensure_capacity(16); | 
					
						
							| 
									
										
										
										
											2020-04-13 16:42:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto& declaration : scope_node.variables()) { | 
					
						
							|  |  |  |         for (auto& declarator : declaration.declarations()) { | 
					
						
							| 
									
										
										
										
											2020-06-07 10:53:14 -07:00
										 |  |  |             if (scope_node.is_program()) { | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  |                 global_object.put(declarator.id().string(), js_undefined()); | 
					
						
							| 
									
										
										
										
											2020-06-07 10:53:14 -07:00
										 |  |  |                 if (exception()) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:42:54 +02:00
										 |  |  |                 scope_variables_with_declaration_kind.set(declarator.id().string(), { js_undefined(), declaration.declaration_kind() }); | 
					
						
							| 
									
										
										
										
											2020-06-07 10:53:14 -07:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-04-13 16:42:54 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 19:53:31 +01:00
										 |  |  |     for (auto& argument : arguments) { | 
					
						
							| 
									
										
										
										
											2020-04-08 11:59:18 +02:00
										 |  |  |         scope_variables_with_declaration_kind.set(argument.name, { argument.value, DeclarationKind::Var }); | 
					
						
							| 
									
										
										
										
											2020-03-12 14:24:34 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-13 16:42:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 21:58:22 +02:00
										 |  |  |     bool pushed_lexical_environment = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-16 10:24:45 +02:00
										 |  |  |     if (!scope_variables_with_declaration_kind.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-06-20 15:40:48 +02:00
										 |  |  |         auto* block_lexical_environment = heap().allocate<LexicalEnvironment>(global_object, move(scope_variables_with_declaration_kind), current_environment()); | 
					
						
							| 
									
										
										
										
											2020-04-16 10:24:45 +02:00
										 |  |  |         m_call_stack.last().environment = block_lexical_environment; | 
					
						
							|  |  |  |         pushed_lexical_environment = true; | 
					
						
							| 
									
										
										
										
											2020-04-15 21:58:22 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_scope_stack.append({ scope_type, scope_node, pushed_lexical_environment }); | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Interpreter::exit_scope(const ScopeNode& scope_node) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-27 11:34:58 +01:00
										 |  |  |     while (!m_scope_stack.is_empty()) { | 
					
						
							|  |  |  |         auto popped_scope = m_scope_stack.take_last(); | 
					
						
							| 
									
										
										
										
											2020-04-15 21:58:22 +02:00
										 |  |  |         if (popped_scope.pushed_environment) | 
					
						
							|  |  |  |             m_call_stack.last().environment = m_call_stack.last().environment->parent(); | 
					
						
							| 
									
										
										
										
											2020-03-27 11:34:58 +01:00
										 |  |  |         if (popped_scope.scope_node.ptr() == &scope_node) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-23 19:19:03 +01:00
										 |  |  |     // If we unwind all the way, just reset m_unwind_until so that future "return" doesn't break.
 | 
					
						
							|  |  |  |     if (m_scope_stack.is_empty()) | 
					
						
							|  |  |  |         m_unwind_until = ScopeType::None; | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  | void Interpreter::set_variable(const FlyString& name, Value value, GlobalObject& global_object, bool first_assignment) | 
					
						
							| 
									
										
										
										
											2020-03-09 21:13:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-19 18:42:41 +04:30
										 |  |  |     if (m_call_stack.size()) { | 
					
						
							|  |  |  |         for (auto* environment = current_environment(); environment; environment = environment->parent()) { | 
					
						
							|  |  |  |             auto possible_match = environment->get(name); | 
					
						
							|  |  |  |             if (possible_match.has_value()) { | 
					
						
							|  |  |  |                 if (!first_assignment && possible_match.value().declaration_kind == DeclarationKind::Const) { | 
					
						
							| 
									
										
										
										
											2020-06-09 22:48:01 -07:00
										 |  |  |                     throw_exception<TypeError>(ErrorType::InvalidAssignToConst); | 
					
						
							| 
									
										
										
										
											2020-04-19 18:42:41 +04:30
										 |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 environment->set(name, { value, possible_match.value().declaration_kind }); | 
					
						
							| 
									
										
										
										
											2020-04-12 15:50:49 -07:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-03-09 21:13:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  |     global_object.put(move(name), move(value)); | 
					
						
							| 
									
										
										
										
											2020-03-09 21:13:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  | Value Interpreter::get_variable(const FlyString& name, GlobalObject& global_object) | 
					
						
							| 
									
										
										
										
											2020-03-09 21:13:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-19 18:42:41 +04:30
										 |  |  |     if (m_call_stack.size()) { | 
					
						
							|  |  |  |         for (auto* environment = current_environment(); environment; environment = environment->parent()) { | 
					
						
							|  |  |  |             auto possible_match = environment->get(name); | 
					
						
							|  |  |  |             if (possible_match.has_value()) | 
					
						
							|  |  |  |                 return possible_match.value().value; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-09 21:13:55 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-08 21:25:16 +02:00
										 |  |  |     auto value = global_object.get(name); | 
					
						
							| 
									
										
										
										
											2020-06-08 12:08:35 +01:00
										 |  |  |     if (m_underscore_is_last_value && name == "_" && value.is_empty()) | 
					
						
							|  |  |  |         return m_last_value; | 
					
						
							|  |  |  |     return value; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:13:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-27 12:37:27 +02:00
										 |  |  | Reference Interpreter::get_reference(const FlyString& name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_call_stack.size()) { | 
					
						
							|  |  |  |         for (auto* environment = current_environment(); environment; environment = environment->parent()) { | 
					
						
							|  |  |  |             auto possible_match = environment->get(name); | 
					
						
							|  |  |  |             if (possible_match.has_value()) | 
					
						
							|  |  |  |                 return { Reference::LocalVariable, name }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-28 14:44:48 +02:00
										 |  |  |     return { Reference::GlobalVariable, name }; | 
					
						
							| 
									
										
										
										
											2020-04-27 12:37:27 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 16:57:22 -07:00
										 |  |  | Symbol* Interpreter::get_global_symbol(const String& description) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto result = m_global_symbol_map.get(description); | 
					
						
							|  |  |  |     if (result.has_value()) | 
					
						
							|  |  |  |         return result.value(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto new_global_symbol = js_symbol(*this, description, true); | 
					
						
							|  |  |  |     m_global_symbol_map.set(description, new_global_symbol); | 
					
						
							|  |  |  |     return new_global_symbol; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-15 15:12:34 +01:00
										 |  |  | void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots) | 
					
						
							| 
									
										
										
										
											2020-03-09 21:29:22 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     roots.set(m_global_object); | 
					
						
							| 
									
										
										
										
											2020-03-24 14:37:39 +01:00
										 |  |  |     roots.set(m_exception); | 
					
						
							| 
									
										
										
										
											2020-03-09 21:29:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 23:45:13 +02:00
										 |  |  |     if (m_last_value.is_cell()) | 
					
						
							|  |  |  |         roots.set(m_last_value.as_cell()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-17 11:00:09 +01:00
										 |  |  |     for (auto& call_frame : m_call_stack) { | 
					
						
							|  |  |  |         if (call_frame.this_value.is_cell()) | 
					
						
							|  |  |  |             roots.set(call_frame.this_value.as_cell()); | 
					
						
							|  |  |  |         for (auto& argument : call_frame.arguments) { | 
					
						
							|  |  |  |             if (argument.is_cell()) | 
					
						
							|  |  |  |                 roots.set(argument.as_cell()); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-15 21:58:22 +02:00
										 |  |  |         roots.set(call_frame.environment); | 
					
						
							| 
									
										
										
										
											2020-03-15 15:07:49 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-29 23:25:21 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-09 15:34:20 -07:00
										 |  |  | #define __JS_ENUMERATE(SymbolName, snake_name) \
 | 
					
						
							|  |  |  |     roots.set(well_known_symbol_##snake_name()); | 
					
						
							|  |  |  |     JS_ENUMERATE_WELL_KNOWN_SYMBOLS | 
					
						
							|  |  |  | #undef __JS_ENUMERATE
 | 
					
						
							| 
									
										
										
										
											2020-07-06 16:57:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto& symbol : m_global_symbol_map) | 
					
						
							|  |  |  |         roots.set(symbol.value); | 
					
						
							| 
									
										
										
										
											2020-03-09 21:29:22 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-25 22:18:32 +04:30
										 |  |  | Value Interpreter::call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments) | 
					
						
							| 
									
										
										
										
											2020-03-18 15:20:49 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-08-14 17:30:34 +02:00
										 |  |  |     ASSERT(!exception()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-18 15:20:49 +01:00
										 |  |  |     auto& call_frame = push_call_frame(); | 
					
						
							| 
									
										
										
										
											2020-04-29 13:43:57 +02:00
										 |  |  |     call_frame.function_name = function.name(); | 
					
						
							| 
									
										
										
										
											2020-05-30 01:07:02 -05:00
										 |  |  |     call_frame.this_value = function.bound_this().value_or(this_value); | 
					
						
							|  |  |  |     call_frame.arguments = function.bound_arguments(); | 
					
						
							| 
									
										
										
										
											2020-04-19 17:24:56 +02:00
										 |  |  |     if (arguments.has_value()) | 
					
						
							| 
									
										
										
										
											2020-05-30 01:07:02 -05:00
										 |  |  |         call_frame.arguments.append(arguments.value().values()); | 
					
						
							| 
									
										
										
										
											2020-04-29 13:43:57 +02:00
										 |  |  |     call_frame.environment = function.create_environment(); | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized); | 
					
						
							|  |  |  |     call_frame.environment->bind_this_value(call_frame.this_value); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 13:43:57 +02:00
										 |  |  |     auto result = function.call(*this); | 
					
						
							| 
									
										
										
										
											2020-03-18 15:20:49 +01:00
										 |  |  |     pop_call_frame(); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 17:53:33 +02:00
										 |  |  | Value Interpreter::construct(Function& function, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject& global_object) | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     auto& call_frame = push_call_frame(); | 
					
						
							|  |  |  |     call_frame.function_name = function.name(); | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  |     call_frame.arguments = function.bound_arguments(); | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  |     if (arguments.has_value()) | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  |         call_frame.arguments.append(arguments.value().values()); | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  |     call_frame.environment = function.create_environment(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  |     current_environment()->set_new_target(&new_target); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Object* new_object = nullptr; | 
					
						
							|  |  |  |     if (function.constructor_kind() == Function::ConstructorKind::Base) { | 
					
						
							| 
									
										
										
										
											2020-07-22 17:50:18 +02:00
										 |  |  |         new_object = Object::create_empty(global_object); | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  |         current_environment()->bind_this_value(new_object); | 
					
						
							| 
									
										
										
										
											2020-06-07 10:53:14 -07:00
										 |  |  |         if (exception()) | 
					
						
							|  |  |  |             return {}; | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  |         auto prototype = new_target.get("prototype"); | 
					
						
							|  |  |  |         if (exception()) | 
					
						
							|  |  |  |             return {}; | 
					
						
							|  |  |  |         if (prototype.is_object()) { | 
					
						
							|  |  |  |             new_object->set_prototype(&prototype.as_object()); | 
					
						
							|  |  |  |             if (exception()) | 
					
						
							|  |  |  |                 return {}; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-07 10:53:14 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // If we are a Derived constructor, |this| has not been constructed before super is called.
 | 
					
						
							|  |  |  |     Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {}; | 
					
						
							|  |  |  |     call_frame.this_value = this_value; | 
					
						
							| 
									
										
										
										
											2020-06-25 15:30:58 -07:00
										 |  |  |     auto result = function.construct(*this, new_target); | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  |     this_value = current_environment()->get_this_binding(); | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  |     pop_call_frame(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  |     // If we are constructing an instance of a derived class,
 | 
					
						
							|  |  |  |     // set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
 | 
					
						
							|  |  |  |     if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) { | 
					
						
							|  |  |  |         current_environment()->replace_this_binding(result); | 
					
						
							|  |  |  |         auto prototype = new_target.get("prototype"); | 
					
						
							|  |  |  |         if (exception()) | 
					
						
							|  |  |  |             return {}; | 
					
						
							|  |  |  |         if (prototype.is_object()) { | 
					
						
							|  |  |  |             result.as_object().set_prototype(&prototype.as_object()); | 
					
						
							|  |  |  |             if (exception()) | 
					
						
							|  |  |  |                 return {}; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  |     if (exception()) | 
					
						
							|  |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  |     if (result.is_object()) | 
					
						
							|  |  |  |         return result; | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return this_value; | 
					
						
							| 
									
										
										
										
											2020-05-01 11:06:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-25 12:52:32 +02:00
										 |  |  | void Interpreter::throw_exception(Exception* exception) | 
					
						
							| 
									
										
										
										
											2020-03-24 14:37:39 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-02 18:01:09 -07:00
										 |  |  | #ifdef INTERPRETER_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-04-04 22:14:03 +02:00
										 |  |  |     if (exception->value().is_object() && exception->value().as_object().is_error()) { | 
					
						
							|  |  |  |         auto& error = static_cast<Error&>(exception->value().as_object()); | 
					
						
							|  |  |  |         dbg() << "Throwing JavaScript Error: " << error.name() << ", " << error.message(); | 
					
						
							| 
									
										
										
										
											2020-04-16 20:23:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (ssize_t i = m_call_stack.size() - 1; i >= 0; --i) { | 
					
						
							|  |  |  |             auto function_name = m_call_stack[i].function_name; | 
					
						
							|  |  |  |             if (function_name.is_empty()) | 
					
						
							|  |  |  |                 function_name = "<anonymous>"; | 
					
						
							|  |  |  |             dbg() << "  " << function_name; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-04 22:14:03 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-26 12:52:20 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-03-24 14:37:39 +01:00
										 |  |  |     m_exception = exception; | 
					
						
							|  |  |  |     unwind(ScopeType::Try); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 11:05:38 +02:00
										 |  |  | GlobalObject& Interpreter::global_object() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return static_cast<GlobalObject&>(*m_global_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const GlobalObject& Interpreter::global_object() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return static_cast<const GlobalObject&>(*m_global_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-04 14:18:15 +02:00
										 |  |  | String Interpreter::join_arguments() const | 
					
						
							| 
									
										
										
										
											2020-05-04 12:34:49 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     StringBuilder joined_arguments; | 
					
						
							|  |  |  |     for (size_t i = 0; i < argument_count(); ++i) { | 
					
						
							| 
									
										
										
										
											2020-05-15 13:39:24 +02:00
										 |  |  |         joined_arguments.append(argument(i).to_string_without_side_effects().characters()); | 
					
						
							| 
									
										
										
										
											2020-05-04 12:34:49 +02:00
										 |  |  |         if (i != argument_count() - 1) | 
					
						
							|  |  |  |             joined_arguments.append(' '); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return joined_arguments.build(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 13:31:21 -05:00
										 |  |  | Value Interpreter::resolve_this_binding() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return get_this_environment()->get_this_binding(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const LexicalEnvironment* Interpreter::get_this_environment() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // We will always return because the Global environment will always be reached, which has a |this| binding.
 | 
					
						
							|  |  |  |     for (const LexicalEnvironment* environment = current_environment(); environment; environment = environment->parent()) { | 
					
						
							|  |  |  |         if (environment->has_this_binding()) | 
					
						
							|  |  |  |             return environment; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ASSERT_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Value Interpreter::get_new_target() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return get_this_environment()->new_target(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 19:42:11 +01:00
										 |  |  | } |