reduce bytecode size

This commit is contained in:
blueloveTH 2023-10-14 14:30:15 +08:00
parent ffde186dfa
commit 1afef9dcb9
7 changed files with 33 additions and 30 deletions

View File

@ -21,8 +21,7 @@ inline const char* OP_NAMES[] = {
struct Bytecode{
uint8_t op;
uint16_t block;
int arg;
uint16_t arg;
};
enum CodeBlockType {
@ -33,7 +32,7 @@ enum CodeBlockType {
TRY_EXCEPT,
};
inline const int BC_NOARG = -1;
inline const uint8_t BC_NOARG = 0;
inline const int BC_KEEPLINE = -1;
struct CodeBlock {
@ -103,6 +102,7 @@ struct CodeObject {
bool is_generator = false;
std::vector<Bytecode> codes;
std::vector<int> iblocks; // block index for each bytecode
std::vector<int> lines; // line number for each bytecode
List consts;
std::vector<StrName> varnames; // local variables
@ -111,6 +111,10 @@ struct CodeObject {
NameDictInt labels;
std::vector<FuncDecl_> func_decls;
const CodeBlock& _get_block_codei(int codei) const{
return blocks[iblocks[codei]];
}
CodeObject(std::shared_ptr<SourceData> src, const Str& name);
void _gc_mark() const;
void write(VM* vm, CodeObjectSerializer& ss) const;

View File

@ -52,7 +52,7 @@
// This is the maximum number of arguments in a function declaration
// including positional arguments, keyword-only arguments, and varargs
// (not recommended to change this)
// (not recommended to change this / it should be less than 200)
#define PK_MAX_CO_VARNAMES 32
namespace pkpy{

View File

@ -60,7 +60,7 @@ struct CodeEmitContext{
void exit_block();
void emit_expr(); // clear the expression stack and generate bytecode
std::string _log_s_expr();
int emit(Opcode opcode, int arg, int line);
int emit(Opcode opcode, uint16_t arg, int line);
void patch_jump(int index);
bool add_label(StrName name);
int add_varname(StrName name);

View File

@ -88,7 +88,7 @@ __NEXT_STEP:;
TARGET(LOAD_NONE) PUSH(None); DISPATCH();
TARGET(LOAD_TRUE) PUSH(True); DISPATCH();
TARGET(LOAD_FALSE) PUSH(False); DISPATCH();
TARGET(LOAD_INTEGER) PUSH(VAR(byte.arg)); DISPATCH();
TARGET(LOAD_INTEGER) PUSH(VAR((int16_t)byte.arg)); DISPATCH();
TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
TARGET(LOAD_FUNCTION) {
FuncDecl_ decl = co->func_decls[byte.arg];
@ -511,8 +511,8 @@ __NEXT_STEP:;
DISPATCH();
TARGET(CALL)
_0 = vectorcall(
byte.arg & 0xFFFF, // ARGC
(byte.arg>>16) & 0xFFFF, // KWARGC
byte.arg & 0xFF, // ARGC
(byte.arg>>8) & 0xFF, // KWARGC
true
);
if(_0 == PY_OP_CALL) DISPATCH_OP_CALL();
@ -600,7 +600,8 @@ __NEXT_STEP:;
if(_0 != StopIteration){
PUSH(_0);
}else{
frame->jump_abs_break(co_blocks[byte.block].end);
// TODO: optimize this
frame->jump_abs_break(co->_get_block_codei(frame->_ip).end);
}
DISPATCH();
/*****************************************/

View File

@ -50,10 +50,9 @@ namespace pkpy{
return ss.str();
}
int CodeEmitContext::emit(Opcode opcode, int arg, int line) {
co->codes.push_back(
Bytecode{(uint8_t)opcode, (uint16_t)curr_block_i, arg}
);
int CodeEmitContext::emit(Opcode opcode, uint16_t arg, int line) {
co->codes.push_back(Bytecode{(uint8_t)opcode, arg});
co->iblocks.push_back(curr_block_i);
co->lines.push_back(line);
int i = co->codes.size() - 1;
if(line==BC_KEEPLINE){
@ -75,6 +74,7 @@ namespace pkpy{
}
int CodeEmitContext::add_varname(StrName name){
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
int index = co->varnames_inv.try_get(name);
if(index >= 0) return index;
co->varnames.push_back(name);
@ -143,8 +143,7 @@ namespace pkpy{
bool NameExpr::emit_store(CodeEmitContext* ctx) {
if(ctx->is_compiling_class){
int index = name.index;
ctx->emit(OP_STORE_CLASS_ATTR, index, line);
ctx->emit(OP_STORE_CLASS_ATTR, name.index, line);
return true;
}
ctx->emit_store_name(scope, name, line);
@ -214,7 +213,7 @@ namespace pkpy{
if(std::holds_alternative<i64>(value)){
i64 _val = std::get<i64>(value);
if(_val >= INT16_MIN && _val <= INT16_MAX){
ctx->emit(OP_LOAD_INTEGER, (int)_val, line);
ctx->emit(OP_LOAD_INTEGER, (uint16_t)_val, line);
return;
}
obj = VAR(_val);
@ -237,7 +236,7 @@ namespace pkpy{
if(std::holds_alternative<i64>(lit->value)){
i64 _val = -std::get<i64>(lit->value);
if(_val >= INT16_MIN && _val <= INT16_MAX){
ctx->emit(OP_LOAD_INTEGER, (int)_val, line);
ctx->emit(OP_LOAD_INTEGER, (uint16_t)_val, line);
}else{
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line);
}
@ -484,7 +483,7 @@ namespace pkpy{
if(vargs || vkwargs){
for(auto& item: args) item->emit(ctx);
ctx->emit(OP_BUILD_TUPLE_UNPACK, (int)args.size(), line);
ctx->emit(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line);
if(!kwargs.empty()){
for(auto& item: kwargs){
@ -508,13 +507,13 @@ namespace pkpy{
// vectorcall protocal
for(auto& item: args) item->emit(ctx);
for(auto& item: kwargs){
int index = StrName(item.first.sv()).index;
uint16_t index = StrName(item.first.sv()).index;
ctx->emit(OP_LOAD_INTEGER, index, line);
item.second->emit(ctx);
}
int KWARGC = (int)kwargs.size();
int ARGC = (int)args.size();
ctx->emit(OP_CALL, (KWARGC<<16)|ARGC, line);
int KWARGC = kwargs.size();
int ARGC = args.size();
ctx->emit(OP_CALL, (KWARGC<<8)|ARGC, line);
}
}

View File

@ -25,7 +25,7 @@ namespace pkpy{
bool Frame::jump_to_exception_handler(){
// try to find a parent try block
int block = co->codes[_ip].block;
int block = co->iblocks[_ip];
while(block >= 0){
if(co->blocks[block].type == TRY_EXCEPT) break;
block = co->blocks[block].parent;
@ -47,8 +47,7 @@ namespace pkpy{
}
void Frame::jump_abs_break(int target){
const Bytecode& prev = co->codes[_ip];
int i = prev.block;
int i = co->iblocks[_ip];
_next_ip = target;
if(_next_ip >= co->codes.size()){
while(i>=0) i = _exit_block(i);
@ -58,9 +57,9 @@ namespace pkpy{
// _ = 0
// # if there is no op here, the block check will fail
// while i: --i
const Bytecode& next = co->codes[target];
while(i>=0 && i!=next.block) i = _exit_block(i);
if(i!=next.block) throw std::runtime_error("invalid jump");
int next_block = co->iblocks[target];
while(i>=0 && i!=next_block) i = _exit_block(i);
if(i!=next_block) throw std::runtime_error("invalid jump");
}
}

View File

@ -513,7 +513,7 @@ PyObject* VM::new_module(Str name, Str package) {
}
static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
std::string argStr = byte.arg == BC_NOARG ? "" : std::to_string(byte.arg);
switch(byte.op){
case OP_LOAD_CONST: case OP_FORMAT_STRING: case OP_IMPORT_PATH:
if(vm != nullptr){