* Copyright (c) 2021-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BYTECODE_EMITTER_H
#define BYTECODE_EMITTER_H
#include <bytecode_instruction.h>
#include <cstdint>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <list>
namespace ark {
class BytecodeEmitter;
* Label represents a branch target.
* User can associate a labe with the special place by calling
* BytecodeEmitter.Bind(const Label& label) method.
* It is not allowed to share labels between different instancies
* of BytecodeEmitter.
* Lifetime of a label must match lifetime of the emitter.
*/
class Label {
private:
explicit Label(std::list<uint32_t>::iterator pc) : pc_(pc) {}
uint32_t GetPc() const
{
return *pc_;
}
private:
std::list<uint32_t>::iterator pc_;
friend class BytecodeEmitter;
};
class BytecodeEmitter {
public:
enum class ErrorCode {
SUCCESS,
INTERNAL_ERROR,
UNBOUND_LABELS,
};
enum class BitImmSize {
BITSIZE_4,
BITSIZE_8,
BITSIZE_16,
BITSIZE_32,
};
public:
BytecodeEmitter() = default;
~BytecodeEmitter() = default;
NO_COPY_SEMANTIC(BytecodeEmitter);
NO_MOVE_SEMANTIC(BytecodeEmitter);
Label CreateLabel()
{
pcList_.push_front(0);
return Label(pcList_.begin());
}
PANDA_PUBLIC_API void Bind(const Label &label);
* Generate mov <reg> <reg> instruction.
* The method chooses appropriate instruction encoding.
*/
PANDA_PUBLIC_API ErrorCode Build(std::vector<uint8_t> *output);
#include <bytecode_emitter_def_gen.h>
private:
ErrorCode ReserveSpaceForOffsets();
ErrorCode DoReserveSpaceForOffset(const BytecodeInstruction &insn, uint32_t insnPc, BitImmSize expectedImmSize,
size_t *extraBytesPtr, uint32_t *targetPtr);
ErrorCode UpdateBranches();
void UpdateLabelTargets(uint32_t pc, size_t bias);
int32_t EstimateMaxDistance(uint32_t insnPc, uint32_t targetPc, uint32_t bias) const;
ErrorCode CheckLabels();
static size_t GetSizeByOpcode(BytecodeInstruction::Opcode opcode);
static BytecodeInstruction::Opcode RevertConditionCode(BytecodeInstruction::Opcode opcode);
static void UpdateBranchOffs(uint8_t *insn, int32_t offs);
static BitImmSize GetBitImmSizeByOpcode(BytecodeInstruction::Opcode opcode);
static BytecodeInstruction::Opcode GetLongestJump(BytecodeInstruction::Opcode opcode);
BytecodeInstruction::Opcode GetSuitableJump(BytecodeInstruction::Opcode opcode, BytecodeEmitter::BitImmSize width);
private:
struct LabelCmp {
bool operator()(const Label &l1, const Label &l2) const
{
return *l1.pc_ < *l2.pc_;
}
};
private:
uint32_t pc_ {0};
std::map<uint32_t, Label> branches_;
std::multiset<Label, LabelCmp> targets_;
std::list<uint32_t> pcList_;
std::vector<uint8_t> bytecode_;
};
}
#endif