| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 15:17:37 +02:00
										 |  |  | #include <AK/Debug.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-09 10:02:01 +02:00
										 |  |  | #include <AK/TemporaryChange.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-09 06:49:58 +04:30
										 |  |  | #include <LibJS/Bytecode/BasicBlock.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | #include <LibJS/Bytecode/Instruction.h>
 | 
					
						
							|  |  |  | #include <LibJS/Bytecode/Interpreter.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-09 09:19:34 +02:00
										 |  |  | #include <LibJS/Bytecode/Op.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-03 18:26:13 +02:00
										 |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace JS::Bytecode { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | static Interpreter* s_current; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Interpreter* Interpreter::current() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return s_current; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | Interpreter::Interpreter(GlobalObject& global_object) | 
					
						
							| 
									
										
										
										
											2021-06-03 18:26:13 +02:00
										 |  |  |     : m_vm(global_object.vm()) | 
					
						
							|  |  |  |     , m_global_object(global_object) | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  |     VERIFY(!s_current); | 
					
						
							|  |  |  |     s_current = this; | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Interpreter::~Interpreter() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  |     VERIFY(s_current == this); | 
					
						
							|  |  |  |     s_current = nullptr; | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-11 01:38:30 +04:30
										 |  |  | Value Interpreter::run(Executable const& executable, BasicBlock const* entry_point) | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-09 09:11:20 +02:00
										 |  |  |     dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter will run unit {:p}", &executable); | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-09 10:02:01 +02:00
										 |  |  |     TemporaryChange restore_executable { m_current_executable, &executable }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-10 21:01:44 +02:00
										 |  |  |     vm().set_last_value(Badge<Interpreter> {}, {}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 13:54:29 +02:00
										 |  |  |     CallFrame global_call_frame; | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  |     if (vm().call_stack().is_empty()) { | 
					
						
							|  |  |  |         global_call_frame.this_value = &global_object(); | 
					
						
							|  |  |  |         static FlyString global_execution_context_name = "(*BC* global execution context)"; | 
					
						
							|  |  |  |         global_call_frame.function_name = global_execution_context_name; | 
					
						
							|  |  |  |         global_call_frame.scope = &global_object(); | 
					
						
							|  |  |  |         VERIFY(!vm().exception()); | 
					
						
							|  |  |  |         // FIXME: How do we know if we're in strict mode? Maybe the Bytecode::Block should know this?
 | 
					
						
							|  |  |  |         // global_call_frame.is_strict_mode = ???;
 | 
					
						
							|  |  |  |         vm().push_call_frame(global_call_frame, global_object()); | 
					
						
							|  |  |  |         VERIFY(!vm().exception()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-05 15:11:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-11 01:38:30 +04:30
										 |  |  |     auto block = entry_point ?: &executable.basic_blocks.first(); | 
					
						
							|  |  |  |     if (m_manually_entered_frames) { | 
					
						
							|  |  |  |         VERIFY(registers().size() >= executable.number_of_registers); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         m_register_windows.append(make<RegisterWindow>()); | 
					
						
							|  |  |  |         registers().resize(executable.number_of_registers); | 
					
						
							|  |  |  |         registers()[Register::global_object_index] = Value(&global_object()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-09 06:49:58 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |     for (;;) { | 
					
						
							|  |  |  |         Bytecode::InstructionStreamIterator pc(block->instruction_stream()); | 
					
						
							|  |  |  |         bool will_jump = false; | 
					
						
							|  |  |  |         bool will_return = false; | 
					
						
							|  |  |  |         while (!pc.at_end()) { | 
					
						
							|  |  |  |             auto& instruction = *pc; | 
					
						
							|  |  |  |             instruction.execute(*this); | 
					
						
							| 
									
										
										
										
											2021-06-10 15:04:38 +02:00
										 |  |  |             if (vm().exception()) { | 
					
						
							|  |  |  |                 m_saved_exception = {}; | 
					
						
							|  |  |  |                 if (m_unwind_contexts.is_empty()) | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 auto& unwind_context = m_unwind_contexts.last(); | 
					
						
							|  |  |  |                 if (unwind_context.handler) { | 
					
						
							|  |  |  |                     block = unwind_context.handler; | 
					
						
							|  |  |  |                     unwind_context.handler = nullptr; | 
					
						
							|  |  |  |                     accumulator() = vm().exception()->value(); | 
					
						
							|  |  |  |                     vm().clear_exception(); | 
					
						
							|  |  |  |                     will_jump = true; | 
					
						
							|  |  |  |                 } else if (unwind_context.finalizer) { | 
					
						
							|  |  |  |                     block = unwind_context.finalizer; | 
					
						
							|  |  |  |                     m_unwind_contexts.take_last(); | 
					
						
							|  |  |  |                     will_jump = true; | 
					
						
							|  |  |  |                     m_saved_exception = Handle<Exception>::create(vm().exception()); | 
					
						
							|  |  |  |                     vm().clear_exception(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-06-09 06:49:58 +04:30
										 |  |  |             if (m_pending_jump.has_value()) { | 
					
						
							|  |  |  |                 block = m_pending_jump.release_value(); | 
					
						
							|  |  |  |                 will_jump = true; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (!m_return_value.is_empty()) { | 
					
						
							|  |  |  |                 will_return = true; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             ++pc; | 
					
						
							| 
									
										
										
										
											2021-06-04 12:07:38 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-09 06:49:58 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |         if (will_return) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (pc.at_end() && !will_jump) | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2021-06-09 18:19:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (vm().exception()) | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2021-06-04 12:07:38 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-09 09:11:20 +02:00
										 |  |  |     dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter did run unit {:p}", &executable); | 
					
						
							| 
									
										
										
										
											2021-06-07 15:17:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if constexpr (JS_BYTECODE_DEBUG) { | 
					
						
							|  |  |  |         for (size_t i = 0; i < registers().size(); ++i) { | 
					
						
							|  |  |  |             String value_string; | 
					
						
							|  |  |  |             if (registers()[i].is_empty()) | 
					
						
							|  |  |  |                 value_string = "(empty)"; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 value_string = registers()[i].to_string_without_side_effects(); | 
					
						
							|  |  |  |             dbgln("[{:3}] {}", i, value_string); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-10 21:01:44 +02:00
										 |  |  |     vm().set_last_value(Badge<Interpreter> {}, accumulator()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-11 01:38:30 +04:30
										 |  |  |     if (!m_manually_entered_frames) | 
					
						
							|  |  |  |         m_register_windows.take_last(); | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 13:57:02 +02:00
										 |  |  |     auto return_value = m_return_value.value_or(js_undefined()); | 
					
						
							|  |  |  |     m_return_value = {}; | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // NOTE: The return value from a called function is put into $0 in the caller context.
 | 
					
						
							|  |  |  |     if (!m_register_windows.is_empty()) | 
					
						
							| 
									
										
										
										
											2021-06-07 13:57:02 +02:00
										 |  |  |         m_register_windows.last()[0] = return_value; | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (vm().call_stack().size() == 1) | 
					
						
							|  |  |  |         vm().pop_call_frame(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 13:57:02 +02:00
										 |  |  |     return return_value; | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-10 15:04:38 +02:00
										 |  |  | void Interpreter::enter_unwind_context(Optional<Label> handler_target, Optional<Label> finalizer_target) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_unwind_contexts.empend(handler_target.has_value() ? &handler_target->block() : nullptr, finalizer_target.has_value() ? &finalizer_target->block() : nullptr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Interpreter::leave_unwind_context() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_unwind_contexts.take_last(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Interpreter::continue_pending_unwind(Label const& resume_label) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!m_saved_exception.is_null()) { | 
					
						
							|  |  |  |         vm().set_exception(*m_saved_exception.cell()); | 
					
						
							|  |  |  |         m_saved_exception = {}; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         jump(resume_label); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | } |