mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:52:45 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			66 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			66 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include <LibJS/Bytecode/PassManager.h>
 | |
| #include <string.h>
 | |
| 
 | |
| namespace JS::Bytecode::Passes {
 | |
| 
 | |
| void UnifySameBlocks::perform(PassPipelineExecutable& executable)
 | |
| {
 | |
|     started();
 | |
| 
 | |
|     VERIFY(executable.cfg.has_value());
 | |
|     VERIFY(executable.inverted_cfg.has_value());
 | |
|     auto cfg = executable.cfg.release_value();
 | |
|     auto inverted_cfg = executable.inverted_cfg.release_value();
 | |
| 
 | |
|     HashMap<BasicBlock const*, BasicBlock const*> equal_blocks;
 | |
| 
 | |
|     for (size_t i = 0; i < executable.executable.basic_blocks.size(); ++i) {
 | |
|         auto& block = executable.executable.basic_blocks[i];
 | |
|         auto block_bytes = block.instruction_stream();
 | |
|         for (auto& candidate_block : executable.executable.basic_blocks.span().slice(i + 1)) {
 | |
|             if (equal_blocks.contains(&*candidate_block))
 | |
|                 continue;
 | |
|             // FIXME: This can probably be relaxed a bit...
 | |
|             if (candidate_block->size() != block.size())
 | |
|                 continue;
 | |
| 
 | |
|             auto candidate_bytes = candidate_block->instruction_stream();
 | |
|             // FIXME: NewBigInt's value is not correctly reflected by its encoding in memory,
 | |
|             //        this will yield false negatives for blocks containing that
 | |
|             if (memcmp(candidate_bytes.data(), block_bytes.data(), candidate_block->size()) == 0)
 | |
|                 equal_blocks.set(&*candidate_block, &block);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     auto replace_blocks = [&](auto& match, auto& replacement) {
 | |
|         Optional<size_t> first_successor_position;
 | |
|         auto it = executable.executable.basic_blocks.find_if([match](auto& block) { return match == block; });
 | |
|         VERIFY(!it.is_end());
 | |
|         executable.executable.basic_blocks.remove(it.index());
 | |
|         if (!first_successor_position.has_value())
 | |
|             first_successor_position = it.index();
 | |
| 
 | |
|         for (auto& block : executable.executable.basic_blocks) {
 | |
|             InstructionStreamIterator it { block.instruction_stream() };
 | |
|             while (!it.at_end()) {
 | |
|                 auto& instruction = *it;
 | |
|                 ++it;
 | |
|                 const_cast<Instruction&>(instruction).replace_references(*match, replacement);
 | |
|             }
 | |
|         }
 | |
|         return first_successor_position;
 | |
|     };
 | |
| 
 | |
|     for (auto& entry : equal_blocks)
 | |
|         (void)replace_blocks(entry.key, *entry.value);
 | |
| 
 | |
|     finished();
 | |
| }
 | |
| 
 | |
| }
 | 
