@@ -5732,7 +5732,7 @@ iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
57325732 VALUE v , type , eiseqval ;
57335733 const VALUE * ptr ;
57345734 LABEL * lstart , * lend , * lcont ;
5735- int sp ;
5735+ unsigned int sp ;
57365736
57375737 v = rb_convert_type (RARRAY_AREF (exception , i ), T_ARRAY ,
57385738 "Array" , "to_ary" );
@@ -5751,7 +5751,7 @@ iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
57515751 lstart = register_label (iseq , labels_table , ptr [2 ]);
57525752 lend = register_label (iseq , labels_table , ptr [3 ]);
57535753 lcont = register_label (iseq , labels_table , ptr [4 ]);
5754- sp = NUM2INT (ptr [5 ]);
5754+ sp = NUM2UINT (ptr [5 ]);
57555755
57565756 (void )sp ;
57575757
@@ -5807,14 +5807,25 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
58075807 VALUE vflag = rb_hash_aref (op , ID2SYM (rb_intern ("flag" )));
58085808 VALUE vorig_argc = rb_hash_aref (op , ID2SYM (rb_intern ("orig_argc" )));
58095809 VALUE vblock = rb_hash_aref (op , ID2SYM (rb_intern ("blockptr" )));
5810+ VALUE vkw_arg = rb_hash_aref (op , ID2SYM (rb_intern ("kw_arg" )));
58105811
58115812 if (!NIL_P (vmid )) mid = SYM2ID (vmid );
58125813 if (!NIL_P (vflag )) flag = NUM2UINT (vflag );
58135814 if (!NIL_P (vorig_argc )) orig_argc = FIX2INT (vorig_argc );
58145815 if (!NIL_P (vblock )) block = iseq_build_load_iseq (iseq , vblock );
5815- }
58165816
5817- /* TODO: support keywords */
5817+ if (!NIL_P (vkw_arg )) {
5818+ int i ;
5819+ int len = RARRAY_LENINT (vkw_arg );
5820+ size_t n = sizeof (rb_call_info_kw_arg_t ) + sizeof (ID ) * (len - 1 );
5821+
5822+ kw_arg = xmalloc (n );
5823+ kw_arg -> keyword_len = len ;
5824+ for (i = 0 ; i < len ; i ++ ) {
5825+ kw_arg -> keywords [i ] = SYM2ID (RARRAY_AREF (vkw_arg , i ));
5826+ }
5827+ }
5828+ }
58185829
58195830 return (VALUE )new_callinfo (iseq , mid , orig_argc , block , flag , kw_arg );
58205831}
@@ -5915,16 +5926,21 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
59155926 case TS_CDHASH :
59165927 {
59175928 int i ;
5929+ VALUE map = rb_hash_new ();
5930+
5931+ rb_hash_tbl_raw (map )-> type = & cdhash_type ;
59185932 op = rb_convert_type (op , T_ARRAY , "Array" , "to_ary" );
59195933 op = rb_ary_dup (op );
59205934 for (i = 0 ; i < RARRAY_LEN (op ); i += 2 ) {
5921- VALUE sym = rb_ary_entry (op , i + 1 );
5935+ VALUE key = RARRAY_AREF (op , i );
5936+ VALUE sym = RARRAY_AREF (op , i + 1 );
59225937 LABEL * label =
59235938 register_label (iseq , labels_table , sym );
5924- rb_ary_store ( op , i + 1 , (VALUE )label | 1 );
5939+ rb_hash_aset ( map , key , (VALUE )label | 1 );
59255940 }
5926- argv [j ] = op ;
5927- iseq_add_mark_object_compile_time (iseq , op );
5941+ RB_GC_GUARD (op );
5942+ argv [j ] = map ;
5943+ iseq_add_mark_object_compile_time (iseq , map );
59285944 }
59295945 break ;
59305946 default :
@@ -5947,68 +5963,180 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
59475963}
59485964
59495965#define CHECK_ARRAY (v ) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
5950- #define CHECK_STRING (v ) rb_convert_type((v), T_STRING, "String", "to_str")
59515966#define CHECK_SYMBOL (v ) rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
5952- static inline VALUE CHECK_INTEGER (VALUE v ) {(void )NUM2LONG (v ); return v ;}
5967+
5968+ static int
5969+ int_param (int * dst , VALUE param , VALUE sym )
5970+ {
5971+ VALUE val = rb_hash_aref (param , sym );
5972+ switch (TYPE (val )) {
5973+ case T_NIL :
5974+ return FALSE;
5975+ case T_FIXNUM :
5976+ * dst = FIX2INT (val );
5977+ return TRUE;
5978+ default :
5979+ rb_raise (rb_eTypeError , "invalid %+" PRIsVALUE " Fixnum: %+" PRIsVALUE ,
5980+ sym , val );
5981+ }
5982+ return FALSE;
5983+ }
5984+
5985+ static void
5986+ iseq_build_kw (rb_iseq_t * iseq , VALUE params , VALUE keywords )
5987+ {
5988+ int i , j ;
5989+ int len = RARRAY_LENINT (keywords );
5990+ int default_len ;
5991+ VALUE key , sym , default_val ;
5992+
5993+ iseq -> param .flags .has_kw = TRUE;
5994+
5995+ iseq -> param .keyword = ZALLOC (struct rb_iseq_param_keyword );
5996+ iseq -> param .keyword -> num = len ;
5997+ #define SYM (s ) ID2SYM(rb_intern(#s))
5998+ (void )int_param (& iseq -> param .keyword -> bits_start , params , SYM (kwbits ));
5999+ i = iseq -> param .keyword -> bits_start - iseq -> param .keyword -> num ;
6000+ iseq -> param .keyword -> table = & iseq -> local_table [i ];
6001+ #undef SYM
6002+
6003+ /* required args */
6004+ for (i = 0 ; i < len ; i ++ ) {
6005+ VALUE val = RARRAY_AREF (keywords , i );
6006+
6007+ if (!SYMBOL_P (val )) {
6008+ goto default_values ;
6009+ }
6010+ iseq -> param .keyword -> table [i ] = SYM2ID (val );
6011+ iseq -> param .keyword -> required_num ++ ;
6012+ }
6013+
6014+ default_values : /* note: we intentionally preserve `i' from previous loop */
6015+ default_len = len - i ;
6016+ if (default_len == 0 ) {
6017+ return ;
6018+ }
6019+
6020+ iseq -> param .keyword -> default_values = ALLOC_N (VALUE , default_len );
6021+
6022+ for (j = 0 ; i < len ; i ++ , j ++ ) {
6023+ key = RARRAY_AREF (keywords , i );
6024+ CHECK_ARRAY (key );
6025+
6026+ switch (RARRAY_LEN (key )) {
6027+ case 1 :
6028+ sym = RARRAY_AREF (key , 0 );
6029+ default_val = Qundef ;
6030+ break ;
6031+ case 2 :
6032+ sym = RARRAY_AREF (key , 0 );
6033+ default_val = RARRAY_AREF (key , 1 );
6034+ break ;
6035+ default :
6036+ rb_raise (rb_eTypeError ,
6037+ "keyword default has unsupported len %+" PRIsVALUE ,
6038+ key );
6039+ }
6040+ iseq -> param .keyword -> table [i ] = SYM2ID (sym );
6041+ iseq -> param .keyword -> default_values [j ] = default_val ;
6042+ }
6043+ }
59536044
59546045VALUE
5955- rb_iseq_build_from_ary (rb_iseq_t * iseq , VALUE locals , VALUE args ,
6046+ rb_iseq_build_from_ary (rb_iseq_t * iseq , VALUE misc , VALUE locals , VALUE params ,
59566047 VALUE exception , VALUE body )
59576048{
5958- int i ;
6049+ #define SYM (s ) ID2SYM(rb_intern(#s))
6050+ int i , len ;
59596051 ID * tbl ;
59606052 struct st_table * labels_table = st_init_numtable ();
6053+ VALUE arg_opt_labels = rb_hash_aref (params , SYM (opt ));
6054+ VALUE keywords = rb_hash_aref (params , SYM (keyword ));
6055+ VALUE sym_arg_rest = ID2SYM (rb_intern ("#arg_rest" ));
59616056 DECL_ANCHOR (anchor );
59626057 INIT_ANCHOR (anchor );
59636058
5964- iseq -> local_table_size = RARRAY_LENINT (locals );
6059+ len = RARRAY_LENINT (locals );
6060+ iseq -> local_table_size = len ;
59656061 iseq -> local_table = tbl = (ID * )ALLOC_N (ID , iseq -> local_table_size );
59666062 iseq -> local_size = iseq -> local_table_size + 1 ;
59676063
5968- for (i = 0 ; i < RARRAY_LEN ( locals ) ; i ++ ) {
6064+ for (i = 0 ; i < len ; i ++ ) {
59696065 VALUE lv = RARRAY_AREF (locals , i );
5970- tbl [i ] = FIXNUM_P (lv ) ? (ID )FIX2LONG (lv ) : SYM2ID (CHECK_SYMBOL (lv ));
6066+
6067+ if (sym_arg_rest == lv ) {
6068+ tbl [i ] = 0 ;
6069+ }
6070+ else {
6071+ tbl [i ] = FIXNUM_P (lv ) ? (ID )FIX2LONG (lv ) : SYM2ID (CHECK_SYMBOL (lv ));
6072+ }
59716073 }
59726074
5973- /* args */
5974- if (FIXNUM_P (args )) {
5975- iseq -> param .size = iseq -> param .lead_num = FIX2INT (args );
6075+ #define MISC_PARAM (D ,F ) do { \
6076+ if (!int_param(D, misc, SYM(F))) { \
6077+ rb_raise(rb_eTypeError, "misc field missing: %s", #F); \
6078+ } } while (0)
6079+ MISC_PARAM (& iseq -> local_size , local_size );
6080+ /* iseq->stack_size and iseq->param.size are calculated */
6081+ #undef MISC_PARAM
6082+
6083+ #define INT_PARAM (F ) int_param(&iseq->param.F, params, SYM(F))
6084+ if (INT_PARAM (lead_num )) {
59766085 iseq -> param .flags .has_lead = TRUE;
59776086 }
5978- else {
5979- int i = 0 ;
5980- VALUE argc = CHECK_INTEGER (rb_ary_entry (args , i ++ ));
5981- VALUE arg_opt_labels = CHECK_ARRAY (rb_ary_entry (args , i ++ ));
5982- VALUE arg_post_num = CHECK_INTEGER (rb_ary_entry (args , i ++ ));
5983- VALUE arg_post_start = CHECK_INTEGER (rb_ary_entry (args , i ++ ));
5984- VALUE arg_rest = CHECK_INTEGER (rb_ary_entry (args , i ++ ));
5985- VALUE arg_block = CHECK_INTEGER (rb_ary_entry (args , i ++ ));
5986-
5987- iseq -> param .lead_num = FIX2INT (argc );
5988- iseq -> param .rest_start = FIX2INT (arg_rest );
5989- iseq -> param .post_num = FIX2INT (arg_post_num );
5990- iseq -> param .post_start = FIX2INT (arg_post_start );
5991- iseq -> param .block_start = FIX2INT (arg_block );
5992- iseq -> param .opt_num = RARRAY_LENINT (arg_opt_labels ) - 1 ;
5993- iseq -> param .opt_table = (VALUE * )ALLOC_N (VALUE , iseq -> param .opt_num + 1 );
6087+ if (INT_PARAM (post_num )) iseq -> param .flags .has_post = TRUE;
6088+ if (INT_PARAM (post_start )) iseq -> param .flags .has_post = TRUE;
6089+ if (INT_PARAM (rest_start )) iseq -> param .flags .has_rest = TRUE;
6090+ if (INT_PARAM (block_start )) iseq -> param .flags .has_block = TRUE;
6091+ #undef INT_PARAM
59946092
5995- if ( iseq -> param . flags . has_block ) {
5996- iseq -> param . size = iseq -> param . block_start + 1 ;
5997- }
5998- else if ( iseq -> param .flags .has_post ) {
5999- iseq -> param . size = iseq -> param . post_start + iseq -> param . post_num ;
6000- }
6001- else if ( iseq -> param .flags . has_rest ) {
6002- iseq -> param .size = iseq -> param . rest_start + 1 ;
6003- }
6004- else {
6005- iseq -> param . size = iseq -> param . lead_num + iseq -> param . opt_num ;
6006- }
6093+ switch ( TYPE ( arg_opt_labels ) ) {
6094+ case T_ARRAY :
6095+ len = RARRAY_LENINT ( arg_opt_labels );
6096+ iseq -> param .flags .has_opt = !!( len - 1 >= 0 );
6097+
6098+ if ( iseq -> param . flags . has_opt ) {
6099+ iseq -> param .opt_num = len - 1 ;
6100+ iseq -> param .opt_table = ( VALUE * ) ALLOC_N ( VALUE , len ) ;
6101+
6102+ for ( i = 0 ; i < len ; i ++ ) {
6103+ VALUE ent = RARRAY_AREF ( arg_opt_labels , i ) ;
6104+ LABEL * label = register_label ( iseq , labels_table , ent );
60076105
6008- for ( i = 0 ; i < RARRAY_LEN ( arg_opt_labels ); i ++ ) {
6009- iseq -> param . opt_table [ i ] = ( VALUE ) register_label ( iseq , labels_table , rb_ary_entry ( arg_opt_labels , i ));
6106+ iseq -> param . opt_table [ i ] = ( VALUE ) label ;
6107+ }
60106108 }
6109+ case T_NIL :
6110+ break ;
6111+ default :
6112+ rb_raise (rb_eTypeError , ":opt param is not an array: %+" PRIsVALUE ,
6113+ arg_opt_labels );
6114+ }
6115+
6116+ switch (TYPE (keywords )) {
6117+ case T_ARRAY :
6118+ iseq_build_kw (iseq , params , keywords );
6119+ case T_NIL :
6120+ break ;
6121+ default :
6122+ rb_raise (rb_eTypeError , ":keywords param is not an array: %+" PRIsVALUE ,
6123+ keywords );
6124+ }
6125+
6126+ if (Qtrue == rb_hash_aref (params , SYM (ambiguous_param0 ))) {
6127+ iseq -> param .flags .ambiguous_param0 = TRUE;
6128+ }
6129+
6130+ if (int_param (& i , params , SYM (kwrest ))) {
6131+ if (!iseq -> param .keyword ) {
6132+ iseq -> param .keyword = ZALLOC (struct rb_iseq_param_keyword );
6133+ }
6134+ iseq -> param .keyword -> rest_start = i ;
6135+ iseq -> param .flags .has_kwrest = TRUE;
6136+
60116137 }
6138+ #undef SYM
6139+ iseq_calc_param_size (iseq );
60126140
60136141 /* exception */
60146142 iseq_build_from_ary_exception (iseq , labels_table , exception );
0 commit comments