Assign opcode ids (#6637)

This commit is contained in:
Shahar Naveh authored and GitHub committed 2026-01-09 22:52:47 +09:00
1 parent 83a0deac25
commit c2bfdf30bd
10 files changed
+404 -812

No files matched your search

+19 -28
View File
@@ -10,7 +10,7 @@ opmap = {
'CACHE': 0,
'BEFORE_ASYNC_WITH': 1,
'BEFORE_WITH': 2,
'RESERVED_3': 3,
'BINARY_OP_INPLACE_ADD_UNICODE': 3,
'BINARY_SLICE': 4,
'BINARY_SUBSCR': 5,
'CHECK_EG_MATCH': 6,
@@ -24,7 +24,7 @@ opmap = {
'FORMAT_SIMPLE': 14,
'FORMAT_WITH_SPEC': 15,
'GET_AITER': 16,
'RESERVED_17': 17,
'RESERVED': 17,
'GET_ANEXT': 18,
'GET_ITER': 19,
'GET_LEN': 20,
@@ -127,36 +127,27 @@ opmap = {
'UNPACK_SEQUENCE': 117,
'YIELD_VALUE': 118,
'BREAK': 119,
'BUILD_LIST_UNPACK': 120,
'BUILD_LIST_FROM_TUPLES': 120,
'BUILD_MAP_FOR_CALL': 121,
'BUILD_SET_UNPACK': 122,
'BUILD_TUPLE_ITER': 123,
'BUILD_TUPLE_UNPACK': 124,
'CALL_METHOD': 125,
'CALL_METHOD_KW': 126,
'BUILD_SET_FROM_TUPLES': 122,
'BUILD_TUPLE_FROM_ITER': 123,
'BUILD_TUPLE_FROM_TUPLES': 124,
'CALL_METHOD_POSITIONAL': 125,
'CALL_METHOD_KEYWORD': 126,
'CALL_METHOD_EX': 127,
'CONTINUE': 128,
'JUMP': 129,
'JUMP_IF_FALSE_OR_POP': 130,
'JUMP_IF_TRUE_OR_POP': 131,
'JUMP_IF_NOT_EXC_MATCH': 132,
'LOAD_CLASSDEREF': 133,
'LOAD_CLOSURE': 134,
'LOAD_METHOD': 135,
'POP_BLOCK': 136,
'REVERSE': 137,
'SET_EXC_INFO': 138,
'SUBSCRIPT': 139,
'UNARY_OP': 140,
'RESERVED_141': 141,
'RESERVED_142': 142,
'RESERVED_143': 143,
'RESERVED_144': 144,
'RESERVED_145': 145,
'RESERVED_146': 146,
'RESERVED_147': 147,
'RESERVED_148': 148,
'JUMP_IF_FALSE_OR_POP': 129,
'JUMP_IF_TRUE_OR_POP': 130,
'JUMP_IF_NOT_EXC_MATCH': 131,
'LOAD_CLASS_DEREF': 132,
'REVERSE': 133,
'SET_EXC_INFO': 134,
'SUBSCRIPT': 135,
'RESUME': 149,
'JUMP': 252,
'LOAD_CLOSURE': 253,
'LOAD_METHOD': 254,
'POP_BLOCK': 255,
}
# CPython 3.13 compatible: opcodes < 44 have no argument
+1
View File
@@ -16,6 +16,7 @@ class OpListTests(unittest.TestCase):
self.assertIsInstance(func(op), bool)
self.assertEqual(func(op), expected)
@unittest.expectedFailure # TODO: RUSTPYTHON; Only supporting u8 ATM
def test_invalid_opcodes(self):
invalid = [-100, -1, 255, 512, 513, 1000]
self.check_bool_function_result(_opcode.is_valid, invalid, False)
+1
View File
@@ -937,6 +937,7 @@ class DisTests(DisTestBase):
def test_boundaries(self):
self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 29 not less than or equal to 20
def test_widths(self):
long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT',
'INSTRUMENTED_CALL_FUNCTION_EX'])
+76 -76
View File
@@ -494,7 +494,7 @@ impl Compiler {
}
ExprContext::Store => {
emit!(self, Instruction::BuildSlice { argc });
emit!(self, Instruction::StoreSubscript);
emit!(self, Instruction::StoreSubscr);
}
_ => unreachable!(),
}
@@ -505,8 +505,8 @@ impl Compiler {
// Emit appropriate instruction based on context
match ctx {
ExprContext::Load => emit!(self, Instruction::Subscript),
ExprContext::Store => emit!(self, Instruction::StoreSubscript),
ExprContext::Del => emit!(self, Instruction::DeleteSubscript),
ExprContext::Store => emit!(self, Instruction::StoreSubscr),
ExprContext::Del => emit!(self, Instruction::DeleteSubscr),
ExprContext::Invalid => {
return Err(self.error(CodegenErrorType::SyntaxError(
"Invalid expression context".to_owned(),
@@ -1013,7 +1013,7 @@ impl Compiler {
// Stack when in FinallyEnd: [..., prev_exc, exc] or
// [..., prev_exc, exc, return_value] if preserve_tos
// Note: No lasti here - it's only pushed for cleanup handler exceptions
// We need to pop: exc, prev_exc (via PopException)
// We need to pop: exc, prev_exc (via PopExcept)
if preserve_tos {
emit!(self, Instruction::Swap { index: 2 });
}
@@ -1021,7 +1021,7 @@ impl Compiler {
if preserve_tos {
emit!(self, Instruction::Swap { index: 2 });
}
emit!(self, Instruction::PopException); // prev_exc is restored
emit!(self, Instruction::PopExcept); // prev_exc is restored
}
FBlockType::With | FBlockType::AsyncWith => {
@@ -1040,7 +1040,7 @@ impl Compiler {
self.emit_load_const(ConstantData::None);
self.emit_load_const(ConstantData::None);
self.emit_load_const(ConstantData::None);
emit!(self, Instruction::CallFunctionPositional { nargs: 3 });
emit!(self, Instruction::Call { nargs: 3 });
// For async with, await the result
if matches!(info.fb_type, FBlockType::AsyncWith) {
@@ -1057,7 +1057,7 @@ impl Compiler {
if preserve_tos {
emit!(self, Instruction::Swap { index: 2 });
}
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
// If there's an exception name, clean it up
if let FBlockDatum::ExceptionName(ref name) = info.fb_datum {
@@ -1342,7 +1342,7 @@ impl Compiler {
}
if Self::find_ann(statements) {
emit!(self, Instruction::SetupAnnotation);
emit!(self, Instruction::SetupAnnotations);
}
self.compile_statements(statements)?;
@@ -1362,7 +1362,7 @@ impl Compiler {
self.symbol_table_stack.push(symbol_table);
if Self::find_ann(body) {
emit!(self, Instruction::SetupAnnotation);
emit!(self, Instruction::SetupAnnotations);
}
if let Some((last, body)) = body.split_last() {
@@ -1594,9 +1594,9 @@ impl Compiler {
NameOp::Name => {
let idx = self.get_global_name_index(&name);
let op = match usage {
NameUsage::Load => Instruction::LoadNameAny,
NameUsage::Store => Instruction::StoreLocal,
NameUsage::Delete => Instruction::DeleteLocal,
NameUsage::Load => Instruction::LoadName,
NameUsage::Store => Instruction::StoreName,
NameUsage::Delete => Instruction::DeleteName,
};
self.emit_arg(idx, op);
}
@@ -1815,7 +1815,7 @@ impl Compiler {
None => bytecode::RaiseKind::BareRaise,
};
self.set_source_range(*range);
emit!(self, Instruction::Raise { kind });
emit!(self, Instruction::RaiseVarargs { kind });
}
Stmt::Try(StmtTry {
body,
@@ -1878,15 +1878,15 @@ impl Compiler {
match msg {
Some(e) => {
self.compile_expression(e)?;
emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
emit!(self, Instruction::Call { nargs: 1 });
}
None => {
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
emit!(self, Instruction::Call { nargs: 0 });
}
}
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::Raise,
}
);
@@ -2102,7 +2102,7 @@ impl Compiler {
fn apply_decorators(&mut self, decorator_list: &[Decorator]) {
// Apply decorators:
for _ in decorator_list {
emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
emit!(self, Instruction::Call { nargs: 1 });
}
}
@@ -2144,7 +2144,7 @@ impl Compiler {
self.make_closure(code, bytecode::MakeFunctionFlags::empty())?;
// Call the function immediately
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
emit!(self, Instruction::Call { nargs: 0 });
Ok(())
}
@@ -2379,7 +2379,7 @@ impl Compiler {
// which then properly restores prev_exc before going to outer handler
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack
}
);
@@ -2391,10 +2391,10 @@ impl Compiler {
if let Some(cleanup) = finally_cleanup_block {
self.switch_to_block(cleanup);
emit!(self, Instruction::CopyItem { index: 3_u32 });
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack
}
);
@@ -2439,7 +2439,7 @@ impl Compiler {
)?;
// Exception is on top of stack now, pushed by unwind_blocks
// PUSH_EXC_INFO transforms [exc] -> [prev_exc, exc] for PopException
// PUSH_EXC_INFO transforms [exc] -> [prev_exc, exc] for PopExcept
emit!(self, Instruction::PushExcInfo);
for handler in handlers {
let ExceptHandler::ExceptHandler(ExceptHandlerExceptHandler {
@@ -2524,7 +2524,7 @@ impl Compiler {
// which does COPY 3; POP_EXCEPT; RERAISE
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack,
}
);
@@ -2537,7 +2537,7 @@ impl Compiler {
// POP_BLOCK (HandlerCleanup) then POP_BLOCK (SETUP_CLEANUP)
// followed by POP_EXCEPT
self.pop_fblock(FBlockType::ExceptionHandler);
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
// Delete the exception variable if it was bound (normal path)
if let Some(alias) = name {
@@ -2577,7 +2577,7 @@ impl Compiler {
// NOTE: We emit RERAISE 0 BEFORE popping fblock so it is within cleanup handler scope
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack,
}
);
@@ -2593,10 +2593,10 @@ impl Compiler {
// RERAISE 1: reraise with lasti
self.switch_to_block(cleanup_block);
emit!(self, Instruction::CopyItem { index: 3_u32 });
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack,
}
);
@@ -2671,7 +2671,7 @@ impl Compiler {
// Stack: [lasti, prev_exc, exc] - exception is on top
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack,
}
);
@@ -2689,11 +2689,11 @@ impl Compiler {
// COPY 3: copy the exception from position 3
emit!(self, Instruction::CopyItem { index: 3_u32 });
// POP_EXCEPT: restore prev_exc as current exception
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
// RERAISE 1: reraise with lasti from stack
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack,
}
);
@@ -2962,7 +2962,7 @@ impl Compiler {
// POP_BLOCK - no-op for us with exception tables (fblocks handle this)
// POP_EXCEPT - restore previous exception context
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
// Stack: []
if !finalbody.is_empty() {
@@ -2981,7 +2981,7 @@ impl Compiler {
// Stack: [result, prev_exc]
// POP_EXCEPT
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
// Stack: [result]
// RERAISE 0
@@ -3317,13 +3317,13 @@ impl Compiler {
);
emit!(
self,
Instruction::CallFunctionPositional {
Instruction::Call {
nargs: num_typeparam_args as u32
}
);
} else {
// No arguments, just call the closure
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
emit!(self, Instruction::Call { nargs: 0 });
}
}
@@ -3561,20 +3561,20 @@ impl Compiler {
let dunder_name = self.name("__name__");
emit!(self, Instruction::LoadGlobal(dunder_name));
let dunder_module = self.name("__module__");
emit!(self, Instruction::StoreLocal(dunder_module));
emit!(self, Instruction::StoreName(dunder_module));
// Store __qualname__
self.emit_load_const(ConstantData::Str {
value: qualname.into(),
});
let qualname_name = self.name("__qualname__");
emit!(self, Instruction::StoreLocal(qualname_name));
emit!(self, Instruction::StoreName(qualname_name));
// Store __doc__ only if there's an explicit docstring
if let Some(doc) = doc_str {
self.emit_load_const(ConstantData::Str { value: doc.into() });
let doc_name = self.name("__doc__");
emit!(self, Instruction::StoreLocal(doc_name));
emit!(self, Instruction::StoreName(doc_name));
}
// Store __firstlineno__ (new in Python 3.12+)
@@ -3582,22 +3582,22 @@ impl Compiler {
value: BigInt::from(firstlineno),
});
let firstlineno_name = self.name("__firstlineno__");
emit!(self, Instruction::StoreLocal(firstlineno_name));
emit!(self, Instruction::StoreName(firstlineno_name));
// Set __type_params__ if we have type parameters
if type_params.is_some() {
// Load .type_params from enclosing scope
let dot_type_params = self.name(".type_params");
emit!(self, Instruction::LoadNameAny(dot_type_params));
emit!(self, Instruction::LoadName(dot_type_params));
// Store as __type_params__
let dunder_type_params = self.name("__type_params__");
emit!(self, Instruction::StoreLocal(dunder_type_params));
emit!(self, Instruction::StoreName(dunder_type_params));
}
// Setup annotations if needed
if Self::find_ann(body) {
emit!(self, Instruction::SetupAnnotation);
emit!(self, Instruction::SetupAnnotations);
}
// 3. Compile the class body
@@ -3617,7 +3617,7 @@ impl Compiler {
emit!(self, Instruction::LoadClosure(classcell_idx.to_u32()));
emit!(self, Instruction::CopyItem { index: 1_u32 });
let classcell = self.name("__classcell__");
emit!(self, Instruction::StoreLocal(classcell));
emit!(self, Instruction::StoreName(classcell));
} else {
self.emit_load_const(ConstantData::None);
}
@@ -3659,7 +3659,7 @@ impl Compiler {
// Compile type parameters and store as .type_params
self.compile_type_params(type_params.unwrap())?;
let dot_type_params = self.name(".type_params");
emit!(self, Instruction::StoreLocal(dot_type_params));
emit!(self, Instruction::StoreName(dot_type_params));
}
// Step 2: Compile class body (always done, whether generic or not)
@@ -3680,21 +3680,21 @@ impl Compiler {
let dot_generic_base = self.name(".generic_base");
// Create .generic_base
emit!(self, Instruction::LoadNameAny(dot_type_params));
emit!(self, Instruction::LoadName(dot_type_params));
emit!(
self,
Instruction::CallIntrinsic1 {
func: bytecode::IntrinsicFunction1::SubscriptGeneric
}
);
emit!(self, Instruction::StoreLocal(dot_generic_base));
emit!(self, Instruction::StoreName(dot_generic_base));
// Generate class creation code
emit!(self, Instruction::LoadBuildClass);
// Set up the class function with type params
let mut func_flags = bytecode::MakeFunctionFlags::empty();
emit!(self, Instruction::LoadNameAny(dot_type_params));
emit!(self, Instruction::LoadName(dot_type_params));
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
// Create class function with closure
@@ -3712,7 +3712,7 @@ impl Compiler {
};
// Load .generic_base as the last base
emit!(self, Instruction::LoadNameAny(dot_generic_base));
emit!(self, Instruction::LoadName(dot_generic_base));
let nargs = 2 + u32::try_from(base_count).expect("too many base classes") + 1; // function, name, bases..., generic_base
@@ -3730,14 +3730,14 @@ impl Compiler {
}
emit!(
self,
Instruction::CallFunctionKeyword {
Instruction::CallKw {
nargs: nargs
+ u32::try_from(arguments.keywords.len())
.expect("too many keyword arguments")
}
);
} else {
emit!(self, Instruction::CallFunctionPositional { nargs });
emit!(self, Instruction::Call { nargs });
}
// Return the created class
@@ -3748,7 +3748,7 @@ impl Compiler {
// Execute the type params function
self.make_closure(type_params_code, bytecode::MakeFunctionFlags::empty())?;
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
emit!(self, Instruction::Call { nargs: 0 });
} else {
// Non-generic class: standard path
emit!(self, Instruction::LoadBuildClass);
@@ -3915,7 +3915,7 @@ impl Compiler {
self.emit_load_const(ConstantData::None);
self.emit_load_const(ConstantData::None);
self.emit_load_const(ConstantData::None);
emit!(self, Instruction::CallFunctionPositional { nargs: 3 });
emit!(self, Instruction::Call { nargs: 3 });
if is_async {
emit!(self, Instruction::GetAwaitable);
self.emit_load_const(ConstantData::None);
@@ -3991,7 +3991,7 @@ impl Compiler {
// Need to pop: True, exc, prev_exc, __exit__
self.switch_to_block(suppress_block);
emit!(self, Instruction::PopTop); // pop True (TO_BOOL result)
emit!(self, Instruction::PopException); // pop exc and restore prev_exc
emit!(self, Instruction::PopExcept); // pop exc and restore prev_exc
emit!(self, Instruction::PopTop); // pop __exit__
emit!(self, Instruction::PopTop); // pop lasti
emit!(
@@ -4013,7 +4013,7 @@ impl Compiler {
// If we cleared fblock, exceptions here would propagate uncaught.
self.switch_to_block(cleanup_block);
emit!(self, Instruction::CopyItem { index: 3 });
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
emit!(self, Instruction::Reraise { depth: 1 });
// ===== After block =====
@@ -4335,7 +4335,7 @@ impl Compiler {
);
}
// Use BINARY_OP/NB_SUBSCR to extract the element.
emit!(self, Instruction::BinarySubscript);
emit!(self, Instruction::BinarySubscr);
// Compile the subpattern in irrefutable mode.
self.compile_pattern_subpattern(pattern, pc)?;
}
@@ -4588,7 +4588,7 @@ impl Compiler {
// Stack: [subject, len, size]
emit!(
self,
Instruction::CompareOperation {
Instruction::CompareOp {
op: ComparisonOperator::GreaterOrEqual
}
);
@@ -4714,7 +4714,7 @@ impl Compiler {
// Stack: [rest_dict, k1, ..., kn, rest_dict]
emit!(self, Instruction::Swap { index: 2 });
// Stack: [rest_dict, k1, ..., kn-1, rest_dict, kn]
emit!(self, Instruction::DeleteSubscript);
emit!(self, Instruction::DeleteSubscr);
// Stack: [rest_dict, k1, ..., kn-1] (removed kn from rest_dict)
remaining -= 1;
}
@@ -4892,7 +4892,7 @@ impl Compiler {
self.emit_load_const(ConstantData::Integer { value: size.into() });
emit!(
self,
Instruction::CompareOperation {
Instruction::CompareOp {
op: ComparisonOperator::Equal
}
);
@@ -4905,7 +4905,7 @@ impl Compiler {
});
emit!(
self,
Instruction::CompareOperation {
Instruction::CompareOp {
op: ComparisonOperator::GreaterOrEqual
}
);
@@ -4934,7 +4934,7 @@ impl Compiler {
self.compile_expression(&p.value)?;
emit!(
self,
Instruction::CompareOperation {
Instruction::CompareOp {
op: bytecode::ComparisonOperator::Equal
}
);
@@ -5078,13 +5078,13 @@ impl Compiler {
fn compile_addcompare(&mut self, op: &CmpOp) {
use bytecode::ComparisonOperator::*;
match op {
CmpOp::Eq => emit!(self, Instruction::CompareOperation { op: Equal }),
CmpOp::NotEq => emit!(self, Instruction::CompareOperation { op: NotEqual }),
CmpOp::Lt => emit!(self, Instruction::CompareOperation { op: Less }),
CmpOp::LtE => emit!(self, Instruction::CompareOperation { op: LessOrEqual }),
CmpOp::Gt => emit!(self, Instruction::CompareOperation { op: Greater }),
CmpOp::Eq => emit!(self, Instruction::CompareOp { op: Equal }),
CmpOp::NotEq => emit!(self, Instruction::CompareOp { op: NotEqual }),
CmpOp::Lt => emit!(self, Instruction::CompareOp { op: Less }),
CmpOp::LtE => emit!(self, Instruction::CompareOp { op: LessOrEqual }),
CmpOp::Gt => emit!(self, Instruction::CompareOp { op: Greater }),
CmpOp::GtE => {
emit!(self, Instruction::CompareOperation { op: GreaterOrEqual })
emit!(self, Instruction::CompareOp { op: GreaterOrEqual })
}
CmpOp::In => emit!(self, Instruction::ContainsOp(Invert::No)),
CmpOp::NotIn => emit!(self, Instruction::ContainsOp(Invert::Yes)),
@@ -5219,11 +5219,11 @@ impl Compiler {
if let Expr::Name(ExprName { id, .. }) = &target {
// Store as dict entry in __annotations__ dict:
let annotations = self.name("__annotations__");
emit!(self, Instruction::LoadNameAny(annotations));
emit!(self, Instruction::LoadName(annotations));
self.emit_load_const(ConstantData::Str {
value: self.mangle(id.as_str()).into_owned().into(),
});
emit!(self, Instruction::StoreSubscript);
emit!(self, Instruction::StoreSubscr);
} else {
// Drop annotation if not assigned to simple identifier.
emit!(self, Instruction::PopTop);
@@ -5360,7 +5360,7 @@ impl Compiler {
// stack: CONTAINER SLICE RESULT
emit!(self, Instruction::Swap { index: 3 });
emit!(self, Instruction::Swap { index: 2 });
emit!(self, Instruction::StoreSubscript);
emit!(self, Instruction::StoreSubscr);
}
AugAssignKind::Attr { idx } => {
// stack: CONTAINER RESULT
@@ -6108,9 +6108,9 @@ impl Compiler {
fn compile_normal_call(&mut self, ty: CallType) {
match ty {
CallType::Positional { nargs } => {
emit!(self, Instruction::CallFunctionPositional { nargs })
emit!(self, Instruction::Call { nargs })
}
CallType::Keyword { nargs } => emit!(self, Instruction::CallFunctionKeyword { nargs }),
CallType::Keyword { nargs } => emit!(self, Instruction::CallKw { nargs }),
CallType::Ex { has_kwargs } => emit!(self, Instruction::CallFunctionEx { has_kwargs }),
}
}
@@ -6422,7 +6422,7 @@ impl Compiler {
};
// Call just created <listcomp> function:
emit!(self, Instruction::CallFunctionPositional { nargs: 1 });
emit!(self, Instruction::Call { nargs: 1 });
if is_async_list_set_dict_comprehension {
emit!(self, Instruction::GetAwaitable);
self.emit_load_const(ConstantData::None);
@@ -6622,7 +6622,7 @@ impl Compiler {
// Re-raise the exception
emit!(
self,
Instruction::Raise {
Instruction::RaiseVarargs {
kind: bytecode::RaiseKind::ReraiseFromStack
}
);
@@ -6841,7 +6841,7 @@ impl Compiler {
self.emit_load_const(ConstantData::None);
self.emit_load_const(ConstantData::None);
self.emit_load_const(ConstantData::None);
emit!(self, Instruction::CallFunctionPositional { nargs: 3 });
emit!(self, Instruction::Call { nargs: 3 });
if is_async {
emit!(self, Instruction::GetAwaitable);
@@ -6852,7 +6852,7 @@ impl Compiler {
emit!(self, Instruction::PopTop);
}
UnwindAction::HandlerCleanup => {
emit!(self, Instruction::PopException);
emit!(self, Instruction::PopExcept);
}
UnwindAction::FinallyTry { body, fblock_idx } => {
// compile finally body inline
@@ -6871,9 +6871,9 @@ impl Compiler {
UnwindAction::FinallyEnd => {
// Stack when in FinallyEnd: [..., prev_exc, exc]
// Note: No lasti here - it's only pushed for cleanup handler exceptions
// We need to pop: exc, prev_exc (via PopException)
// We need to pop: exc, prev_exc (via PopExcept)
emit!(self, Instruction::PopTop); // exc
emit!(self, Instruction::PopException); // prev_exc is restored
emit!(self, Instruction::PopExcept); // prev_exc is restored
}
UnwindAction::PopValue => {
// Pop the return value - continue/break cancels the pending return
+234 -426
View File
@@ -676,441 +676,287 @@ pub type NameIdx = u32;
#[repr(u8)]
pub enum Instruction {
// ==================== No-argument instructions (opcode < 44) ====================
// 0: CACHE - placeholder for inline cache (not executed)
Cache,
// 1: BEFORE_ASYNC_WITH
BeforeAsyncWith,
// 2: BEFORE_WITH
BeforeWith,
// 3: Reserved (BINARY_OP_INPLACE_ADD_UNICODE in CPython)
Reserved3,
// 4: BINARY_SLICE - not implemented, placeholder
BinarySlice,
// 5: BINARY_SUBSCR
BinarySubscript,
// 6: CHECK_EG_MATCH
CheckEgMatch,
// 7: CHECK_EXC_MATCH
CheckExcMatch,
// 8: CLEANUP_THROW
CleanupThrow,
// 9: DELETE_SUBSCR
DeleteSubscript,
// 10: END_ASYNC_FOR
EndAsyncFor,
// 11: END_FOR - not implemented, placeholder
EndFor,
// 12: END_SEND
EndSend,
// 13: EXIT_INIT_CHECK - not implemented, placeholder
ExitInitCheck,
// 14: FORMAT_SIMPLE
FormatSimple,
// 15: FORMAT_WITH_SPEC
FormatWithSpec,
// 16: GET_AITER
GetAIter,
// 17: RESERVED
Reserved17,
// 18: GET_ANEXT
GetANext,
// 19: GET_ITER
GetIter,
// 20: GET_LEN
GetLen,
// 21: GET_YIELD_FROM_ITER - not implemented, placeholder
GetYieldFromIter,
// 22: INTERPRETER_EXIT - not implemented, placeholder
InterpreterExit,
// 23: LOAD_ASSERTION_ERROR - not implemented, placeholder
LoadAssertionError,
// 24: LOAD_BUILD_CLASS
LoadBuildClass,
// 25: LOAD_LOCALS - not implemented, placeholder
LoadLocals,
// 26: MAKE_FUNCTION
MakeFunction,
// 27: MATCH_KEYS
MatchKeys,
// 28: MATCH_MAPPING
MatchMapping,
// 29: MATCH_SEQUENCE
MatchSequence,
// 30: NOP
Nop,
// 31: POP_EXCEPT
PopException,
// 32: POP_TOP
PopTop,
// 33: PUSH_EXC_INFO
PushExcInfo,
// 34: PUSH_NULL - not implemented, placeholder
PushNull,
// 35: RETURN_GENERATOR - not implemented, placeholder
ReturnGenerator,
// 36: RETURN_VALUE
ReturnValue,
// 37: SETUP_ANNOTATIONS
SetupAnnotation,
// 38: STORE_SLICE - not implemented, placeholder
StoreSlice,
// 39: STORE_SUBSCR
StoreSubscript,
// 40: TO_BOOL
ToBool,
// 41: UNARY_INVERT
UnaryInvert,
// 42: UNARY_NEGATIVE
UnaryNegative,
// 43: UNARY_NOT
UnaryNot,
// ==================== With-argument instructions (opcode >= 44) ====================
// 44: WITH_EXCEPT_START
WithExceptStart,
// 45: BINARY_OP
Cache = 0, // Placeholder
BeforeAsyncWith = 1,
BeforeWith = 2,
BinaryOpInplaceAddUnicode = 3, // Placeholder
BinarySlice = 4, // Placeholder
BinarySubscr = 5,
CheckEgMatch = 6,
CheckExcMatch = 7,
CleanupThrow = 8,
DeleteSubscr = 9,
EndAsyncFor = 10,
EndFor = 11, // Placeholder
EndSend = 12,
ExitInitCheck = 13, // Placeholder
FormatSimple = 14,
FormatWithSpec = 15,
GetAIter = 16,
Reserved = 17,
GetANext = 18,
GetIter = 19,
GetLen = 20,
GetYieldFromIter = 21,
InterpreterExit = 22, // Placeholder
LoadAssertionError = 23, // Placeholder
LoadBuildClass = 24,
LoadLocals = 25, // Placeholder
MakeFunction = 26,
MatchKeys = 27,
MatchMapping = 28,
MatchSequence = 29,
Nop = 30,
PopExcept = 31,
PopTop = 32,
PushExcInfo = 33,
PushNull = 34, // Placeholder
ReturnGenerator = 35, // Placeholder
ReturnValue = 36,
SetupAnnotations = 37,
StoreSlice = 38, // Placeholder
StoreSubscr = 39,
ToBool = 40,
UnaryInvert = 41,
UnaryNegative = 42,
UnaryNot = 43,
WithExceptStart = 44,
// ==================== With-argument instructions (opcode > 44) ====================
BinaryOp {
op: Arg<BinaryOperator>,
},
// 46: BUILD_CONST_KEY_MAP - not implemented, placeholder
} = 45,
BuildConstKeyMap {
size: Arg<u32>,
},
// 47: BUILD_LIST
} = 46, // Placeholder
BuildList {
size: Arg<u32>,
},
// 48: BUILD_MAP
} = 47,
BuildMap {
size: Arg<u32>,
},
// 49: BUILD_SET
} = 48,
BuildSet {
size: Arg<u32>,
},
// 50: BUILD_SLICE
} = 49,
BuildSlice {
argc: Arg<BuildSliceArgCount>,
},
// 51: BUILD_STRING
} = 50,
BuildString {
size: Arg<u32>,
},
// 52: BUILD_TUPLE
} = 51,
BuildTuple {
size: Arg<u32>,
},
// 53: CALL
CallFunctionPositional {
} = 52,
Call {
nargs: Arg<u32>,
},
// 54: CALL_FUNCTION_EX
} = 53,
CallFunctionEx {
has_kwargs: Arg<bool>,
},
// 55: CALL_INTRINSIC_1
} = 54,
CallIntrinsic1 {
func: Arg<IntrinsicFunction1>,
},
// 56: CALL_INTRINSIC_2
} = 55,
CallIntrinsic2 {
func: Arg<IntrinsicFunction2>,
},
// 57: CALL_KW
CallFunctionKeyword {
} = 56,
CallKw {
nargs: Arg<u32>,
},
// 58: COMPARE_OP
CompareOperation {
} = 57,
CompareOp {
op: Arg<ComparisonOperator>,
},
// 59: CONTAINS_OP
ContainsOp(Arg<Invert>),
// 60: CONVERT_VALUE
} = 58,
ContainsOp(Arg<Invert>) = 59,
ConvertValue {
oparg: Arg<ConvertValueOparg>,
},
// 61: COPY
} = 60,
CopyItem {
index: Arg<u32>,
},
// 62: COPY_FREE_VARS - not implemented, placeholder
} = 61,
CopyFreeVars {
count: Arg<u32>,
},
// 63: DELETE_ATTR
} = 62, // Placeholder
DeleteAttr {
idx: Arg<NameIdx>,
},
// 64: DELETE_DEREF
DeleteDeref(Arg<NameIdx>),
// 65: DELETE_FAST
DeleteFast(Arg<NameIdx>),
// 66: DELETE_GLOBAL
DeleteGlobal(Arg<NameIdx>),
// 67: DELETE_NAME
DeleteLocal(Arg<NameIdx>),
// 68: DICT_MERGE - not implemented, placeholder
} = 63,
DeleteDeref(Arg<NameIdx>) = 64,
DeleteFast(Arg<NameIdx>) = 65,
DeleteGlobal(Arg<NameIdx>) = 66,
DeleteName(Arg<NameIdx>) = 67,
DictMerge {
index: Arg<u32>,
},
// 69: DICT_UPDATE
} = 68, // Placeholder
DictUpdate {
index: Arg<u32>,
},
// 70: ENTER_EXECUTOR - not implemented, placeholder
EnterExecutor {
index: Arg<u32>,
},
// 71: EXTENDED_ARG
ExtendedArg,
// 72: FOR_ITER
} = 69,
EnterExecutor = 70, // Placeholder
ExtendedArg = 71,
ForIter {
target: Arg<Label>,
},
// 73: GET_AWAITABLE
GetAwaitable,
// 74: IMPORT_FROM
} = 72,
GetAwaitable = 73, // TODO: Make this instruction to hold an oparg
ImportFrom {
idx: Arg<NameIdx>,
},
// 75: IMPORT_NAME
} = 74,
ImportName {
idx: Arg<NameIdx>,
},
// 76: IS_OP
IsOp(Arg<Invert>),
// 77: JUMP_BACKWARD - not implemented, placeholder
} = 75,
IsOp(Arg<Invert>) = 76,
JumpBackward {
target: Arg<Label>,
},
// 78: JUMP_BACKWARD_NO_INTERRUPT - not implemented, placeholder
} = 77, // Placeholder
JumpBackwardNoInterrupt {
target: Arg<Label>,
},
// 79: JUMP_FORWARD - not implemented, placeholder
} = 78, // Placeholder
JumpForward {
target: Arg<Label>,
},
// 80: LIST_APPEND
} = 79, // Placeholder
ListAppend {
i: Arg<u32>,
},
// 81: LIST_EXTEND - not implemented, placeholder
} = 80,
ListExtend {
i: Arg<u32>,
},
// 82: LOAD_ATTR
} = 81, // Placeholder
LoadAttr {
idx: Arg<NameIdx>,
},
// 83: LOAD_CONST
} = 82,
LoadConst {
idx: Arg<u32>,
},
// 84: LOAD_DEREF
LoadDeref(Arg<NameIdx>),
// 85: LOAD_FAST
LoadFast(Arg<NameIdx>),
// 86: LOAD_FAST_AND_CLEAR
LoadFastAndClear(Arg<NameIdx>),
// 87: LOAD_FAST_CHECK - not implemented, placeholder
LoadFastCheck(Arg<NameIdx>),
// 88: LOAD_FAST_LOAD_FAST - not implemented, placeholder
} = 83,
LoadDeref(Arg<NameIdx>) = 84,
LoadFast(Arg<NameIdx>) = 85,
LoadFastAndClear(Arg<NameIdx>) = 86,
LoadFastCheck(Arg<NameIdx>) = 87, // Placeholder
LoadFastLoadFast {
arg: Arg<u32>,
},
// 89: LOAD_FROM_DICT_OR_DEREF - not implemented, placeholder
LoadFromDictOrDeref(Arg<NameIdx>),
// 90: LOAD_FROM_DICT_OR_GLOBALS - not implemented, placeholder
LoadFromDictOrGlobals(Arg<NameIdx>),
// 91: LOAD_GLOBAL
LoadGlobal(Arg<NameIdx>),
// 92: LOAD_NAME
LoadNameAny(Arg<NameIdx>),
// 93: LOAD_SUPER_ATTR - not implemented, placeholder
} = 88, // Placeholder
LoadFromDictOrDeref(Arg<NameIdx>) = 89, // Placeholder
LoadFromDictOrGlobals(Arg<NameIdx>) = 90, // Placeholder
LoadGlobal(Arg<NameIdx>) = 91,
LoadName(Arg<NameIdx>) = 92,
LoadSuperAttr {
arg: Arg<u32>,
},
// 94: MAKE_CELL - not implemented, placeholder
MakeCell(Arg<NameIdx>),
// 95: MAP_ADD
} = 93, // Placeholder
MakeCell(Arg<NameIdx>) = 94, // Placeholder
MapAdd {
i: Arg<u32>,
},
// 96: MATCH_CLASS
MatchClass(Arg<u32>),
// 97: POP_JUMP_IF_FALSE
} = 95,
MatchClass(Arg<u32>) = 96,
PopJumpIfFalse {
target: Arg<Label>,
},
// 98: POP_JUMP_IF_NONE - not implemented, placeholder
} = 97,
PopJumpIfNone {
target: Arg<Label>,
},
// 99: POP_JUMP_IF_NOT_NONE - not implemented, placeholder
} = 98, // Placeholder
PopJumpIfNotNone {
target: Arg<Label>,
},
// 100: POP_JUMP_IF_TRUE
} = 99, // Placeholder
PopJumpIfTrue {
target: Arg<Label>,
},
// 101: RAISE_VARARGS
Raise {
} = 100,
RaiseVarargs {
kind: Arg<RaiseKind>,
},
// 102: RERAISE
} = 101,
Reraise {
depth: Arg<u32>,
},
// 103: RETURN_CONST
} = 102,
ReturnConst {
idx: Arg<u32>,
},
// 104: SEND
} = 103,
Send {
target: Arg<Label>,
},
// 105: SET_ADD
} = 104,
SetAdd {
i: Arg<u32>,
},
// 106: SET_FUNCTION_ATTRIBUTE
} = 105,
SetFunctionAttribute {
attr: Arg<MakeFunctionFlags>,
},
// 107: SET_UPDATE - not implemented, placeholder
} = 106,
SetUpdate {
i: Arg<u32>,
},
// 108: STORE_ATTR
} = 107, // Placeholder
StoreAttr {
idx: Arg<NameIdx>,
},
// 109: STORE_DEREF
StoreDeref(Arg<NameIdx>),
// 110: STORE_FAST
StoreFast(Arg<NameIdx>),
// 111: STORE_FAST_LOAD_FAST
} = 108,
StoreDeref(Arg<NameIdx>) = 109,
StoreFast(Arg<NameIdx>) = 110,
StoreFastLoadFast {
store_idx: Arg<NameIdx>,
load_idx: Arg<NameIdx>,
},
// 112: STORE_FAST_STORE_FAST - not implemented, placeholder
} = 111,
StoreFastStoreFast {
arg: Arg<u32>,
},
// 113: STORE_GLOBAL
StoreGlobal(Arg<NameIdx>),
// 114: STORE_NAME
StoreLocal(Arg<NameIdx>),
// 115: SWAP
} = 112, // Placeholder
StoreGlobal(Arg<NameIdx>) = 113,
StoreName(Arg<NameIdx>) = 114,
Swap {
index: Arg<u32>,
},
// 116: UNPACK_EX
} = 115,
UnpackEx {
args: Arg<UnpackExArgs>,
},
// 117: UNPACK_SEQUENCE
} = 116,
UnpackSequence {
size: Arg<u32>,
},
// 118: YIELD_VALUE
} = 117,
YieldValue {
arg: Arg<u32>,
},
// ==================== RustPython-only instructions (119+) ====================
// 119: BREAK
Break {
target: Arg<Label>,
},
// 120: BUILD_LIST_FROM_TUPLES
BuildListFromTuples {
size: Arg<u32>,
},
// 121: BUILD_MAP_FOR_CALL
BuildMapForCall {
size: Arg<u32>,
},
// 122: BUILD_SET_FROM_TUPLES
BuildSetFromTuples {
size: Arg<u32>,
},
// 123: BUILD_TUPLE_FROM_ITER
BuildTupleFromIter,
// 124: BUILD_TUPLE_FROM_TUPLES
BuildTupleFromTuples {
size: Arg<u32>,
},
// 125: CALL_METHOD
CallMethodPositional {
nargs: Arg<u32>,
},
// 126: CALL_METHOD_KW
CallMethodKeyword {
nargs: Arg<u32>,
},
// 127: CALL_METHOD_EX
CallMethodEx {
has_kwargs: Arg<bool>,
},
// 128: CONTINUE
Continue {
target: Arg<Label>,
},
// 129: JUMP (CPython uses pseudo-op 256)
Jump {
target: Arg<Label>,
},
// 130: JUMP_IF_FALSE_OR_POP
JumpIfFalseOrPop {
target: Arg<Label>,
},
// 131: JUMP_IF_TRUE_OR_POP
JumpIfTrueOrPop {
target: Arg<Label>,
},
// 132: JUMP_IF_NOT_EXC_MATCH
JumpIfNotExcMatch(Arg<Label>),
// 133: LOAD_CLASSDEREF
LoadClassDeref(Arg<NameIdx>),
// 134: LOAD_CLOSURE (CPython uses pseudo-op 258)
LoadClosure(Arg<NameIdx>),
// 135: LOAD_METHOD (CPython uses pseudo-op 259)
LoadMethod {
idx: Arg<NameIdx>,
},
// 136: POP_BLOCK (CPython uses pseudo-op 263)
PopBlock,
// 137: REVERSE
Reverse {
amount: Arg<u32>,
},
// 138: SET_EXC_INFO
SetExcInfo,
// 139: SUBSCRIPT
Subscript,
// 140-148: Reserved (padding to keep RESUME at 149)
Reserved140,
Reserved141,
Reserved142,
Reserved143,
Reserved144,
Reserved145,
Reserved146,
Reserved147,
Reserved148,
// 149: RESUME
} = 118,
Resume {
arg: Arg<u32>,
},
// If you add a new instruction here, be sure to keep LAST_INSTRUCTION updated
} = 149,
// ==================== RustPython-only instructions (119-135) ====================
// Ideally, we want to be fully aligned with CPython opcodes, but we still have some leftovers.
// So we assign random IDs to these opcodes.
Break {
target: Arg<Label>,
} = 119,
BuildListFromTuples {
size: Arg<u32>,
} = 120,
BuildMapForCall {
size: Arg<u32>,
} = 121,
BuildSetFromTuples {
size: Arg<u32>,
} = 122,
BuildTupleFromIter = 123,
BuildTupleFromTuples {
size: Arg<u32>,
} = 124,
CallMethodPositional {
nargs: Arg<u32>,
} = 125,
CallMethodKeyword {
nargs: Arg<u32>,
} = 126,
CallMethodEx {
has_kwargs: Arg<bool>,
} = 127,
Continue {
target: Arg<Label>,
} = 128,
JumpIfFalseOrPop {
target: Arg<Label>,
} = 129,
JumpIfTrueOrPop {
target: Arg<Label>,
} = 130,
JumpIfNotExcMatch(Arg<Label>) = 131,
LoadClassDeref(Arg<NameIdx>) = 132,
Reverse {
amount: Arg<u32>,
} = 133,
SetExcInfo = 134,
Subscript = 135,
// ===== Pseudo Opcodes (252+) ======
Jump {
target: Arg<Label>,
} = 252, // CPython uses pseudo-op 256
LoadClosure(Arg<NameIdx>) = 253, // CPython uses pseudo-op 258
LoadMethod {
idx: Arg<NameIdx>,
} = 254, // CPython uses pseudo-op 259
PopBlock = 255, // CPython uses pseudo-op 263
}
// This must be kept up to date to avoid marshaling errors
const LAST_INSTRUCTION: Instruction = Instruction::Resume { arg: Arg::marker() };
const _: () = assert!(mem::size_of::<Instruction>() == 1);
impl From<Instruction> for u8 {
@@ -1126,10 +972,29 @@ impl TryFrom<u8> for Instruction {
#[inline]
fn try_from(value: u8) -> Result<Self, MarshalError> {
if value <= u8::from(LAST_INSTRUCTION) {
let cpython_start = u8::from(Self::Cache);
let cpython_end = u8::from(Self::YieldValue { arg: Arg::marker() });
let resume_id = u8::from(Self::Resume { arg: Arg::marker() });
let custom_start = u8::from(Self::Break {
target: Arg::marker(),
});
let custom_end = u8::from(Self::Subscript);
let pseudo_start = u8::from(Self::Jump {
target: Arg::marker(),
});
let pseudo_end = u8::from(Self::PopBlock);
if (cpython_start..=cpython_end).contains(&value)
|| value == resume_id
|| (custom_start..=custom_end).contains(&value)
|| (pseudo_start..=pseudo_end).contains(&value)
{
Ok(unsafe { core::mem::transmute::<u8, Self>(value) })
} else {
Err(MarshalError::InvalidBytecode)
Err(Self::Error::InvalidBytecode)
}
}
}
@@ -1857,13 +1722,7 @@ impl Instruction {
| ForIter { target: l }
| Break { target: l }
| Continue { target: l }
| Send { target: l }
// Dummy jump instructions (placeholders)
| JumpBackward { target: l }
| JumpBackwardNoInterrupt { target: l }
| JumpForward { target: l }
| PopJumpIfNone { target: l }
| PopJumpIfNotNone { target: l } => Some(*l),
| Send { target: l } => Some(*l),
_ => None,
}
}
@@ -1885,7 +1744,7 @@ impl Instruction {
| Break { .. }
| ReturnValue
| ReturnConst { .. }
| Raise { .. }
| RaiseVarargs { .. }
| Reraise { .. }
)
}
@@ -1903,47 +1762,25 @@ impl Instruction {
///
pub fn stack_effect(&self, arg: OpArg, jump: bool) -> i32 {
match self {
// Dummy/placeholder instructions (never executed)
Cache | Reserved3 | Reserved17 | Reserved140 | Reserved141 | Reserved142
| Reserved143 | Reserved144 | Reserved145 | Reserved146 | Reserved147 | Reserved148 => {
0
}
BinarySlice | EndFor | ExitInitCheck | GetYieldFromIter | InterpreterExit
| LoadAssertionError | LoadLocals | PushNull | ReturnGenerator | StoreSlice => 0,
BuildConstKeyMap { .. }
| CopyFreeVars { .. }
| DictMerge { .. }
| EnterExecutor { .. }
| ListExtend { .. }
| LoadFastCheck(_)
| LoadFastLoadFast { .. }
| LoadFromDictOrDeref(_)
| LoadFromDictOrGlobals(_)
| LoadSuperAttr { .. }
| MakeCell(_)
| SetUpdate { .. }
| StoreFastStoreFast { .. } => 0,
JumpBackward { .. } | JumpBackwardNoInterrupt { .. } | JumpForward { .. } => 0,
PopJumpIfNone { .. } | PopJumpIfNotNone { .. } => -1,
Nop => 0,
ImportName { .. } => -1,
ImportFrom { .. } => 1,
LoadFast(_) | LoadFastAndClear(_) | LoadNameAny(_) | LoadGlobal(_) | LoadDeref(_)
LoadFast(_) | LoadFastAndClear(_) | LoadName(_) | LoadGlobal(_) | LoadDeref(_)
| LoadClassDeref(_) => 1,
StoreFast(_) | StoreLocal(_) | StoreGlobal(_) | StoreDeref(_) => -1,
StoreFast(_) | StoreName(_) | StoreGlobal(_) | StoreDeref(_) => -1,
StoreFastLoadFast { .. } => 0, // pop 1, push 1
DeleteFast(_) | DeleteLocal(_) | DeleteGlobal(_) | DeleteDeref(_) => 0,
DeleteFast(_) | DeleteName(_) | DeleteGlobal(_) | DeleteDeref(_) => 0,
LoadClosure(_) => 1,
Subscript => -1,
StoreSubscript => -3,
DeleteSubscript => -2,
StoreSubscr => -3,
DeleteSubscr => -2,
LoadAttr { .. } => 0,
StoreAttr { .. } => -2,
DeleteAttr { .. } => -1,
LoadConst { .. } => 1,
BinaryOp { .. } | CompareOperation { .. } => -1,
BinarySubscript => -1,
Reserved => 0,
BinaryOp { .. } | CompareOp { .. } => -1,
BinarySubscr => -1,
CopyItem { .. } => 1,
PopTop => -1,
Swap { .. } => 0,
@@ -1971,9 +1808,9 @@ impl Instruction {
// pops attribute value and function, pushes function back
-2 + 1
}
CallFunctionPositional { nargs } => -(nargs.get(arg) as i32) - 1 + 1,
Call { nargs } => -(nargs.get(arg) as i32) - 1 + 1,
CallMethodPositional { nargs } => -(nargs.get(arg) as i32) - 3 + 1,
CallFunctionKeyword { nargs } => -1 - (nargs.get(arg) as i32) - 1 + 1,
CallKw { nargs } => -1 - (nargs.get(arg) as i32) - 1 + 1,
CallMethodKeyword { nargs } => -1 - (nargs.get(arg) as i32) - 3 + 1,
CallFunctionEx { has_kwargs } => -1 - (has_kwargs.get(arg) as i32) - 1 + 1,
CallMethodEx { has_kwargs } => -1 - (has_kwargs.get(arg) as i32) - 3 + 1,
@@ -2005,11 +1842,11 @@ impl Instruction {
PushExcInfo => 1, // [exc] -> [prev_exc, exc]
CheckExcMatch => 0, // [exc, type] -> [exc, bool] (pops type, pushes bool)
Reraise { .. } => 0, // Exception raised, stack effect doesn't matter
SetupAnnotation => 0,
SetupAnnotations => 0,
BeforeWith => 1, // push __exit__, then replace ctx_mgr with __enter__ result
WithExceptStart => 1, // push __exit__ result
PopBlock => 0,
Raise { kind } => {
RaiseVarargs { kind } => {
// Stack effects for different raise kinds:
// - Reraise (0): gets from VM state, no stack pop
// - Raise (1): pops 1 exception
@@ -2057,7 +1894,7 @@ impl Instruction {
let UnpackExArgs { before, after } = args.get(arg);
-1 + before as i32 + 1 + after as i32
}
PopException => 0,
PopExcept => 0,
Reverse { .. } => 0,
GetAwaitable => 0,
BeforeAsyncWith => 1,
@@ -2071,6 +1908,8 @@ impl Instruction {
UnaryInvert => 0,
UnaryNegative => 0,
UnaryNot => 0,
GetYieldFromIter => 0,
_ => 0,
}
}
@@ -2141,47 +1980,10 @@ impl Instruction {
};
match self {
// Dummy/placeholder instructions
Cache => w!(CACHE),
Reserved3 | Reserved17 | Reserved140 | Reserved141 | Reserved142 | Reserved143
| Reserved144 | Reserved145 | Reserved146 | Reserved147 | Reserved148 => w!(RESERVED),
BinarySlice => w!(BINARY_SLICE),
EndFor => w!(END_FOR),
ExitInitCheck => w!(EXIT_INIT_CHECK),
GetYieldFromIter => w!(GET_YIELD_FROM_ITER),
InterpreterExit => w!(INTERPRETER_EXIT),
LoadAssertionError => w!(LOAD_ASSERTION_ERROR),
LoadLocals => w!(LOAD_LOCALS),
PushNull => w!(PUSH_NULL),
ReturnGenerator => w!(RETURN_GENERATOR),
StoreSlice => w!(STORE_SLICE),
UnaryInvert => w!(UNARY_INVERT),
UnaryNegative => w!(UNARY_NEGATIVE),
UnaryNot => w!(UNARY_NOT),
BuildConstKeyMap { size } => w!(BUILD_CONST_KEY_MAP, size),
CopyFreeVars { count } => w!(COPY_FREE_VARS, count),
DictMerge { index } => w!(DICT_MERGE, index),
EnterExecutor { index } => w!(ENTER_EXECUTOR, index),
JumpBackward { target } => w!(JUMP_BACKWARD, target),
JumpBackwardNoInterrupt { target } => w!(JUMP_BACKWARD_NO_INTERRUPT, target),
JumpForward { target } => w!(JUMP_FORWARD, target),
ListExtend { i } => w!(LIST_EXTEND, i),
LoadFastCheck(idx) => w!(LOAD_FAST_CHECK, varname = idx),
LoadFastLoadFast { arg } => w!(LOAD_FAST_LOAD_FAST, arg),
LoadFromDictOrDeref(idx) => w!(LOAD_FROM_DICT_OR_DEREF, cell_name = idx),
LoadFromDictOrGlobals(idx) => w!(LOAD_FROM_DICT_OR_GLOBALS, name = idx),
LoadSuperAttr { arg } => w!(LOAD_SUPER_ATTR, arg),
MakeCell(idx) => w!(MAKE_CELL, cell_name = idx),
PopJumpIfNone { target } => w!(POP_JUMP_IF_NONE, target),
PopJumpIfNotNone { target } => w!(POP_JUMP_IF_NOT_NONE, target),
SetUpdate { i } => w!(SET_UPDATE, i),
StoreFastStoreFast { arg } => w!(STORE_FAST_STORE_FAST, arg),
// Real instructions
BeforeAsyncWith => w!(BEFORE_ASYNC_WITH),
BeforeWith => w!(BEFORE_WITH),
BinaryOp { op } => write!(f, "{:pad$}({})", "BINARY_OP", op.get(arg)),
BinarySubscript => w!(BINARY_SUBSCR),
BinarySubscr => w!(BINARY_SUBSCR),
Break { target } => w!(BREAK, target),
BuildList { size } => w!(BUILD_LIST, size),
BuildListFromTuples { size } => w!(BUILD_LIST_FROM_TUPLES, size),
@@ -2194,9 +1996,9 @@ impl Instruction {
BuildTuple { size } => w!(BUILD_TUPLE, size),
BuildTupleFromIter => w!(BUILD_TUPLE_FROM_ITER),
BuildTupleFromTuples { size } => w!(BUILD_TUPLE_FROM_TUPLES, size),
Call { nargs } => w!(CALL, nargs),
CallFunctionEx { has_kwargs } => w!(CALL_FUNCTION_EX, has_kwargs),
CallFunctionKeyword { nargs } => w!(CALL_KW, nargs),
CallFunctionPositional { nargs } => w!(CALL, nargs),
CallKw { nargs } => w!(CALL_KW, nargs),
CallIntrinsic1 { func } => w!(CALL_INTRINSIC_1, ?func),
CallIntrinsic2 { func } => w!(CALL_INTRINSIC_2, ?func),
CallMethodEx { has_kwargs } => w!(CALL_METHOD_EX, has_kwargs),
@@ -2205,7 +2007,7 @@ impl Instruction {
CheckEgMatch => w!(CHECK_EG_MATCH),
CheckExcMatch => w!(CHECK_EXC_MATCH),
CleanupThrow => w!(CLEANUP_THROW),
CompareOperation { op } => w!(COMPARE_OP, ?op),
CompareOp { op } => w!(COMPARE_OP, ?op),
ContainsOp(inv) => w!(CONTAINS_OP, ?inv),
Continue { target } => w!(CONTINUE, target),
ConvertValue { oparg } => write!(f, "{:pad$}{}", "CONVERT_VALUE", oparg.get(arg)),
@@ -2214,8 +2016,8 @@ impl Instruction {
DeleteDeref(idx) => w!(DELETE_DEREF, cell_name = idx),
DeleteFast(idx) => w!(DELETE_FAST, varname = idx),
DeleteGlobal(idx) => w!(DELETE_GLOBAL, name = idx),
DeleteLocal(idx) => w!(DELETE_NAME, name = idx),
DeleteSubscript => w!(DELETE_SUBSCR),
DeleteName(idx) => w!(DELETE_NAME, name = idx),
DeleteSubscr => w!(DELETE_SUBSCR),
DictUpdate { index } => w!(DICT_UPDATE, index),
EndAsyncFor => w!(END_ASYNC_FOR),
EndSend => w!(END_SEND),
@@ -2226,6 +2028,7 @@ impl Instruction {
GetAIter => w!(GET_AITER),
GetANext => w!(GET_ANEXT),
GetAwaitable => w!(GET_AWAITABLE),
Reserved => w!(RESERVED),
GetIter => w!(GET_ITER),
GetLen => w!(GET_LEN),
ImportFrom { idx } => w!(IMPORT_FROM, name = idx),
@@ -2246,7 +2049,7 @@ impl Instruction {
LoadFastAndClear(idx) => w!(LOAD_FAST_AND_CLEAR, varname = idx),
LoadGlobal(idx) => w!(LOAD_GLOBAL, name = idx),
LoadMethod { idx } => w!(LOAD_METHOD, name = idx),
LoadNameAny(idx) => w!(LOAD_NAME, name = idx),
LoadName(idx) => w!(LOAD_NAME, name = idx),
MakeFunction => w!(MAKE_FUNCTION),
MapAdd { i } => w!(MAP_ADD, i),
MatchClass(arg) => w!(MATCH_CLASS, arg),
@@ -2255,12 +2058,12 @@ impl Instruction {
MatchSequence => w!(MATCH_SEQUENCE),
Nop => w!(NOP),
PopBlock => w!(POP_BLOCK),
PopException => w!(POP_EXCEPT),
PopExcept => w!(POP_EXCEPT),
PopJumpIfFalse { target } => w!(POP_JUMP_IF_FALSE, target),
PopJumpIfTrue { target } => w!(POP_JUMP_IF_TRUE, target),
PopTop => w!(POP_TOP),
PushExcInfo => w!(PUSH_EXC_INFO),
Raise { kind } => w!(RAISE_VARARGS, ?kind),
RaiseVarargs { kind } => w!(RAISE_VARARGS, ?kind),
Reraise { depth } => w!(RERAISE, depth),
Resume { arg } => w!(RESUME, arg),
ReturnConst { idx } => fmt_const("RETURN_CONST", arg, f, idx),
@@ -2270,7 +2073,7 @@ impl Instruction {
SetAdd { i } => w!(SET_ADD, i),
SetExcInfo => w!(SET_EXC_INFO),
SetFunctionAttribute { attr } => w!(SET_FUNCTION_ATTRIBUTE, ?attr),
SetupAnnotation => w!(SETUP_ANNOTATIONS),
SetupAnnotations => w!(SETUP_ANNOTATIONS),
StoreAttr { idx } => w!(STORE_ATTR, name = idx),
StoreDeref(idx) => w!(STORE_DEREF, cell_name = idx),
StoreFast(idx) => w!(STORE_FAST, varname = idx),
@@ -2282,15 +2085,20 @@ impl Instruction {
write!(f, " ({}, {})", store_idx.get(arg), load_idx.get(arg))
}
StoreGlobal(idx) => w!(STORE_GLOBAL, name = idx),
StoreLocal(idx) => w!(STORE_NAME, name = idx),
StoreSubscript => w!(STORE_SUBSCR),
StoreName(idx) => w!(STORE_NAME, name = idx),
StoreSubscr => w!(STORE_SUBSCR),
Subscript => w!(SUBSCRIPT),
Swap { index } => w!(SWAP, index),
ToBool => w!(TO_BOOL),
UnpackEx { args } => w!(UNPACK_EX, args),
UnpackSequence { size } => w!(UNPACK_SEQUENCE, size),
WithExceptStart => w!(WITH_EXCEPT_START),
UnaryInvert => w!(UNARY_INVERT),
UnaryNegative => w!(UNARY_NEGATIVE),
UnaryNot => w!(UNARY_NOT),
YieldValue { arg } => w!(YIELD_VALUE, arg),
GetYieldFromIter => w!(GET_YIELD_FROM_ITER),
_ => w!(RUSTPYTHON_PLACEHOLDER),
}
}
}
+2 -2
View File
@@ -454,7 +454,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
self.stack.push(JitValue::Tuple(elements));
Ok(())
}
Instruction::CallFunctionPositional { nargs } => {
Instruction::Call { nargs } => {
let nargs = nargs.get(arg);
let mut args = Vec::new();
@@ -489,7 +489,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
_ => Err(JitCompileError::NotSupported),
}
}
Instruction::CompareOperation { op, .. } => {
Instruction::CompareOp { op, .. } => {
let op = op.get(arg);
// the rhs is popped off first
let b = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
+2 -2
View File
@@ -96,10 +96,10 @@ impl StackMachine {
let idx = idx.get(arg);
self.stack.push(constants[idx as usize].clone().into())
}
Instruction::LoadNameAny(idx) => self
Instruction::LoadName(idx) => self
.stack
.push(StackValue::String(names[idx.get(arg) as usize].clone())),
Instruction::StoreLocal(idx) => {
Instruction::StoreName(idx) => {
let idx = idx.get(arg);
self.locals
.insert(names[idx as usize].clone(), self.stack.pop().unwrap());
+3 -5
View File
@@ -69,16 +69,16 @@ mod opcode {
Instruction::try_from(opcode as u8),
Ok(Instruction::DeleteAttr { .. }
| Instruction::DeleteGlobal(_)
| Instruction::DeleteLocal(_)
| Instruction::DeleteName(_)
| Instruction::ImportFrom { .. }
| Instruction::ImportName { .. }
| Instruction::LoadAttr { .. }
| Instruction::LoadGlobal(_)
| Instruction::LoadMethod { .. }
| Instruction::LoadNameAny(_)
| Instruction::LoadName(_)
| Instruction::StoreAttr { .. }
| Instruction::StoreGlobal(_)
| Instruction::StoreLocal(_))
| Instruction::StoreName(_))
)
}
@@ -97,8 +97,6 @@ mod opcode {
| Instruction::Jump { .. }
| Instruction::PopJumpIfFalse { .. }
| Instruction::PopJumpIfTrue { .. }
| Instruction::PopJumpIfNone { .. }
| Instruction::PopJumpIfNotNone { .. }
| Instruction::Send { .. })
)
}
+15 -57
View File
@@ -391,7 +391,7 @@ impl ExecutingFrame<'_> {
// Instruction::Reraise are reraise operations that should not add
// new traceback entries
let is_reraise = match op {
bytecode::Instruction::Raise { kind } => matches!(
bytecode::Instruction::RaiseVarargs { kind } => matches!(
kind.get(arg),
bytecode::RaiseKind::BareRaise | bytecode::RaiseKind::ReraiseFromStack
),
@@ -610,7 +610,7 @@ impl ExecutingFrame<'_> {
Ok(None)
}
bytecode::Instruction::BinaryOp { op } => self.execute_bin_op(vm, op.get(arg)),
bytecode::Instruction::BinarySubscript => {
bytecode::Instruction::BinarySubscr => {
let key = self.pop_value();
let container = self.pop_value();
self.state
@@ -711,11 +711,11 @@ impl ExecutingFrame<'_> {
let args = self.collect_ex_args(vm, has_kwargs.get(arg))?;
self.execute_call(args, vm)
}
bytecode::Instruction::CallFunctionKeyword { nargs } => {
bytecode::Instruction::CallKw { nargs } => {
let args = self.collect_keyword_args(nargs.get(arg));
self.execute_call(args, vm)
}
bytecode::Instruction::CallFunctionPositional { nargs } => {
bytecode::Instruction::Call { nargs } => {
let args = self.collect_positional_args(nargs.get(arg));
self.execute_call(args, vm)
}
@@ -753,7 +753,7 @@ impl ExecutingFrame<'_> {
self.push_value(matched);
Ok(None)
}
bytecode::Instruction::CompareOperation { op } => self.execute_compare(vm, op.get(arg)),
bytecode::Instruction::CompareOp { op } => self.execute_compare(vm, op.get(arg)),
bytecode::Instruction::ContainsOp(invert) => {
let b = self.pop_value();
let a = self.pop_value();
@@ -822,7 +822,7 @@ impl ExecutingFrame<'_> {
}
Ok(None)
}
bytecode::Instruction::DeleteLocal(idx) => {
bytecode::Instruction::DeleteName(idx) => {
let name = self.code.names[idx.get(arg) as usize];
let res = self.locals.mapping().ass_subscript(name, None, vm);
@@ -835,7 +835,7 @@ impl ExecutingFrame<'_> {
}
Ok(None)
}
bytecode::Instruction::DeleteSubscript => self.execute_delete_subscript(vm),
bytecode::Instruction::DeleteSubscr => self.execute_delete_subscript(vm),
bytecode::Instruction::DictUpdate { index } => {
// Stack before: [..., dict, ..., source] (source at TOS)
// Stack after: [..., dict, ...] (source consumed)
@@ -1192,7 +1192,7 @@ impl ExecutingFrame<'_> {
self.push_value(func);
Ok(None)
}
bytecode::Instruction::LoadNameAny(idx) => {
bytecode::Instruction::LoadName(idx) => {
let name = self.code.names[idx.get(arg) as usize];
let result = self.locals.mapping().subscript(name, vm);
match result {
@@ -1428,7 +1428,7 @@ impl ExecutingFrame<'_> {
bytecode::Instruction::Nop => Ok(None),
// PopBlock is now a pseudo-instruction - exception table handles this
bytecode::Instruction::PopBlock => Ok(None),
bytecode::Instruction::PopException => {
bytecode::Instruction::PopExcept => {
// Pop prev_exc from value stack and restore it
let prev_exc = self.pop_value();
if vm.is_none(&prev_exc) {
@@ -1457,7 +1457,7 @@ impl ExecutingFrame<'_> {
self.pop_value();
Ok(None)
}
bytecode::Instruction::Raise { kind } => self.execute_raise(vm, kind.get(arg)),
bytecode::Instruction::RaiseVarargs { kind } => self.execute_raise(vm, kind.get(arg)),
bytecode::Instruction::Resume { arg: resume_arg } => {
// Resume execution after yield, await, or at function start
// In CPython, this checks instrumentation and eval breaker
@@ -1559,7 +1559,7 @@ impl ExecutingFrame<'_> {
bytecode::Instruction::SetFunctionAttribute { attr } => {
self.execute_set_function_attribute(vm, attr.get(arg))
}
bytecode::Instruction::SetupAnnotation => self.setup_annotations(vm),
bytecode::Instruction::SetupAnnotations => self.setup_annotations(vm),
bytecode::Instruction::BeforeWith => {
// TOS: context_manager
// Result: [..., __exit__, __enter__ result]
@@ -1621,13 +1621,13 @@ impl ExecutingFrame<'_> {
.set_item(self.code.names[idx.get(arg) as usize], value, vm)?;
Ok(None)
}
bytecode::Instruction::StoreLocal(idx) => {
bytecode::Instruction::StoreName(idx) => {
let name = self.code.names[idx.get(arg) as usize];
let value = self.pop_value();
self.locals.mapping().ass_subscript(name, Some(value), vm)?;
Ok(None)
}
bytecode::Instruction::StoreSubscript => self.execute_store_subscript(vm),
bytecode::Instruction::StoreSubscr => self.execute_store_subscript(vm),
bytecode::Instruction::Subscript => self.execute_subscript(vm),
bytecode::Instruction::Swap { index } => {
let len = self.state.stack.len();
@@ -1779,50 +1779,8 @@ impl ExecutingFrame<'_> {
self.push_value(vm.ctx.new_bool(!value).into());
Ok(None)
}
// Placeholder/dummy instructions - these should never be executed
bytecode::Instruction::Cache
| bytecode::Instruction::Reserved3
| bytecode::Instruction::Reserved17
| bytecode::Instruction::BinarySlice
| bytecode::Instruction::EndFor
| bytecode::Instruction::ExitInitCheck
| bytecode::Instruction::InterpreterExit
| bytecode::Instruction::LoadAssertionError
| bytecode::Instruction::LoadLocals
| bytecode::Instruction::PushNull
| bytecode::Instruction::ReturnGenerator
| bytecode::Instruction::StoreSlice
| bytecode::Instruction::BuildConstKeyMap { .. }
| bytecode::Instruction::CopyFreeVars { .. }
| bytecode::Instruction::DictMerge { .. }
| bytecode::Instruction::EnterExecutor { .. }
| bytecode::Instruction::JumpBackward { .. }
| bytecode::Instruction::JumpBackwardNoInterrupt { .. }
| bytecode::Instruction::JumpForward { .. }
| bytecode::Instruction::ListExtend { .. }
| bytecode::Instruction::LoadFastCheck(_)
| bytecode::Instruction::LoadFastLoadFast { .. }
| bytecode::Instruction::LoadFromDictOrDeref(_)
| bytecode::Instruction::LoadFromDictOrGlobals(_)
| bytecode::Instruction::LoadSuperAttr { .. }
| bytecode::Instruction::MakeCell(_)
| bytecode::Instruction::PopJumpIfNone { .. }
| bytecode::Instruction::PopJumpIfNotNone { .. }
| bytecode::Instruction::SetUpdate { .. }
| bytecode::Instruction::StoreFastStoreFast { .. }
| bytecode::Instruction::Reserved140
| bytecode::Instruction::Reserved141
| bytecode::Instruction::Reserved142
| bytecode::Instruction::Reserved143
| bytecode::Instruction::Reserved144
| bytecode::Instruction::Reserved145
| bytecode::Instruction::Reserved146
| bytecode::Instruction::Reserved147
| bytecode::Instruction::Reserved148 => {
unreachable!(
"placeholder instruction should not be executed: {:?}",
instruction
)
_ => {
unreachable!("{instruction:?} instruction should not be executed")
}
}
}
+51 -216
View File
@@ -1,208 +1,60 @@
"""Generate _opcode_metadata.py for RustPython bytecode.
"""
Generate Lib/_opcode_metadata.py for RustPython bytecode.
This file generates opcode metadata that is compatible with CPython 3.13.
RustPython's Instruction enum is now ordered to match CPython opcode numbers exactly.
"""
import itertools
import pathlib
import re
import typing
# Read the bytecode.rs file to get instruction names
with open("crates/compiler-core/src/bytecode.rs", "r") as f:
content = f.read()
# Find the Instruction enum
match = re.search(r"pub enum Instruction \{(.+?)\n\}", content, re.DOTALL)
if not match:
raise ValueError("Could not find Instruction enum")
enum_body = match.group(1)
# Extract variant names
variants = []
for line in enum_body.split("\n"):
if line.strip().startswith("///") or line.strip().startswith("//"):
continue
m = re.match(r"^\s+([A-Z][a-zA-Z0-9]*)", line)
if m:
variants.append(m.group(1))
print(f"Found {len(variants)} instruction variants")
# Map RustPython variant names to CPython-compatible names
# The opcode number is the index in the Instruction enum
name_mapping = {
# Dummy/placeholder instructions
"Cache": "CACHE",
"Reserved3": "RESERVED",
"Reserved17": "RESERVED",
"Reserved141": "RESERVED",
"Reserved142": "RESERVED",
"Reserved143": "RESERVED",
"Reserved144": "RESERVED",
"Reserved145": "RESERVED",
"Reserved146": "RESERVED",
"Reserved147": "RESERVED",
"Reserved148": "RESERVED",
"BinarySlice": "BINARY_SLICE",
"EndFor": "END_FOR",
"ExitInitCheck": "EXIT_INIT_CHECK",
"GetYieldFromIter": "GET_YIELD_FROM_ITER",
"InterpreterExit": "INTERPRETER_EXIT",
"LoadAssertionError": "LOAD_ASSERTION_ERROR",
"LoadLocals": "LOAD_LOCALS",
"PushNull": "PUSH_NULL",
"ReturnGenerator": "RETURN_GENERATOR",
"StoreSlice": "STORE_SLICE",
"UnaryInvert": "UNARY_INVERT",
"UnaryNegative": "UNARY_NEGATIVE",
"UnaryNot": "UNARY_NOT",
"BuildConstKeyMap": "BUILD_CONST_KEY_MAP",
"CopyFreeVars": "COPY_FREE_VARS",
"DictMerge": "DICT_MERGE",
"EnterExecutor": "ENTER_EXECUTOR",
"JumpBackward": "JUMP_BACKWARD",
"JumpBackwardNoInterrupt": "JUMP_BACKWARD_NO_INTERRUPT",
"JumpForward": "JUMP_FORWARD",
"ListExtend": "LIST_EXTEND",
"LoadFastCheck": "LOAD_FAST_CHECK",
"LoadFastLoadFast": "LOAD_FAST_LOAD_FAST",
"LoadFromDictOrDeref": "LOAD_FROM_DICT_OR_DEREF",
"LoadFromDictOrGlobals": "LOAD_FROM_DICT_OR_GLOBALS",
"LoadSuperAttr": "LOAD_SUPER_ATTR",
"MakeCell": "MAKE_CELL",
"PopJumpIfNone": "POP_JUMP_IF_NONE",
"PopJumpIfNotNone": "POP_JUMP_IF_NOT_NONE",
"SetUpdate": "SET_UPDATE",
"StoreFastStoreFast": "STORE_FAST_STORE_FAST",
# Real instructions
"BeforeAsyncWith": "BEFORE_ASYNC_WITH",
"BeforeWith": "BEFORE_WITH",
"BinaryOp": "BINARY_OP",
"BinarySubscript": "BINARY_SUBSCR",
"Break": "BREAK",
"BuildList": "BUILD_LIST",
"BuildListFromTuples": "BUILD_LIST_UNPACK",
"BuildMap": "BUILD_MAP",
"BuildMapForCall": "BUILD_MAP_FOR_CALL",
"BuildSet": "BUILD_SET",
"BuildSetFromTuples": "BUILD_SET_UNPACK",
"BuildSlice": "BUILD_SLICE",
"BuildString": "BUILD_STRING",
"BuildTuple": "BUILD_TUPLE",
"BuildTupleFromIter": "BUILD_TUPLE_ITER",
"BuildTupleFromTuples": "BUILD_TUPLE_UNPACK",
"CallFunctionEx": "CALL_FUNCTION_EX",
"CallFunctionKeyword": "CALL_KW",
"CallFunctionPositional": "CALL",
"CallIntrinsic1": "CALL_INTRINSIC_1",
"CallIntrinsic2": "CALL_INTRINSIC_2",
"CallMethodEx": "CALL_METHOD_EX",
"CallMethodKeyword": "CALL_METHOD_KW",
"CallMethodPositional": "CALL_METHOD",
"CheckEgMatch": "CHECK_EG_MATCH",
"CheckExcMatch": "CHECK_EXC_MATCH",
"CleanupThrow": "CLEANUP_THROW",
"CompareOperation": "COMPARE_OP",
"ContainsOp": "CONTAINS_OP",
"Continue": "CONTINUE",
"ConvertValue": "CONVERT_VALUE",
"CopyItem": "COPY",
"DeleteAttr": "DELETE_ATTR",
"DeleteDeref": "DELETE_DEREF",
"DeleteFast": "DELETE_FAST",
"DeleteGlobal": "DELETE_GLOBAL",
"DeleteLocal": "DELETE_NAME",
"DeleteSubscript": "DELETE_SUBSCR",
"DictUpdate": "DICT_UPDATE",
"EndAsyncFor": "END_ASYNC_FOR",
"EndSend": "END_SEND",
"ExtendedArg": "EXTENDED_ARG",
"ForIter": "FOR_ITER",
"FormatSimple": "FORMAT_SIMPLE",
"FormatWithSpec": "FORMAT_WITH_SPEC",
"GetAIter": "GET_AITER",
"GetANext": "GET_ANEXT",
"GetAwaitable": "GET_AWAITABLE",
"GetIter": "GET_ITER",
"GetLen": "GET_LEN",
"ImportFrom": "IMPORT_FROM",
"ImportName": "IMPORT_NAME",
"IsOp": "IS_OP",
"Jump": "JUMP",
"JumpIfFalseOrPop": "JUMP_IF_FALSE_OR_POP",
"JumpIfNotExcMatch": "JUMP_IF_NOT_EXC_MATCH",
"JumpIfTrueOrPop": "JUMP_IF_TRUE_OR_POP",
"ListAppend": "LIST_APPEND",
"LoadAttr": "LOAD_ATTR",
"LoadBuildClass": "LOAD_BUILD_CLASS",
"LoadClassDeref": "LOAD_CLASSDEREF",
"LoadClosure": "LOAD_CLOSURE",
"LoadConst": "LOAD_CONST",
"LoadDeref": "LOAD_DEREF",
"LoadFast": "LOAD_FAST",
"LoadFastAndClear": "LOAD_FAST_AND_CLEAR",
"LoadGlobal": "LOAD_GLOBAL",
"LoadMethod": "LOAD_METHOD",
"LoadNameAny": "LOAD_NAME",
"MakeFunction": "MAKE_FUNCTION",
"MapAdd": "MAP_ADD",
"MatchClass": "MATCH_CLASS",
"MatchKeys": "MATCH_KEYS",
"MatchMapping": "MATCH_MAPPING",
"MatchSequence": "MATCH_SEQUENCE",
"Nop": "NOP",
"PopBlock": "POP_BLOCK",
"PopException": "POP_EXCEPT",
"PopJumpIfFalse": "POP_JUMP_IF_FALSE",
"PopJumpIfTrue": "POP_JUMP_IF_TRUE",
"PopTop": "POP_TOP",
"PushExcInfo": "PUSH_EXC_INFO",
"Raise": "RAISE_VARARGS",
"Reraise": "RERAISE",
"Resume": "RESUME",
"ReturnConst": "RETURN_CONST",
"ReturnValue": "RETURN_VALUE",
"Reverse": "REVERSE",
"Send": "SEND",
"SetAdd": "SET_ADD",
"SetExcInfo": "SET_EXC_INFO",
"SetFunctionAttribute": "SET_FUNCTION_ATTRIBUTE",
"SetupAnnotation": "SETUP_ANNOTATIONS",
"StoreAttr": "STORE_ATTR",
"StoreDeref": "STORE_DEREF",
"StoreFast": "STORE_FAST",
"StoreFastLoadFast": "STORE_FAST_LOAD_FAST",
"StoreGlobal": "STORE_GLOBAL",
"StoreLocal": "STORE_NAME",
"StoreSubscript": "STORE_SUBSCR",
"Subscript": "SUBSCRIPT",
"Swap": "SWAP",
"ToBool": "TO_BOOL",
"UnaryOperation": "UNARY_OP",
"UnpackEx": "UNPACK_EX",
"UnpackSequence": "UNPACK_SEQUENCE",
"WithExceptStart": "WITH_EXCEPT_START",
"YieldValue": "YIELD_VALUE",
}
# Build opmap with RustPython instruction indices
opmap = {}
rust_to_cpython_name = {}
for i, variant in enumerate(variants):
cpython_name = name_mapping.get(variant, variant.upper())
# Skip adding duplicates (RESERVED appears multiple times)
if cpython_name == "RESERVED":
# Use unique names for reserved slots
cpython_name = f"RESERVED_{i}"
if cpython_name not in opmap:
opmap[cpython_name] = i
rust_to_cpython_name[variant] = cpython_name
ROOT = pathlib.Path(__file__).parents[1]
BYTECODE_FILE = ROOT / "crates" / "compiler-core" / "src" / "bytecode.rs"
OPCODE_METADATA_FILE = ROOT / "Lib" / "_opcode_metadata.py"
# Find specific instruction indices for categorization
def find_opcode(cpython_name):
return opmap.get(cpython_name, -1)
class Opcode(typing.NamedTuple):
rust_name: str
id: int
@property
def cpython_name(self) -> str:
if self.rust_name == "CopyItem":
return "COPY"
name = self.rust_name
name = re.sub(r"(?<=[a-z0-9])([A-Z])", r"_\1", name)
return re.sub(r"(\D)(\d+)$", r"\1_\2", name).upper()
return re.sub(r"(?<=[a-z0-9])([A-Z])", r"_\1", self.rust_name).upper()
return re.sub(r"(?<!^)(?=[A-Z])", "_", self.rust_name).upper()
@classmethod
def from_str(cls, body: str):
raw_variants = re.split(r"(\d+),", body.strip())
raw_variants.remove("")
for raw_name, raw_id in itertools.batched(raw_variants, 2):
name = re.findall(r"\b[A-Z][A-Za-z]*\d*\b(?=\s*[\({=])", raw_name)[0]
yield cls(rust_name=name.strip(), id=int(raw_id))
def __lt__(self, other: typing.Self) -> bool:
return self.id < other.id
def extract_enum_body(contents: str) -> str:
res = re.search(r"pub enum Instruction \{(.+?)\n\}", contents, re.DOTALL)
if not res:
raise ValueError("Could not find Instruction enum")
return "\n".join(
line.split("//")[0].strip() # Remove any comment. i.e. "foo // some comment"
for line in res.group(1).splitlines()
if not line.strip().startswith("//") # Ignore comment lines
)
contents = BYTECODE_FILE.read_text()
enum_body = extract_enum_body(contents)
opcodes = list(Opcode.from_str(enum_body))
# Generate the output file
output = """# This file is generated by scripts/generate_opcode_metadata.py
@@ -216,8 +68,8 @@ _specialized_opmap = {}
opmap = {
"""
for name, num in sorted(opmap.items(), key=lambda x: x[1]):
output += f" '{name}': {num},\n"
for opcode in sorted(opcodes):
output += f" '{opcode.cpython_name}': {opcode.id},\n"
output += """}
@@ -226,21 +78,4 @@ HAVE_ARGUMENT = 44
MIN_INSTRUMENTED_OPCODE = 236
"""
with open("Lib/_opcode_metadata.py", "w") as f:
f.write(output)
print("Generated Lib/_opcode_metadata.py")
print("\nKey opcode indices (matching CPython 3.13):")
print(f" CACHE = {find_opcode('CACHE')} (expected: 0)")
print(f" BEFORE_ASYNC_WITH = {find_opcode('BEFORE_ASYNC_WITH')} (expected: 1)")
print(f" BINARY_SUBSCR = {find_opcode('BINARY_SUBSCR')} (expected: 5)")
print(
f" WITH_EXCEPT_START = {find_opcode('WITH_EXCEPT_START')} (expected: 44, HAVE_ARGUMENT)"
)
print(f" BINARY_OP = {find_opcode('BINARY_OP')} (expected: 45)")
print(f" LOAD_CONST = {find_opcode('LOAD_CONST')} (expected: 83)")
print(f" LOAD_FAST = {find_opcode('LOAD_FAST')} (expected: 85)")
print(f" LOAD_GLOBAL = {find_opcode('LOAD_GLOBAL')} (expected: 91)")
print(f" STORE_FAST = {find_opcode('STORE_FAST')} (expected: 110)")
print(f" YIELD_VALUE = {find_opcode('YIELD_VALUE')} (expected: 118)")
print(f" RESUME = {find_opcode('RESUME')} (expected: 149)")
OPCODE_METADATA_FILE.write_text(output)