mirror of
				https://github.com/LadybirdBrowser/ladybird.git
				synced 2025-10-31 05:10:57 +00:00 
			
		
		
		
	 855f6417df
			
		
	
	
		855f6417df
		
	
	
	
	
		
			
			These were out-of-line because we had some ideas about marking instruction streams PROT_READ only, but that seems pretty arbitrary and there's a lot of performance to be gained by putting these inline.
		
			
				
	
	
		
			117 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021-2024, Andreas Kling <kling@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include <LibJS/Bytecode/BasicBlock.h>
 | |
| #include <LibJS/Bytecode/Executable.h>
 | |
| #include <LibJS/Bytecode/Instruction.h>
 | |
| #include <LibJS/Bytecode/RegexTable.h>
 | |
| #include <LibJS/SourceCode.h>
 | |
| 
 | |
| namespace JS::Bytecode {
 | |
| 
 | |
| JS_DEFINE_ALLOCATOR(Executable);
 | |
| 
 | |
| Executable::Executable(
 | |
|     Vector<u8> bytecode,
 | |
|     NonnullOwnPtr<IdentifierTable> identifier_table,
 | |
|     NonnullOwnPtr<StringTable> string_table,
 | |
|     NonnullOwnPtr<RegexTable> regex_table,
 | |
|     Vector<Value> constants,
 | |
|     NonnullRefPtr<SourceCode const> source_code,
 | |
|     size_t number_of_property_lookup_caches,
 | |
|     size_t number_of_global_variable_caches,
 | |
|     size_t number_of_registers,
 | |
|     bool is_strict_mode)
 | |
|     : bytecode(move(bytecode))
 | |
|     , string_table(move(string_table))
 | |
|     , identifier_table(move(identifier_table))
 | |
|     , regex_table(move(regex_table))
 | |
|     , constants(move(constants))
 | |
|     , source_code(move(source_code))
 | |
|     , number_of_registers(number_of_registers)
 | |
|     , is_strict_mode(is_strict_mode)
 | |
| {
 | |
|     property_lookup_caches.resize(number_of_property_lookup_caches);
 | |
|     global_variable_caches.resize(number_of_global_variable_caches);
 | |
| }
 | |
| 
 | |
| Executable::~Executable() = default;
 | |
| 
 | |
| void Executable::dump() const
 | |
| {
 | |
|     warnln("\033[37;1mJS bytecode executable\033[0m \"{}\"", name);
 | |
|     InstructionStreamIterator it(bytecode, this);
 | |
| 
 | |
|     size_t basic_block_offset_index = 0;
 | |
| 
 | |
|     while (!it.at_end()) {
 | |
|         bool print_basic_block_marker = false;
 | |
|         if (basic_block_offset_index < basic_block_start_offsets.size()
 | |
|             && it.offset() == basic_block_start_offsets[basic_block_offset_index]) {
 | |
|             ++basic_block_offset_index;
 | |
|             print_basic_block_marker = true;
 | |
|         }
 | |
| 
 | |
|         StringBuilder builder;
 | |
|         builder.appendff("[{:4x}] ", it.offset());
 | |
|         if (print_basic_block_marker)
 | |
|             builder.appendff("{:4}: ", basic_block_offset_index - 1);
 | |
|         else
 | |
|             builder.append("      "sv);
 | |
|         builder.append((*it).to_byte_string(*this));
 | |
| 
 | |
|         warnln("{}", builder.string_view());
 | |
| 
 | |
|         ++it;
 | |
|     }
 | |
| 
 | |
|     if (!exception_handlers.is_empty()) {
 | |
|         warnln("");
 | |
|         warnln("Exception handlers:");
 | |
|         for (auto& handlers : exception_handlers) {
 | |
|             warnln("    from {:4x} to {:4x} handler {:4x} finalizer {:4x}",
 | |
|                 handlers.start_offset,
 | |
|                 handlers.end_offset,
 | |
|                 handlers.handler_offset.value_or(0),
 | |
|                 handlers.finalizer_offset.value_or(0));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     warnln("");
 | |
| }
 | |
| 
 | |
| void Executable::visit_edges(Visitor& visitor)
 | |
| {
 | |
|     Base::visit_edges(visitor);
 | |
|     visitor.visit(constants);
 | |
| }
 | |
| 
 | |
| Optional<Executable::ExceptionHandlers const&> Executable::exception_handlers_for_offset(size_t offset) const
 | |
| {
 | |
|     for (auto& handlers : exception_handlers) {
 | |
|         if (handlers.start_offset <= offset && offset < handlers.end_offset)
 | |
|             return handlers;
 | |
|     }
 | |
|     return {};
 | |
| }
 | |
| 
 | |
| UnrealizedSourceRange Executable::source_range_at(size_t offset) const
 | |
| {
 | |
|     if (offset >= bytecode.size())
 | |
|         return {};
 | |
|     auto it = InstructionStreamIterator(bytecode.span().slice(offset), this);
 | |
|     VERIFY(!it.at_end());
 | |
|     auto mapping = source_map.get(offset);
 | |
|     if (!mapping.has_value())
 | |
|         return {};
 | |
|     return UnrealizedSourceRange {
 | |
|         .source_code = source_code,
 | |
|         .start_offset = mapping->source_start_offset,
 | |
|         .end_offset = mapping->source_end_offset,
 | |
|     };
 | |
| }
 | |
| 
 | |
| }
 |