mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Assign opcode ids (#6637)
This commit is contained in:
1 parent
83a0deac25
commit
c2bfdf30bd
10 files changed
+404
-812
No files matched your search
Vendored
+19
-28
@@ -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
|
||||
|
||||
Vendored
+1
@@ -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)
|
||||
|
||||
Vendored
+1
@@ -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'])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
Reference in new issue
Block a user