From d56fcd0774c27c0be5ab051f16da1823b60496c7 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 8 Aug 2025 15:06:14 +0900 Subject: [PATCH] DictUpdate instruction --- compiler/codegen/src/compile.rs | 2 +- compiler/core/src/bytecode.rs | 8 +++++--- vm/src/frame.rs | 32 +++++++++++++++++++++++--------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index c481d44908..73dfed218d 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -4398,7 +4398,7 @@ impl Compiler { for item in unpacked { self.compile_expression(&item.value)?; - emit!(self, Instruction::DictUpdate); + emit!(self, Instruction::DictUpdate { index: 1 }); } Ok(()) diff --git a/compiler/core/src/bytecode.rs b/compiler/core/src/bytecode.rs index 8e8104234f..c5b64fe789 100644 --- a/compiler/core/src/bytecode.rs +++ b/compiler/core/src/bytecode.rs @@ -667,7 +667,9 @@ pub enum Instruction { BuildMapForCall { size: Arg, }, - DictUpdate, + DictUpdate { + index: Arg, + }, BuildSlice { /// whether build a slice with a third step argument step: Arg, @@ -1397,7 +1399,7 @@ impl Instruction { let nargs = size.get(arg); -(nargs as i32) + 1 } - DictUpdate => -1, + DictUpdate { .. } => -1, BuildSlice { step } => -2 - (step.get(arg) as i32) + 1, ListAppend { .. } | SetAdd { .. } => -1, MapAdd { .. } => -2, @@ -1586,7 +1588,7 @@ impl Instruction { BuildSetFromTuples { size } => w!(BuildSetFromTuples, size), BuildMap { size } => w!(BuildMap, size), BuildMapForCall { size } => w!(BuildMapForCall, size), - DictUpdate => w!(DictUpdate), + DictUpdate { index } => w!(DictUpdate, index), BuildSlice { step } => w!(BuildSlice, step), ListAppend { i } => w!(ListAppend, i), SetAdd { i } => w!(SetAdd, i), diff --git a/vm/src/frame.rs b/vm/src/frame.rs index de8cb84352..38a2064679 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -800,26 +800,40 @@ impl ExecutingFrame<'_> { bytecode::Instruction::BuildMapForCall { size } => { self.execute_build_map_for_call(vm, size.get(arg)) } - bytecode::Instruction::DictUpdate => { - let other = self.pop_value(); - let dict = self - .top_value() - .downcast_ref::() - .expect("exact dict expected"); + bytecode::Instruction::DictUpdate { index } => { + // Stack before: [..., dict, ..., source] (source at TOS) + // Stack after: [..., dict, ...] (source consumed) + // The dict to update is at position TOS-i (before popping source) + + let idx = index.get(arg); + + // Pop the source from TOS + let source = self.pop_value(); + + // Get the dict to update (it's now at TOS-(i-1) after popping source) + let dict = if idx <= 1 { + // DICT_UPDATE 0 or 1: dict is at TOS (after popping source) + self.top_value() + } else { + // DICT_UPDATE n: dict is at TOS-(n-1) + self.nth_value(idx - 1) + }; + + let dict = dict.downcast_ref::().expect("exact dict expected"); // For dictionary unpacking {**x}, x must be a mapping // Check if the object has the mapping protocol (keys method) if vm - .get_method(other.clone(), vm.ctx.intern_str("keys")) + .get_method(source.clone(), vm.ctx.intern_str("keys")) .is_none() { return Err(vm.new_type_error(format!( "'{}' object is not a mapping", - other.class().name() + source.class().name() ))); } - dict.merge_object(other, vm)?; + dict.merge_object(source, vm)?; Ok(None) } bytecode::Instruction::BuildSlice { step } => {