@@ -2468,6 +2468,22 @@ impl FrameState {
24682468 self . stack . pop ( ) . ok_or_else ( || ParseError :: StackUnderflow ( self . clone ( ) ) )
24692469 }
24702470
2471+ /// Return a vec of the top n stack operands, in the same order as they were on the stack.
2472+ fn stack_popn ( & mut self , n : usize ) -> Result < Vec < InsnId > , ParseError > {
2473+ let mut elements = Vec :: with_capacity ( n) ;
2474+ self . stack_popn_into ( n, & mut elements) ?;
2475+ Ok ( elements)
2476+ }
2477+
2478+ fn stack_popn_into ( & mut self , n : usize , destination : & mut Vec < InsnId > ) -> Result < ( ) , ParseError > {
2479+ unsafe { // Unsafely set the length, so we don't have to initialize the slots we're about to overwrite.
2480+ elements. set_len ( n) ;
2481+ for i in ( 0 ..n) . rev ( ) { // Fill in reverse order, so we preserve the order of the stack.
2482+ elements[ i] = self . stack_pop ( ) ?;
2483+ }
2484+ }
2485+ }
2486+
24712487 /// Get a stack-top operand
24722488 fn stack_top ( & self ) -> Result < InsnId , ParseError > {
24732489 self . stack . last ( ) . ok_or_else ( || ParseError :: StackUnderflow ( self . clone ( ) ) ) . copied ( )
@@ -2787,21 +2803,13 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
27872803 YARVINSN_newarray => {
27882804 let count = get_arg ( pc, 0 ) . as_usize ( ) ;
27892805 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
2790- let mut elements = vec ! [ ] ;
2791- for _ in 0 ..count {
2792- elements. push ( state. stack_pop ( ) ?) ;
2793- }
2794- elements. reverse ( ) ;
2806+ let elements = state. stack_popn ( count) ?;
27952807 state. stack_push ( fun. push_insn ( block, Insn :: NewArray { elements, state : exit_id } ) ) ;
27962808 }
27972809 YARVINSN_opt_newarray_send => {
27982810 let count = get_arg ( pc, 0 ) . as_usize ( ) ;
27992811 let method = get_arg ( pc, 1 ) . as_u32 ( ) ;
2800- let mut elements = vec ! [ ] ;
2801- for _ in 0 ..count {
2802- elements. push ( state. stack_pop ( ) ?) ;
2803- }
2804- elements. reverse ( ) ;
2812+ let elements = state. stack_popn ( count) ?;
28052813 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
28062814 let ( bop, insn) = match method {
28072815 VM_OPT_NEWARRAY_SEND_MAX => ( BOP_MAX , Insn :: ArrayMax { elements, state : exit_id } ) ,
@@ -3074,11 +3082,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
30743082 }
30753083 let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
30763084
3077- let mut args = vec ! [ ] ;
3078- for _ in 0 ..argc {
3079- args. push ( state. stack_pop ( ) ?) ;
3080- }
3081- args. reverse ( ) ;
3085+ let args = state. stack_popn ( argc) ?;
30823086
30833087 let recv = state. stack_pop ( ) ?;
30843088 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -3153,13 +3157,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
31533157 fun. push_insn ( block, Insn :: SideExit { state : exit_id, reason : SideExitReason :: UnknownCallType } ) ;
31543158 break ; // End the block
31553159 }
3156- let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
31573160
3158- let mut args = vec ! [ ] ;
3159- for _ in 0 ..argc {
3160- args. push ( state. stack_pop ( ) ?) ;
3161- }
3162- args. reverse ( ) ;
3161+ let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
3162+ let args = state. stack_popn ( argc) ?;
31633163
31643164 let recv = state. stack_pop ( ) ?;
31653165 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -3176,13 +3176,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
31763176 fun. push_insn ( block, Insn :: SideExit { state : exit_id, reason : SideExitReason :: UnknownCallType } ) ;
31773177 break ; // End the block
31783178 }
3179- let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
31803179
3181- let mut args = vec ! [ ] ;
3182- for _ in 0 ..argc {
3183- args. push ( state. stack_pop ( ) ?) ;
3184- }
3185- args. reverse ( ) ;
3180+ let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
3181+ let args = state. stack_popn ( argc) ?;
31863182
31873183 let recv = state. stack_pop ( ) ?;
31883184 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -3236,12 +3232,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
32363232 YARVINSN_invokebuiltin => {
32373233 let bf: rb_builtin_function = unsafe { * get_arg ( pc, 0 ) . as_ptr ( ) } ;
32383234
3239- let mut args = vec ! [ ] ;
3240- for _ in 0 ..bf. argc {
3241- args. push ( state. stack_pop ( ) ?) ;
3242- }
3243- args. push ( self_param) ;
3244- args. reverse ( ) ;
3235+ let mut args = vec ! [ self_param] ;
3236+ state. stack_popn_into ( bf. argc as usize , & mut args) ?;
32453237
32463238 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
32473239
0 commit comments