WIP: support CPython 3.12

This commit is contained in:
Shunsuke Shibayama 2024-10-09 02:47:28 +09:00
parent e8af24d3c6
commit 85081372ff
7 changed files with 322 additions and 35 deletions

View file

@ -22,6 +22,7 @@ pub mod opcode308;
pub mod opcode309;
pub mod opcode310;
pub mod opcode311;
pub mod opcode312;
pub mod pathutil;
pub mod python_util;
pub mod random;

View file

@ -48,7 +48,7 @@ pub enum CommonOpcode {
BUILD_LIST = 103,
BUILD_SET = 104,
BUILD_MAP = 105, // build a Dict object
LOAD_ATTR = 106,
// LOAD_ATTR = 106,
COMPARE_OP = 107,
IMPORT_NAME = 108,
IMPORT_FROM = 109,
@ -115,7 +115,7 @@ impl TryFrom<u8> for CommonOpcode {
103 => BUILD_LIST,
104 => BUILD_SET,
105 => BUILD_MAP,
106 => LOAD_ATTR,
// 106 => LOAD_ATTR,
107 => COMPARE_OP,
108 => IMPORT_NAME,
109 => IMPORT_FROM,

View file

@ -1,6 +1,6 @@
//! defines `Opcode` (represents Python bytecode opcodes).
//! defines `Opcode310` (represents CPython 3.10 bytecode opcodes).
//!
//! Opcode(Pythonバイトコードオペコードを表す)を定義する
//! Opcode310(CPython 3.10バイトコードオペコードを表す)を定義する
#![allow(dead_code)]
#![allow(non_camel_case_types)]

View file

@ -1,6 +1,6 @@
//! defines `Opcode` (represents Python bytecode opcodes).
//! defines `Opcode311` (represents CPython 3.11 bytecode opcodes).
//!
//! Opcode(Pythonバイトコードオペコードを表す)を定義する
//! Opcode311(CPython 3.11バイトコードオペコードを表す)を定義する
#![allow(dead_code)]
#![allow(non_camel_case_types)]

View file

@ -0,0 +1,177 @@
//! defines `Opcode312` (represents CPython 3.12 bytecode opcodes).
//!
//! Opcode312(CPython 3.12バイトコードオペコードを表す)を定義する
#![allow(dead_code)]
#![allow(non_camel_case_types)]
use crate::impl_u8_enum;
impl_u8_enum! {Opcode312;
CACHE = 0,
POP_TOP = 1,
PUSH_NULL = 2,
INTERPRETER_EXIT = 3,
END_FOR = 4,
END_SEND = 5,
NOP = 9,
UNARY_NEGATIVE = 11,
UNARY_NOT = 12,
UNARY_INVERT = 15,
BINARY_SUBSCR = 25,
BINARY_SLICE = 26,
STORE_SLICE = 27,
GET_LEN = 30,
MATCH_MAPPING = 31,
MATCH_SEQUENCE = 32,
MATCH_KEYS = 33,
PUSH_EXC_INFO = 35,
CHECK_EXC_MATCH = 36,
CHECK_EG_MATCH = 37,
WITH_EXCEPT_START = 49,
GET_AITER = 50,
GET_ANEXT = 51,
BEFORE_ASYNC_WITH = 52,
BEFORE_WITH = 53,
END_ASYNC_FOR = 54,
STORE_SUBSCR = 60,
GET_ITER = 68,
GET_YIELD_FROM_ITER = 69,
PRINT_EXPR = 70,
LOAD_BUILD_CLASS = 71,
LOAD_ASSERTION_ERROR = 74,
RETURN_GENERATOR = 75,
RETURN_VALUE = 83,
SETUP_ANNOTATIONS = 85,
ASYNC_GEN_WRAP = 87,
POP_EXCEPT = 89,
/* ↓ These opcodes take an arg */
STORE_NAME = 90,
DELETE_NAME = 91,
UNPACK_SEQUENCE = 92,
FOR_ITER = 93,
UNPACK_EX = 94,
STORE_ATTR = 95,
DELETE_ATTR = 96,
STORE_GLOBAL = 97,
DELETE_GLOBAL = 98,
SWAP = 99,
LOAD_CONST = 100,
LOAD_NAME = 101,
BUILD_TUPLE = 102,
BUILD_LIST = 103,
BUILD_SET = 104,
BUILD_MAP = 105, // build a Dict object
LOAD_ATTR = 106,
COMPARE_OP = 107,
IMPORT_NAME = 108,
IMPORT_FROM = 109,
JUMP_FORWARD = 110,
POP_JUMP_FORWARD_IF_FALSE = 114,
POP_JUMP_FORWARD_IF_TRUE = 115,
LOAD_GLOBAL = 116,
IS_OP = 117,
CONTAINS_OP = 118,
RERAISE = 119,
COPY = 120,
RETURN_CONST = 121,
BINARY_OP = 122,
SEND = 123,
LOAD_FAST = 124,
STORE_FAST = 125,
DELETE_FAST = 126,
LOAD_FAST_CHECK = 127,
POP_JUMP_IF_NOT_NONE = 128,
POP_JUMP_IF_NONE = 129,
RAISE_VARARGS = 130,
CALL_FUNCTION = 131,
MAKE_FUNCTION = 132,
BUILD_SLICE = 133,
JUMP_BACKWARD_NO_INTERRUPT = 134,
MAKE_CELL = 135,
LOAD_CLOSURE = 136,
LOAD_DEREF = 137,
STORE_DEREF = 138,
JUMP_BACKWARD = 140,
CALL_FUNCTION_EX = 142,
EXTENDED_ARG = 144,
LIST_APPEND = 145,
SET_ADD = 146,
MAP_ADD = 147,
LOAD_CLASSDEREF = 148,
COPY_FREE_VARS = 149,
RESUME = 151,
MATCH_CLASS = 152,
FORMAT_VALUE = 155,
BUILD_CONST_KEY_MAP = 156,
BUILD_STRING = 157,
LIST_EXTEND = 162,
SET_UPDATE = 163,
DICT_MERGE = 164,
DICT_UPDATE = 165,
CALL = 171,
KW_NAMES = 172,
CALL_INTRINSIC_1 = 173,
CALL_INTRINSIC_2 = 174,
LOAD_FROM_DICT_OR_GLOBALS = 175,
LOAD_FROM_DICT_OR_DEREF = 176,
// Erg-specific opcodes (must have a unary `ERG_`)
// Define in descending order from 219, 255
ERG_POP_NTH = 196,
ERG_PEEK_NTH = 197, // get ref to the arg-th element from TOS
ERG_INC = 198, // name += 1; arg: typecode
ERG_DEC = 199, // name -= 1
ERG_LOAD_FAST_IMMUT = 200,
ERG_STORE_FAST_IMMUT = 201,
ERG_MOVE_FAST = 202,
ERG_CLONE_FAST = 203,
ERG_COPY_FAST = 204,
ERG_REF_FAST = 205,
ERG_REF_MUT_FAST = 206,
ERG_MOVE_OUTER = 207,
ERG_CLONE_OUTER = 208,
ERG_COPY_OUTER = 209,
ERG_REF_OUTER = 210,
ERG_REF_MUT_OUTER = 211,
ERG_LESS_THAN = 212,
ERG_LESS_EQUAL = 213,
ERG_EQUAL = 214,
ERG_NOT_EQUAL = 215,
ERG_MAKE_SLOT = 216,
ERG_MAKE_TYPE = 217,
ERG_MAKE_PURE_FUNCTION = 218,
ERG_CALL_PURE_FUNCTION = 219,
/* ↑ These opcodes take an arg ↑ */
/* ↓ These opcodes take no arg ↓ */
// ... = 220,
ERG_LOAD_EMPTY_SLOT = 242,
ERG_LOAD_EMPTY_STR = 243,
ERG_LOAD_1_NAT = 244,
ERG_LOAD_1_INT = 245,
ERG_LOAD_1_REAL = 246,
ERG_LOAD_NONE = 247,
ERG_MUTATE = 248, // !x
ERG_STORE_SUBSCR = 249, // `[] =` (it doesn't cause any exceptions)
// ... = 250,
ERG_BINARY_SUBSCR = 251, // `= []` (it doesn't cause any exceptions)
ERG_BINARY_RANGE = 252,
// `/?` (rhs may be 0, it may cause a runtime panic)
ERG_TRY_BINARY_DIVIDE = 253,
// `/` (rhs could not be 0, it doesn't cause any exceptions)
ERG_BINARY_TRUE_DIVIDE = 254,
NOT_IMPLEMENTED = 255,
}
impl_u8_enum!{IntrinsicOp;
PRINT = 1,
IMPORT_STAR = 2,
STOPITERATION_ERROR = 3,
ASYNC_GEN_WRAP = 4,
UNARY_POSITIVE = 5,
LIST_TO_TUPLE = 6,
TYPEVAR = 7,
PARAMSPEC = 8,
TYPEVARTUPLE = 9,
SUBSCRIPT_GENERIC = 10,
TYPEALIAS = 11,
}

View file

@ -15,6 +15,7 @@ use erg_common::opcode308::Opcode308;
use erg_common::opcode309::Opcode309;
use erg_common::opcode310::Opcode310;
use erg_common::opcode311::{BinOpCode, Opcode311};
use erg_common::opcode312::{Opcode312, IntrinsicOp};
use erg_common::option_enum_unwrap;
use erg_common::python_util::{env_python_version, PythonVersion};
use erg_common::traits::{Locational, Stream};
@ -795,7 +796,8 @@ impl PyCodeGenerator {
}
StoreLoadKind::Local | StoreLoadKind::LocalConst => match acc_kind {
Name => LOAD_NAME as u8,
UnboundAttr => LOAD_ATTR as u8,
UnboundAttr => Opcode311::LOAD_ATTR as u8,
BoundAttr if self.py_version.minor == Some(12) => Opcode311::LOAD_ATTR as u8,
BoundAttr => LOAD_METHOD as u8,
},
}
@ -926,8 +928,13 @@ impl PyCodeGenerator {
self.write_instr(IMPORT_NAME);
self.write_arg(name.idx);
self.stack_inc();
self.write_instr(IMPORT_STAR);
self.write_arg(0);
if self.py_version.minor == Some(12) {
self.write_instr(Opcode312::CALL_INTRINSIC_1);
self.write_arg(IntrinsicOp::IMPORT_STAR as usize);
} else {
self.write_instr(IMPORT_STAR);
self.write_arg(0);
}
self.stack_dec_n(3);
}
@ -965,7 +972,12 @@ impl PyCodeGenerator {
.unwrap_or_else(|| self.register_attr(escaped));
let instr = self.select_load_instr(name.kind, UnboundAttr);
self.write_instr(instr);
self.write_arg(name.idx);
let idx = if self.py_version.minor == Some(12) {
name.idx << 1
} else {
name.idx
};
self.write_arg(idx);
if self.py_version.minor >= Some(11) {
self.write_bytes(&[0; 8]);
}
@ -979,10 +991,22 @@ impl PyCodeGenerator {
.unwrap_or_else(|| self.register_method(escaped));
let instr = self.select_load_instr(name.kind, acc_kind);
self.write_instr(instr);
self.write_arg(name.idx);
if self.py_version.minor >= Some(11) {
self.stack_inc(); // instead of PUSH_NULL
self.write_bytes(&[0; 20]);
let idx = if self.py_version.minor == Some(12) {
name.idx << 1
} else {
name.idx
};
self.write_arg(idx);
match self.py_version.minor {
Some(12) => {
self.stack_inc(); // instead of PUSH_NULL
self.write_bytes(&[0; 18]);
},
Some(11) => {
self.stack_inc(); // instead of PUSH_NULL
self.write_bytes(&[0; 20]);
}
_ => {}
}
}
@ -1173,13 +1197,23 @@ impl PyCodeGenerator {
}
fn emit_precall_and_call(&mut self, argc: usize) {
self.write_instr(Opcode311::PRECALL);
self.write_arg(argc);
self.write_arg(0);
self.write_arg(0);
if self.py_version.minor == Some(11) {
self.write_instr(Opcode311::PRECALL);
self.write_arg(argc);
self.write_arg(0);
self.write_arg(0);
}
self.write_instr(Opcode311::CALL);
self.write_arg(argc);
self.write_bytes(&[0; 8]);
match self.py_version.minor {
Some(12) => {
self.write_bytes(&[0; 6]);
}
Some(11) => {
self.write_bytes(&[0; 8]);
}
_ => {}
}
self.stack_dec();
}
@ -1823,7 +1857,7 @@ impl PyCodeGenerator {
self.write_arg(0);
self.emit_expr(*bin.rhs);
let arg = match self.py_version.minor {
Some(11) => self.lasti() - idx - 4,
Some(12 | 11) => self.lasti() - idx - 4,
_ => self.lasti(),
};
self.fill_jump(idx + 1, arg);
@ -1839,7 +1873,7 @@ impl PyCodeGenerator {
self.write_arg(0);
self.emit_expr(*bin.rhs);
let arg = match self.py_version.minor {
Some(11) => self.lasti() - idx - 4,
Some(12 | 11) => self.lasti() - idx - 4,
_ => self.lasti(),
};
self.fill_jump(idx + 1, arg);
@ -2054,10 +2088,12 @@ impl PyCodeGenerator {
| TokenKind::Closed
| TokenKind::Open
| TokenKind::ContainsOp => {
self.write_instr(Opcode311::PRECALL);
self.write_arg(2);
self.write_arg(0);
self.write_arg(0);
if self.py_version.minor == Some(11) {
self.write_instr(Opcode311::PRECALL);
self.write_arg(2);
self.write_arg(0);
self.write_arg(0);
}
Opcode311::CALL
}
_ => {
@ -2206,7 +2242,7 @@ impl PyCodeGenerator {
self.write_arg(0);
// else block
let idx_else_begin = match self.py_version.minor {
Some(11) => self.lasti() - idx_pop_jump_if_false - 4,
Some(12 | 11) => self.lasti() - idx_pop_jump_if_false - 4,
Some(7..=10) => self.lasti(),
_ => self.lasti(),
};
@ -2282,7 +2318,7 @@ impl PyCodeGenerator {
self.write_instr(EXTENDED_ARG);
self.write_arg(0);
match self.py_version.minor {
Some(11) => {
Some(12 | 11) => {
self.write_instr(Opcode311::JUMP_BACKWARD);
self.write_arg(0);
self.fill_jump(idx + 1, self.lasti() - idx_for_iter);
@ -2347,7 +2383,7 @@ impl PyCodeGenerator {
self.fill_jump(idx + 1, arg);
self.stack_dec();
let idx_end = match self.py_version.minor {
Some(11) => self.lasti() - idx_while - 3,
Some(12 | 11) => self.lasti() - idx_while - 3,
_ => self.lasti(),
};
self.fill_jump(idx_while + 1, idx_end);
@ -2381,7 +2417,7 @@ impl PyCodeGenerator {
self.stack_dec();
for pop_jump_point in pop_jump_points {
let idx = match self.py_version.minor {
Some(11) => self.lasti() - pop_jump_point,
Some(12 | 11) => self.lasti() - pop_jump_point,
Some(10) => self.lasti() + 4,
_ => self.lasti() + 4,
};
@ -2742,7 +2778,7 @@ impl PyCodeGenerator {
"if" | "if!" => self.emit_if_instr(args),
"match" | "match!" => self.emit_match_instr(args, true),
"with!" => match self.py_version.minor {
Some(11) => self.emit_with_instr_311(args),
Some(12 | 11) => self.emit_with_instr_311(args),
Some(10) => self.emit_with_instr_310(args),
Some(9) => self.emit_with_instr_309(args),
Some(8) => self.emit_with_instr_308(args),
@ -2804,6 +2840,10 @@ impl PyCodeGenerator {
} else {
UnboundAttr
};
if self.py_version.minor == Some(12) {
self.emit_push_null();
self.stack_dec();
}
self.emit_expr(obj);
self.emit_load_method_instr(method_name, kind);
if is_type {
@ -2822,8 +2862,13 @@ impl PyCodeGenerator {
if pos_len > 0 {
self.write_instr(Opcode310::LIST_EXTEND);
self.write_arg(1);
self.write_instr(Opcode310::LIST_TO_TUPLE);
self.write_arg(0);
if self.py_version.minor == Some(12) {
self.write_instr(Opcode312::CALL_INTRINSIC_1);
self.write_arg(IntrinsicOp::LIST_TO_TUPLE as usize);
} else {
self.write_instr(Opcode310::LIST_TO_TUPLE);
self.write_arg(0);
}
}
self.stack_dec();
}
@ -3059,7 +3104,7 @@ impl PyCodeGenerator {
self.write_arg(1);
self.stack_dec();
let idx = match self.py_version.minor {
Some(11) => self.lasti() - pop_jump_point - 4,
Some(12 | 11) => self.lasti() - pop_jump_point - 4,
Some(10) => self.lasti(),
Some(_) => self.lasti(),
_ => todo!(),
@ -3932,6 +3977,10 @@ impl PyCodeGenerator {
Some(Identifier::private("#path")),
)],
);
if self.py_version.minor == Some(12) {
self.emit_push_null();
self.stack_dec();
}
self.emit_load_name_instr(Identifier::private("#path"));
self.emit_load_method_instr(Identifier::static_public("append"), BoundAttr);
self.emit_load_const(erg_core_path().to_str().unwrap());

View file

@ -14,6 +14,7 @@ use erg_common::opcode308::Opcode308;
use erg_common::opcode309::Opcode309;
use erg_common::opcode310::Opcode310;
use erg_common::opcode311::{BinOpCode, Opcode311};
use erg_common::opcode312::Opcode312;
use erg_common::python_util::{env_magic_number, exec_pyc_code, PythonVersion};
use erg_common::serialize::*;
use erg_common::Str;
@ -609,6 +610,7 @@ impl CodeObj {
Some(9) => self.read_instr_309(op, arg, idx, &mut instrs),
Some(10) => self.read_instr_310(op, arg, idx, &mut instrs),
Some(11) => self.read_instr_311(op, arg, idx, &mut instrs),
Some(12) => self.read_instr_312(op, arg, idx, &mut instrs),
_ => {}
}
idx += 2;
@ -628,6 +630,9 @@ impl CodeObj {
self.dump_additional_info(op, arg, idx, instrs);
}
match op308 {
Opcode308::LOAD_ATTR => {
write!(instrs, "{arg} ({})", self.names[arg]).unwrap();
}
Opcode308::STORE_DEREF | Opcode308::LOAD_DEREF => {
write!(
instrs,
@ -676,6 +681,9 @@ impl CodeObj {
self.dump_additional_info(op, arg, idx, instrs);
}
match op309 {
Opcode309::LOAD_ATTR => {
write!(instrs, "{arg} ({})", self.names[arg]).unwrap();
}
Opcode309::STORE_DEREF | Opcode309::LOAD_DEREF => {
write!(
instrs,
@ -724,6 +732,9 @@ impl CodeObj {
self.dump_additional_info(op, arg, idx, instrs);
}
match op310 {
Opcode310::LOAD_ATTR => {
write!(instrs, "{arg} ({})", self.names[arg]).unwrap();
}
Opcode310::STORE_DEREF | Opcode310::LOAD_DEREF => {
write!(
instrs,
@ -774,6 +785,9 @@ impl CodeObj {
self.dump_additional_info(op, arg, idx, instrs);
}
match op311 {
Opcode311::LOAD_ATTR => {
write!(instrs, "{arg} ({})", self.names[arg]).unwrap();
}
Opcode311::STORE_DEREF | Opcode311::LOAD_DEREF => {
write!(instrs, "{arg} ({})", self.varnames[arg]).unwrap();
}
@ -815,6 +829,54 @@ impl CodeObj {
instrs.push('\n');
}
fn read_instr_312(&self, op: &u8, arg: usize, idx: usize, instrs: &mut String) {
let op312 = Opcode312::try_from(*op).unwrap_or_else(|_| panic!("{op}?"));
let s_op = op312.to_string();
write!(instrs, "{idx:>15} {s_op:<26}").unwrap();
if let Ok(op) = CommonOpcode::try_from(*op) {
self.dump_additional_info(op, arg, idx, instrs);
}
match op312 {
Opcode312::LOAD_ATTR => {
write!(instrs, "{arg} ({})", self.names[arg>>1]).unwrap();
}
Opcode312::STORE_DEREF | Opcode312::LOAD_DEREF => {
write!(instrs, "{arg} ({})", self.varnames[arg]).unwrap();
}
Opcode312::MAKE_CELL | Opcode312::LOAD_CLOSURE => {
write!(instrs, "{arg} ({})", self.varnames[arg]).unwrap();
}
Opcode312::POP_JUMP_FORWARD_IF_FALSE | Opcode312::POP_JUMP_FORWARD_IF_TRUE => {
write!(instrs, "{arg} (to {})", idx + arg * 2 + 2).unwrap();
}
Opcode312::JUMP_FORWARD => {
write!(instrs, "{arg} (to {})", idx + arg * 2 + 2).unwrap();
}
Opcode312::JUMP_BACKWARD => {
write!(instrs, "{arg} (to {})", idx - arg * 2 + 2).unwrap();
}
| Opcode312::CALL
| Opcode312::COPY
| Opcode312::SWAP
| Opcode312::COPY_FREE_VARS => {
write!(instrs, "{arg}").unwrap();
}
Opcode312::KW_NAMES => {
write!(instrs, "{arg} ({})", self.consts[arg]).unwrap();
}
Opcode312::BINARY_OP => {
write!(
instrs,
"{arg} ({:?})",
BinOpCode::try_from(arg as u8).unwrap()
)
.unwrap();
}
_ => {}
}
instrs.push('\n');
}
fn dump_additional_info(&self, op: CommonOpcode, arg: usize, idx: usize, instrs: &mut String) {
match op {
CommonOpcode::COMPARE_OP => {
@ -833,8 +895,6 @@ impl CodeObj {
| CommonOpcode::LOAD_NAME
| CommonOpcode::STORE_GLOBAL
| CommonOpcode::LOAD_GLOBAL
| CommonOpcode::STORE_ATTR
| CommonOpcode::LOAD_ATTR
| CommonOpcode::LOAD_METHOD
| CommonOpcode::IMPORT_NAME
| CommonOpcode::IMPORT_FROM => {