| 
									
										
										
										
											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-07-01 12:24:46 +02:00
										 |  |  | #include <LibJS/Runtime/GlobalEnvironment.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-03 18:26:13 +02:00
										 |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							| 
									
										
										
										
											2021-09-11 20:27:36 +01:00
										 |  |  | #include <LibJS/Runtime/Realm.h>
 | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace JS::Bytecode { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | static Interpreter* s_current; | 
					
						
							| 
									
										
										
										
											2021-10-24 13:34:46 +02:00
										 |  |  | bool g_dump_bytecode = false; | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Interpreter* Interpreter::current() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return s_current; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-11 19:36:25 +01:00
										 |  |  | Interpreter::Interpreter(GlobalObject& global_object, Realm& realm) | 
					
						
							| 
									
										
										
										
											2021-06-03 18:26:13 +02:00
										 |  |  |     : m_vm(global_object.vm()) | 
					
						
							|  |  |  |     , m_global_object(global_object) | 
					
						
							| 
									
										
										
										
											2021-09-11 19:36:25 +01:00
										 |  |  |     , m_realm(realm) | 
					
						
							| 
									
										
										
										
											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-11-11 00:34:44 +03:30
										 |  |  | Interpreter::ValueAndFrame Interpreter::run_and_return_frame(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-08-09 17:09:48 -04:00
										 |  |  |     ExecutionContext execution_context(vm().heap()); | 
					
						
							| 
									
										
										
										
											2021-06-24 19:17:45 +02:00
										 |  |  |     if (vm().execution_context_stack().is_empty()) { | 
					
						
							|  |  |  |         execution_context.this_value = &global_object(); | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  |         static FlyString global_execution_context_name = "(*BC* global execution context)"; | 
					
						
							| 
									
										
										
										
											2021-06-24 19:17:45 +02:00
										 |  |  |         execution_context.function_name = global_execution_context_name; | 
					
						
							| 
									
										
										
										
											2021-09-11 20:27:36 +01:00
										 |  |  |         execution_context.lexical_environment = &m_realm.global_environment(); | 
					
						
							|  |  |  |         execution_context.variable_environment = &m_realm.global_environment(); | 
					
						
							| 
									
										
										
										
											2021-09-13 21:05:53 +01:00
										 |  |  |         execution_context.realm = &m_realm; | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  |         // FIXME: How do we know if we're in strict mode? Maybe the Bytecode::Block should know this?
 | 
					
						
							| 
									
										
										
										
											2021-06-24 19:17:45 +02:00
										 |  |  |         // execution_context.is_strict_mode = ???;
 | 
					
						
							|  |  |  |         vm().push_execution_context(execution_context, global_object()); | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  |         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(); | 
					
						
							| 
									
										
										
										
											2021-11-11 00:34:44 +03:30
										 |  |  |     if (!m_manually_entered_frames.is_empty() && m_manually_entered_frames.last()) { | 
					
						
							|  |  |  |         m_register_windows.append(make<RegisterWindow>(m_register_windows.last())); | 
					
						
							| 
									
										
										
										
											2021-06-11 01:38:30 +04:30
										 |  |  |     } else { | 
					
						
							|  |  |  |         m_register_windows.append(make<RegisterWindow>()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-09 06:49:58 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-11 00:34:44 +03:30
										 |  |  |     registers().resize(executable.number_of_registers); | 
					
						
							|  |  |  |     registers()[Register::global_object_index] = Value(&global_object()); | 
					
						
							|  |  |  |     m_manually_entered_frames.append(false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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(); | 
					
						
							| 
									
										
										
										
											2021-10-25 12:30:54 +02:00
										 |  |  |                 if (unwind_context.executable != m_current_executable) | 
					
						
							|  |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2021-06-10 15:04:38 +02:00
										 |  |  |                 if (unwind_context.handler) { | 
					
						
							|  |  |  |                     block = unwind_context.handler; | 
					
						
							|  |  |  |                     unwind_context.handler = nullptr; | 
					
						
							|  |  |  |                     accumulator() = vm().exception()->value(); | 
					
						
							|  |  |  |                     vm().clear_exception(); | 
					
						
							|  |  |  |                     will_jump = true; | 
					
						
							| 
									
										
										
										
											2021-10-24 23:52:39 +02:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (unwind_context.finalizer) { | 
					
						
							| 
									
										
										
										
											2021-06-10 15:04:38 +02:00
										 |  |  |                     block = unwind_context.finalizer; | 
					
						
							|  |  |  |                     m_unwind_contexts.take_last(); | 
					
						
							|  |  |  |                     will_jump = true; | 
					
						
							|  |  |  |                     m_saved_exception = Handle<Exception>::create(vm().exception()); | 
					
						
							|  |  |  |                     vm().clear_exception(); | 
					
						
							| 
									
										
										
										
											2021-10-24 23:52:39 +02:00
										 |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2021-06-10 15:04:38 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											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-11-11 00:34:44 +03:30
										 |  |  |     OwnPtr<RegisterWindow> frame; | 
					
						
							|  |  |  |     if (!m_manually_entered_frames.last()) { | 
					
						
							|  |  |  |         frame = m_register_windows.take_last(); | 
					
						
							|  |  |  |         m_manually_entered_frames.take_last(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-11 04:11:56 +03:30
										 |  |  |     Value exception_value; | 
					
						
							|  |  |  |     if (vm().exception()) { | 
					
						
							|  |  |  |         exception_value = vm().exception()->value(); | 
					
						
							|  |  |  |         vm().clear_exception(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-11 00:44:56 +03:30
										 |  |  |     // At this point we may have already run any queued promise jobs via on_call_stack_emptied,
 | 
					
						
							|  |  |  |     // in which case this is a no-op.
 | 
					
						
							|  |  |  |     vm().run_queued_promise_jobs(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-24 19:17:45 +02:00
										 |  |  |     if (vm().execution_context_stack().size() == 1) | 
					
						
							|  |  |  |         vm().pop_execution_context(); | 
					
						
							| 
									
										
										
										
											2021-06-05 15:53:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-12 17:32:54 +03:00
										 |  |  |     vm().finish_execution_generation(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-11 04:11:56 +03:30
										 |  |  |     if (!exception_value.is_empty()) | 
					
						
							|  |  |  |         return { throw_completion(exception_value), move(frame) }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-11 00:34:44 +03:30
										 |  |  |     return { return_value, move(frame) }; | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-10-25 12:30:54 +02:00
										 |  |  |     m_unwind_contexts.empend(m_current_executable, handler_target.has_value() ? &handler_target->block() : nullptr, finalizer_target.has_value() ? &finalizer_target->block() : nullptr); | 
					
						
							| 
									
										
										
										
											2021-06-10 15:04:38 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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-13 20:40:20 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  | AK::Array<OwnPtr<PassManager>, static_cast<UnderlyingType<Interpreter::OptimizationLevel>>(Interpreter::OptimizationLevel::__Count)> Interpreter::s_optimization_pipelines {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Bytecode::PassManager& Interpreter::optimization_pipeline(Interpreter::OptimizationLevel level) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto underlying_level = to_underlying(level); | 
					
						
							|  |  |  |     VERIFY(underlying_level <= to_underlying(Interpreter::OptimizationLevel::__Count)); | 
					
						
							|  |  |  |     auto& entry = s_optimization_pipelines[underlying_level]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (entry) | 
					
						
							|  |  |  |         return *entry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto pm = make<PassManager>(); | 
					
						
							|  |  |  |     if (level == OptimizationLevel::Default) { | 
					
						
							|  |  |  |         pm->add<Passes::GenerateCFG>(); | 
					
						
							|  |  |  |         pm->add<Passes::UnifySameBlocks>(); | 
					
						
							|  |  |  |         pm->add<Passes::GenerateCFG>(); | 
					
						
							|  |  |  |         pm->add<Passes::MergeBlocks>(); | 
					
						
							|  |  |  |         pm->add<Passes::GenerateCFG>(); | 
					
						
							|  |  |  |         pm->add<Passes::UnifySameBlocks>(); | 
					
						
							|  |  |  |         pm->add<Passes::GenerateCFG>(); | 
					
						
							|  |  |  |         pm->add<Passes::MergeBlocks>(); | 
					
						
							|  |  |  |         pm->add<Passes::GenerateCFG>(); | 
					
						
							|  |  |  |         pm->add<Passes::PlaceBlocks>(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& passes = *pm; | 
					
						
							|  |  |  |     entry = move(pm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return passes; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-03 10:46:30 +02:00
										 |  |  | } |