
This pass tries to eliminate repeated lookups of variables by name, by remembering where these where last loaded to. For now the lookup cache needs to be fully cleared with each call or property access, because we do not have a way to check if these have any side effects on the currently visible scopes. Note that property accesses can cause getters/setters to be called, so these are treated as calls in all cases.
150 lines
3.3 KiB
C++
150 lines
3.3 KiB
C++
/*
|
|
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibJS/Bytecode/BasicBlock.h>
|
|
#include <LibJS/Bytecode/Generator.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
|
|
namespace JS::Bytecode {
|
|
|
|
struct PassPipelineExecutable {
|
|
Executable& executable;
|
|
Optional<HashMap<BasicBlock const*, HashTable<BasicBlock const*>>> cfg {};
|
|
Optional<HashMap<BasicBlock const*, HashTable<BasicBlock const*>>> inverted_cfg {};
|
|
Optional<HashTable<BasicBlock const*>> exported_blocks {};
|
|
};
|
|
|
|
class Pass {
|
|
public:
|
|
Pass() = default;
|
|
virtual ~Pass() = default;
|
|
|
|
virtual void perform(PassPipelineExecutable&) = 0;
|
|
void started()
|
|
{
|
|
gettimeofday(&m_start_time, nullptr);
|
|
}
|
|
void finished()
|
|
{
|
|
struct timeval end_time {
|
|
0, 0
|
|
};
|
|
gettimeofday(&end_time, nullptr);
|
|
time_t interval_s = end_time.tv_sec - m_start_time.tv_sec;
|
|
suseconds_t interval_us = end_time.tv_usec;
|
|
if (interval_us < m_start_time.tv_usec) {
|
|
interval_s -= 1;
|
|
interval_us += 1000000;
|
|
}
|
|
interval_us -= m_start_time.tv_usec;
|
|
m_time_difference = interval_s * 1000000 + interval_us;
|
|
}
|
|
|
|
u64 elapsed() const { return m_time_difference; }
|
|
|
|
protected:
|
|
struct timeval m_start_time {
|
|
0, 0
|
|
};
|
|
u64 m_time_difference { 0 };
|
|
};
|
|
|
|
class PassManager : public Pass {
|
|
public:
|
|
PassManager() = default;
|
|
~PassManager() override = default;
|
|
|
|
void add(NonnullOwnPtr<Pass> pass) { m_passes.append(move(pass)); }
|
|
|
|
template<typename PassT, typename... Args>
|
|
void add(Args&&... args) { m_passes.append(make<PassT>(forward<Args>(args)...)); }
|
|
|
|
void perform(Executable& executable)
|
|
{
|
|
PassPipelineExecutable pipeline_executable { executable };
|
|
perform(pipeline_executable);
|
|
}
|
|
|
|
virtual void perform(PassPipelineExecutable& executable) override
|
|
{
|
|
started();
|
|
for (auto& pass : m_passes)
|
|
pass.perform(executable);
|
|
finished();
|
|
}
|
|
|
|
private:
|
|
NonnullOwnPtrVector<Pass> m_passes;
|
|
};
|
|
|
|
namespace Passes {
|
|
|
|
class GenerateCFG : public Pass {
|
|
public:
|
|
GenerateCFG() = default;
|
|
~GenerateCFG() override = default;
|
|
|
|
private:
|
|
virtual void perform(PassPipelineExecutable&) override;
|
|
};
|
|
|
|
class MergeBlocks : public Pass {
|
|
public:
|
|
MergeBlocks() = default;
|
|
~MergeBlocks() override = default;
|
|
|
|
private:
|
|
virtual void perform(PassPipelineExecutable&) override;
|
|
};
|
|
|
|
class PlaceBlocks : public Pass {
|
|
public:
|
|
PlaceBlocks() = default;
|
|
~PlaceBlocks() override = default;
|
|
|
|
private:
|
|
virtual void perform(PassPipelineExecutable&) override;
|
|
};
|
|
|
|
class UnifySameBlocks : public Pass {
|
|
public:
|
|
UnifySameBlocks() = default;
|
|
~UnifySameBlocks() override = default;
|
|
|
|
private:
|
|
virtual void perform(PassPipelineExecutable&) override;
|
|
};
|
|
|
|
class DumpCFG : public Pass {
|
|
public:
|
|
DumpCFG(FILE* file)
|
|
: m_file(file)
|
|
{
|
|
}
|
|
|
|
~DumpCFG() override = default;
|
|
|
|
private:
|
|
virtual void perform(PassPipelineExecutable&) override;
|
|
|
|
FILE* m_file { nullptr };
|
|
};
|
|
|
|
class EliminateLoads : public Pass {
|
|
public:
|
|
EliminateLoads() = default;
|
|
virtual ~EliminateLoads() override = default;
|
|
|
|
private:
|
|
virtual void perform(PassPipelineExecutable&) override;
|
|
};
|
|
|
|
}
|
|
|
|
}
|