int main(int argc, char *argv[]) { char *program_name, *compiler_name, *other_wrappers, *sysroot; struct args *compiler_args, *cmd; compiler_args = args_init(argc, argv); /* check if we were called directly. */ program_name = basename(compiler_args->argv[0]); args_remove_first(compiler_args); if (str_eq(program_name, MYNAME)) { /* the first argument should be a compiler */ if (compiler_args->argc < 1 || compiler_args->argv[0][0] == '-') { fprintf(stderr, "%s", USAGE_TEXT); exit(1); } compiler_name = x_strdup(compiler_args->argv[0]); args_remove_first(compiler_args); } else { compiler_name = x_strdup(program_name); } free(program_name); other_wrappers = getenv(MYNAME "_OTHER_WRAPPERS"); if (!other_wrappers) { other_wrappers = "ccache distcc"; } cmd = find_all_executables(compiler_name, MYNAME, other_wrappers); if (!cmd) { fatal("No valid executables named %s found!", compiler_name); } free(compiler_name); sysroot = getenv("SYSROOT"); if (sysroot) { args_add(cmd, "--sysroot"); args_add(cmd, sysroot); } args_extend(cmd, compiler_args); args_free(compiler_args); execute(cmd->argv); return 1; }
/* * Process the compiler options into options suitable for passing to the * preprocessor and the real compiler. The preprocessor options don't include * -E; this is added later. Returns true on success, otherwise false. */ bool armcc_process_args(struct args *orig_args, struct args **preprocessor_args, struct args **compiler_args) { int i; bool found_c_opt = false; bool found_S_opt = false; bool found_pch = false; bool found_fpch_preprocess = false; const char *actual_language; /* Language to actually use. */ const char *input_charset = NULL; struct stat st; /* is the dependency makefile name overridden with --depend? */ bool dependency_filename_specified = false; /* is the dependency makefile target name specified ? */ bool dependency_target_specified = false; char *dep_file = NULL, *dep_dir = NULL; struct args *stripped_args = NULL, *dep_args = NULL; int argc = orig_args->argc; char **argv = orig_args->argv; bool result = true; /* 0: Choose preprocessor type by the file extension. * 1: Use c preprocessor. * 2: Use c++ preprocessor.*/ unsigned force_preprocessor_type = 0; stripped_args = args_init(0, NULL); dep_args = args_init(0, NULL); args_add(stripped_args, argv[0]); for (i = 1; i < argc; i++) { /* The user knows best: just swallow the next arg */ if (str_eq(argv[i], "--ccache-skip")) { i++; if (i == argc) { cc_log("--ccache-skip lacks an argument"); result = false; goto out; } args_add(stripped_args, argv[i]); continue; } /* Special case for -E. */ if (str_eq(argv[i], "-E")) { stats_update(STATS_PREPROCESSING); result = false; goto out; } /* These are always too hard. */ if (compopt_too_hard(argv[i]) || str_startswith(argv[i], "@") || str_startswith(argv[i], "-fdump-")) { cc_log("Compiler option %s is unsupported", argv[i]); stats_update(STATS_UNSUPPORTED); result = false; goto out; } /* These are too hard in direct mode. */ if (enable_direct) { if (compopt_too_hard_for_direct_mode(argv[i])) { cc_log("Unsupported compiler option for direct mode: %s", argv[i]); enable_direct = false; } } /* we must have -c */ if (str_eq(argv[i], "-c")) { args_add(stripped_args, argv[i]); found_c_opt = true; continue; } /* -S changes the default extension */ if (str_eq(argv[i], "-S")) { args_add(stripped_args, argv[i]); found_S_opt = true; continue; } /* we need to work out where the output was meant to go */ if (str_eq(argv[i], "-o")) { if (i == argc-1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } output_obj = argv[i+1]; i++; continue; } /* alternate form of -o, with no space */ if (str_startswith(argv[i], "-o")) { output_obj = &argv[i][2]; continue; } /* If multiple source type options are there, the armcc will use the last one. */ if (str_eq(argv[i], "--cpp")) { force_preprocessor_type = 2; continue; } else if (str_eq(argv[i], "--c90") || str_eq(argv[i], "--c99")) { force_preprocessor_type = 1; continue; } if (str_eq(argv[i], "--md")) { generating_dependencies = true; continue; } /* The rvct started supporting --depend_target from 4.0. * And there is a bug when using -E and --depend together with rvct which version is earlier than 4.0_697. * That is too hard to support "--depend" for the earlier version of rvct.*/ if (str_startswith(argv[i], "--depend_dir")) { /* We just concat the dir and the filename and pass the result * to --depend. */ if (i >= argc - 1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } dep_dir= x_strdup(argv[i+1]); i++; continue; } else if (str_startswith(argv[i], "--depend_target")) { if (i >= argc - 1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } dependency_target_specified = true; args_add(dep_args, argv[i]); args_add(dep_args, argv[i+1]); i++; continue; } else if (str_startswith(argv[i], "--depend")) { dependency_filename_specified = true; generating_dependencies = true; if (i >= argc - 1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } dep_file = x_strdup(argv[i + 1]); i++; continue; } /* * Options taking an argument that that we may want to rewrite * to relative paths to get better hit rate. A secondary effect * is that paths in the standard error output produced by the * compiler will be normalized. */ if (compopt_takes_path(argv[i])) { char *relpath; char *pchpath; if (i == argc-1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } args_add(stripped_args, argv[i]); relpath = make_relative_path(x_strdup(argv[i+1])); args_add(stripped_args, relpath); /* Try to be smart about detecting precompiled headers */ pchpath = format("%s.gch", argv[i+1]); if (stat(pchpath, &st) == 0) { cc_log("Detected use of precompiled header: %s", pchpath); found_pch = true; } free(pchpath); free(relpath); i++; continue; } /* Same as above but options with concatenated argument. */ if (compopt_short(compopt_takes_path, argv[i])) { char *relpath; char *option; relpath = make_relative_path(x_strdup(argv[i] + 2)); option = format("-%c%s", argv[i][1], relpath); args_add(stripped_args, option); free(relpath); free(option); continue; } /* options that take an argument */ if (compopt_takes_arg(argv[i])) { if (i == argc-1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } args_add(stripped_args, argv[i]); args_add(stripped_args, argv[i+1]); i++; continue; } /* other options */ if (argv[i][0] == '-') { args_add(stripped_args, argv[i]); continue; } /* if an argument isn't a plain file then assume its an option, not an input file. This allows us to cope better with unusual compiler options */ if (stat(argv[i], &st) != 0 || !S_ISREG(st.st_mode)) { cc_log("%s is not a regular file, not considering as input file", argv[i]); args_add(stripped_args, argv[i]); continue; } if (input_file) { if (language_for_file(argv[i])) { cc_log("Multiple input files: %s and %s", input_file, argv[i]); stats_update(STATS_MULTIPLE); } else if (!found_c_opt) { cc_log("Called for link with %s", argv[i]); if (strstr(argv[i], "conftest.")) { stats_update(STATS_CONFTEST); } else { stats_update(STATS_LINK); } } else { cc_log("Unsupported source extension: %s", argv[i]); stats_update(STATS_SOURCELANG); } result = false; goto out; } /* Rewrite to relative to increase hit rate. */ input_file = make_relative_path(x_strdup(argv[i])); } if (!input_file) { cc_log("No input file found"); stats_update(STATS_NOINPUT); result = false; goto out; } if (found_pch || found_fpch_preprocess) { using_precompiled_header = true; if (!(sloppiness & SLOPPY_TIME_MACROS)) { cc_log("You have to specify \"time_macros\" sloppiness when using" " precompiled headers to get direct hits"); cc_log("Disabling direct mode"); stats_update(STATS_CANTUSEPCH); result = false; goto out; } } if(force_preprocessor_type == 0) { actual_language = language_for_file(input_file); } else if(force_preprocessor_type == 2) { actual_language = "c++"; } else { actual_language = "c"; } output_is_precompiled_header = actual_language && strstr(actual_language, "-header") != NULL; if (!found_c_opt && !output_is_precompiled_header) { cc_log("No -c option found"); /* I find that having a separate statistic for autoconf tests is useful, as they are the dominant form of "called for link" in many cases */ if (strstr(input_file, "conftest.")) { stats_update(STATS_CONFTEST); } else { stats_update(STATS_LINK); } result = false; goto out; } if (!actual_language) { cc_log("Unsupported source extension: %s", input_file); stats_update(STATS_SOURCELANG); result = false; goto out; } direct_i_file = language_is_preprocessed(actual_language); if (output_is_precompiled_header) { /* It doesn't work to create the .gch from preprocessed source. */ cc_log("Creating precompiled header; not compiling preprocessed code"); compile_preprocessed_source_code = false; } /* don't try to second guess the compilers heuristics for stdout handling */ if (output_obj && str_eq(output_obj, "-")) { stats_update(STATS_OUTSTDOUT); cc_log("Output file is -"); result = false; goto out; } if (!output_obj) { if (output_is_precompiled_header) { output_obj = format("%s.gch", input_file); } else { char *p; output_obj = x_strdup(input_file); if ((p = strrchr(output_obj, '/'))) { output_obj = p+1; } p = strrchr(output_obj, '.'); if (!p || !p[1]) { cc_log("Badly formed object filename"); stats_update(STATS_ARGS); result = false; goto out; } p[1] = found_S_opt ? 's' : 'o'; p[2] = 0; } } /* cope with -o /dev/null */ if (!str_eq(output_obj,"/dev/null") && stat(output_obj, &st) == 0 && !S_ISREG(st.st_mode)) { cc_log("Not a regular file: %s", output_obj); stats_update(STATS_DEVICE); result = false; goto out; } /* * Some options shouldn't be passed to the real compiler when it compiles * preprocessed code: * * -finput-charset=XXX (otherwise conversion happens twice) * -x XXX (otherwise the wrong language is selected) */ *preprocessor_args = args_copy(stripped_args); if (input_charset) { args_add(*preprocessor_args, input_charset); } if (found_pch) { args_add(*preprocessor_args, "-fpch-preprocess"); } /* * Add flags for dependency generation only to the preprocessor command line. */ if (generating_dependencies) { char *dep_path; if(!dependency_filename_specified) { char *base_name; base_name = remove_extension(output_obj); dep_file = format("%s.d", base_name); free(base_name); } if (!dependency_target_specified) { args_add(dep_args, "--depend_target"); args_add(dep_args, output_obj); } free(output_dep); if(dep_dir) { #ifdef _WIN32 dep_path = make_relative_path(format("%s\\%s", dep_dir, dep_file)); #else dep_path = make_relative_path(format("%s/%s", dep_dir, dep_file)); #endif } else { dep_path = x_strdup(dep_file); } args_add(dep_args, "--depend"); args_add(dep_args, dep_path); /* dep_path will be free in make_relative_path */ output_dep = make_relative_path(x_strdup(dep_path)); } if (compile_preprocessed_source_code) { *compiler_args = args_copy(stripped_args); } else { *compiler_args = args_copy(*preprocessor_args); } i_extension = getenv("CCACHE_EXTENSION"); if (!i_extension) { const char *p_language = p_language_for_language(actual_language); i_extension = extension_for_language(p_language) + 1; } /* Patch for preprocessed file extension for armcc 3.1. * armcc 3.1 cannot recognize "i" or "ii" as the preprocessed source file * without --compile_all_input. */ args_add(*compiler_args, "--compile_all_input"); if (str_eq(i_extension, "ii")) { args_add(*compiler_args, "--cpp"); } /* * Only pass dependency arguments to the preprocesor since Intel's C++ * compiler doesn't produce a correct .d file when compiling preprocessed * source. */ args_extend(*preprocessor_args, dep_args); out: free(dep_file); free(dep_dir); args_free(stripped_args); args_free(dep_args); return result; }
/* * Process the compiler options into options suitable for passing to the * preprocessor and the real compiler. The preprocessor options don't include * -E; this is added later. Returns true on success, otherwise false. */ bool c166_process_args(struct args *orig_args, struct args **preprocessor_args, struct args **compiler_args) { int i; bool found_c_opt = false; bool found_S_opt = false; bool found_H_opt = false; /* 0: Choose preprocessor type by the file extension. * 1: Use c preprocessor. * 2: Use c++ preprocessor.*/ unsigned force_preprocessor_type = 0; const char *actual_language; /* Language to actually use. */ struct stat st; /* is the dependency makefile name overridden with -MF? */ bool dependency_filename_specified = false; /* is the dependency makefile target name specified with -MT or -MQ? */ bool dependency_target_specified = false; struct args *stripped_args = NULL, *dep_args = NULL, *h_args; int argc = orig_args->argc; char **argv = orig_args->argv; bool result = true; stripped_args = args_init(0, NULL); dep_args = args_init(0, NULL); h_args = args_init(0, NULL); args_add(stripped_args, argv[0]); for (i = 1; i < argc; i++) { /* The user knows best: just swallow the next arg */ if (str_eq(argv[i], "--ccache-skip")) { i++; if (i == argc) { cc_log("--ccache-skip lacks an argument"); result = false; goto out; } args_add(stripped_args, argv[i]); continue; } /* Special case for -E. */ if (str_eq(argv[i], "-E")) { stats_update(STATS_PREPROCESSING); result = false; goto out; } /* These are always too hard. */ if (compopt_too_hard(argv[i])) { cc_log("Compiler option %s is unsupported", argv[i]); stats_update(STATS_UNSUPPORTED); result = false; goto out; } /* These are too hard in direct mode. */ if (enable_direct) { if (compopt_too_hard_for_direct_mode(argv[i])) { cc_log("Unsupported compiler option for direct mode: %s", argv[i]); enable_direct = false; } } /* we must have -c */ if (str_eq(argv[i], "-c")) { args_add(stripped_args, argv[i]); found_c_opt = true; continue; } /* -S changes the default extension */ /* TODO: Check this -S out! if (str_eq(argv[i], "-S")) { args_add(stripped_args, argv[i]); found_S_opt = true; continue; } */ /* we need to work out where the output was meant to go */ if (str_eq(argv[i], "-o")) { if (i == argc-1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } output_obj = argv[i+1]; i++; continue; } /* alternate form of -o, with no space */ if (str_startswith(argv[i], "-o")) { output_obj = &argv[i][2]; continue; } /* debugging is handled specially, so that we know if we can strip line number info */ if (str_startswith(argv[i], "-g")) { args_add(stripped_args, argv[i]); if (enable_unify) { cc_log("%s used; disabling unify mode", argv[i]); enable_unify = false; } continue; } if (str_startswith(argv[i], "-H")) { cc_log("Detected -H %s", argv[i]); args_add(h_args, argv[i]); found_H_opt = true; continue; } /* * Options taking an argument that that we may want to rewrite * to relative paths to get better hit rate. A secondary effect * is that paths in the standard error output produced by the * compiler will be normalized. */ if (compopt_takes_path(argv[i])) { char *relpath; if (i == argc-1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } args_add(stripped_args, argv[i]); relpath = make_relative_path(x_strdup(argv[i+1])); args_add(stripped_args, relpath); free(relpath); i++; continue; } /* Same as above but options with concatenated argument. */ if (compopt_short(compopt_takes_path, argv[i])) { char *relpath; char *option; relpath = make_relative_path(x_strdup(argv[i] + 2)); option = format("-%c%s", argv[i][1], relpath); args_add(stripped_args, option); free(relpath); free(option); continue; } /* options that take an argument */ if (compopt_takes_arg(argv[i])) { if (i == argc-1) { cc_log("Missing argument to %s", argv[i]); stats_update(STATS_ARGS); result = false; goto out; } args_add(stripped_args, argv[i]); args_add(stripped_args, argv[i+1]); i++; continue; } if (str_eq(argv[i], "-c++")) { force_preprocessor_type = 2; args_add(stripped_args, argv[i]); continue; } if (str_eq(argv[i], "-noc++")) { force_preprocessor_type = 1; args_add(stripped_args, argv[i]); continue; } /* other options */ if (argv[i][0] == '-') { args_add(stripped_args, argv[i]); continue; } /* if an argument isn't a plain file then assume its an option, not an input file. This allows us to cope better with unusual compiler options */ if (stat(argv[i], &st) != 0 || !S_ISREG(st.st_mode)) { cc_log("%s is not a regular file, not considering as input file", argv[i]); args_add(stripped_args, argv[i]); continue; } if (input_file) { if (language_for_file(argv[i])) { cc_log("Multiple input files: %s and %s", input_file, argv[i]); stats_update(STATS_MULTIPLE); } else if (!found_c_opt) { cc_log("Called for link with %s", argv[i]); if (strstr(argv[i], "conftest.")) { stats_update(STATS_CONFTEST); } else { stats_update(STATS_LINK); } } else { cc_log("Unsupported source extension: %s", argv[i]); stats_update(STATS_SOURCELANG); } result = false; goto out; } /* Rewrite to relative to increase hit rate. */ input_file = make_relative_path(x_strdup(argv[i])); } if (!input_file) { cc_log("No input file found"); stats_update(STATS_NOINPUT); result = false; goto out; } if(force_preprocessor_type == 0) { actual_language = language_for_file(input_file); } else if(force_preprocessor_type == 2) { actual_language = "c++"; } else { actual_language = "c"; } output_is_precompiled_header = actual_language && strstr(actual_language, "-header") != NULL; if (!found_c_opt && !output_is_precompiled_header) { cc_log("No -c option found"); /* I find that having a separate statistic for autoconf tests is useful, as they are the dominant form of "called for link" in many cases */ if (strstr(input_file, "conftest.")) { stats_update(STATS_CONFTEST); } else { stats_update(STATS_LINK); } result = false; goto out; } if (!actual_language) { cc_log("Unsupported source extension: %s", input_file); stats_update(STATS_SOURCELANG); result = false; goto out; } direct_i_file = language_is_preprocessed(actual_language); if (output_is_precompiled_header) { /* It doesn't work to create the .gch from preprocessed source. */ cc_log("Creating precompiled header; not compiling preprocessed code"); compile_preprocessed_source_code = false; } i_extension = getenv("CCACHE_EXTENSION"); if (!i_extension) { const char *p_language = p_language_for_language(actual_language); if(str_eq(p_language, "c++-cpp-output")) { /* Dirty fix for preprocessed file extension for cc166. * The cp166 cannot handle cpp files with extension ii.*/ i_extension = "ii.cpp"; } else { i_extension = extension_for_language(p_language) + 1; } } /* don't try to second guess the compilers heuristics for stdout handling */ if (output_obj && str_eq(output_obj, "-")) { stats_update(STATS_OUTSTDOUT); cc_log("Output file is -"); result = false; goto out; } if (!output_obj) { if (output_is_precompiled_header) { output_obj = format("%s.gch", input_file); } else { char *p; output_obj = x_strdup(input_file); if ((p = strrchr(output_obj, '/'))) { output_obj = p+1; } p = strrchr(output_obj, '.'); if (!p || !p[1]) { cc_log("Badly formed object filename"); stats_update(STATS_ARGS); result = false; goto out; } *p = 0; p = output_obj; if(found_S_opt) { output_obj = format("%s.s", p); } else { /*The default extension of object file is obj for c166.*/ output_obj = format("%s.obj", p); } free(p); } } /* cope with -o /dev/null */ if (!str_eq(output_obj,"/dev/null") && stat(output_obj, &st) == 0 && !S_ISREG(st.st_mode)) { cc_log("Not a regular file: %s", output_obj); stats_update(STATS_DEVICE); result = false; goto out; } /* * Some options shouldn't be passed to the real compiler when it compiles * preprocessed code: */ *preprocessor_args = args_copy(stripped_args); /* Args with -H has been already preprocessed. * If it passed to the compiler again, some type redefined error will pop up.*/ if (found_H_opt) { args_extend(*preprocessor_args, h_args); } /* * Add flags for dependency generation only to the preprocessor command line. */ if (generating_dependencies) { if (!dependency_filename_specified) { char *default_depfile_name; char *base_name; base_name = remove_extension(output_obj); default_depfile_name = format("%s.d", base_name); free(base_name); args_add(dep_args, "-MF"); args_add(dep_args, default_depfile_name); output_dep = make_relative_path(x_strdup(default_depfile_name)); } if (!dependency_target_specified) { args_add(dep_args, "-MQ"); args_add(dep_args, output_obj); } } if (compile_preprocessed_source_code) { *compiler_args = args_copy(stripped_args); } else { *compiler_args = args_copy(*preprocessor_args); } /* Due to bugs or cc166 v8.6r3, the behaviours of c/c++ preprocessor * are quite different. * When using cpp preprocessor, the output will be directly send to stdout like gcc. * When using c preprocessor, the output will be written to filename.i even without "-o".*/ if(str_eq(actual_language, "c")) { #ifdef _WIN32 #error Never test this in Windows. #else args_add(*preprocessor_args, "-o/dev/stdout"); #endif } /* * Only pass dependency arguments to the preprocesor since Intel's C++ * compiler doesn't produce a correct .d file when compiling preprocessed * source. */ args_extend(*preprocessor_args, dep_args); out: args_free(stripped_args); args_free(dep_args); args_free(h_args); return result; }
static int setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, struct rb_calling_info *const calling, const struct rb_call_info *ci, VALUE * const locals, const enum arg_setup_type arg_setup_type) { const int min_argc = iseq->body->param.lead_num + iseq->body->param.post_num; const int max_argc = (iseq->body->param.flags.has_rest == FALSE) ? min_argc + iseq->body->param.opt_num : UNLIMITED_ARGUMENTS; int opt_pc = 0; int given_argc; struct args_info args_body, *args; VALUE keyword_hash = Qnil; VALUE * const orig_sp = th->cfp->sp; unsigned int i; /* * Extend SP for GC. * * [pushed values] [uninitialized values] * <- ci->argc --> * <- iseq->body->param.size------------> * ^ locals ^ sp * * => * [pushed values] [initialized values ] * <- ci->argc --> * <- iseq->body->param.size------------> * ^ locals ^ sp */ for (i=calling->argc; i<iseq->body->param.size; i++) { locals[i] = Qnil; } th->cfp->sp = &locals[i]; /* setup args */ args = &args_body; given_argc = args->argc = calling->argc; args->argv = locals; if (ci->flag & VM_CALL_KWARG) { args->kw_arg = ((struct rb_call_info_with_kwarg *)ci)->kw_arg; if (iseq->body->param.flags.has_kw) { int kw_len = args->kw_arg->keyword_len; /* copy kw_argv */ args->kw_argv = ALLOCA_N(VALUE, kw_len); args->argc -= kw_len; given_argc -= kw_len; MEMCPY(args->kw_argv, locals + args->argc, VALUE, kw_len); } else { args->kw_argv = NULL; given_argc = args_kw_argv_to_hash(args); } } else { args->kw_arg = NULL; args->kw_argv = NULL; } if (ci->flag & VM_CALL_ARGS_SPLAT) { args->rest = locals[--args->argc]; args->rest_index = 0; given_argc += RARRAY_LENINT(args->rest) - 1; } else { args->rest = Qfalse; } switch (arg_setup_type) { case arg_setup_method: break; /* do nothing special */ case arg_setup_block: if (given_argc == 1 && (min_argc > 0 || iseq->body->param.opt_num > 1 || iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) && !iseq->body->param.flags.ambiguous_param0 && args_check_block_arg0(args, th)) { given_argc = RARRAY_LENINT(args->rest); } break; case arg_setup_lambda: if (given_argc == 1 && given_argc != iseq->body->param.lead_num && !iseq->body->param.flags.has_rest && args_check_block_arg0(args, th)) { given_argc = RARRAY_LENINT(args->rest); } } /* argc check */ if (given_argc < min_argc) { if (given_argc == min_argc - 1 && args->kw_argv) { args_stored_kw_argv_to_hash(args); given_argc = args_argc(args); } else { if (arg_setup_type == arg_setup_block) { CHECK_VM_STACK_OVERFLOW(th->cfp, min_argc); given_argc = min_argc; args_extend(args, min_argc); } else { argument_arity_error(th, iseq, given_argc, min_argc, max_argc); } } } if (given_argc > min_argc && (iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) && args->kw_argv == NULL) { if (args_pop_keyword_hash(args, &keyword_hash, th)) { given_argc--; } } if (given_argc > max_argc && max_argc != UNLIMITED_ARGUMENTS) { if (arg_setup_type == arg_setup_block) { /* truncate */ args_reduce(args, given_argc - max_argc); given_argc = max_argc; } else { argument_arity_error(th, iseq, given_argc, min_argc, max_argc); } } if (iseq->body->param.flags.has_lead) { args_setup_lead_parameters(args, iseq->body->param.lead_num, locals + 0); } if (iseq->body->param.flags.has_post) { args_setup_post_parameters(args, iseq->body->param.post_num, locals + iseq->body->param.post_start); } if (iseq->body->param.flags.has_opt) { int opt = args_setup_opt_parameters(args, iseq->body->param.opt_num, locals + iseq->body->param.lead_num); opt_pc = (int)iseq->body->param.opt_table[opt]; } if (iseq->body->param.flags.has_rest) { args_setup_rest_parameter(args, locals + iseq->body->param.rest_start); } if (iseq->body->param.flags.has_kw) { VALUE * const klocals = locals + iseq->body->param.keyword->bits_start - iseq->body->param.keyword->num; if (args->kw_argv != NULL) { const struct rb_call_info_kw_arg *kw_arg = args->kw_arg; args_setup_kw_parameters(args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, iseq, klocals); } else if (!NIL_P(keyword_hash)) { int kw_len = rb_long2int(RHASH_SIZE(keyword_hash)); struct fill_values_arg arg; /* copy kw_argv */ arg.keys = args->kw_argv = ALLOCA_N(VALUE, kw_len * 2); arg.vals = arg.keys + kw_len; arg.argc = 0; rb_hash_foreach(keyword_hash, fill_keys_values, (VALUE)&arg); VM_ASSERT(arg.argc == kw_len); args_setup_kw_parameters(arg.vals, kw_len, arg.keys, iseq, klocals); } else { VM_ASSERT(args_argc(args) == 0); args_setup_kw_parameters(NULL, 0, NULL, iseq, klocals); } } else if (iseq->body->param.flags.has_kwrest) { args_setup_kw_rest_parameter(keyword_hash, locals + iseq->body->param.keyword->rest_start); } if (iseq->body->param.flags.has_block) { args_setup_block_parameter(th, calling, locals + iseq->body->param.block_start); } #if 0 { int i; for (i=0; i<iseq->body->param.size; i++) { fprintf(stderr, "local[%d] = %p\n", i, (void *)locals[i]); } } #endif th->cfp->sp = orig_sp; return opt_pc; }