require './generator' class ExecutorGenerator < Generator def self.filter_key "executor" end def initialize super @need_guest = false @noguest_types = Set.new(["void"]) @expand_common = false end def need_guest if @need_guest then return yield else @need_guest = true result = yield @need_guest = false return result end end def type_needs_guest?(type) size_of_type(type) != 1 && ! @noguest_types.include?(type) end def guestify_type(type, guest) type.strip! return type, "", "" if not type_needs_guest?(type) if type =~ /^(.*)(\[[^\[\]]*\])$/ then post = $2 type1, _, _ = guestify_type($1, true) #if guest then # return "GUEST<#{type1}#{post}>", "", "" #else return type1, "", post #end elsif type =~ /^(.*)\*$/ then type1, _, _ = guestify_type($1, true) if guest then return "GUEST<#{type1}*>", "", "" else return type1, "*", "" end elsif guest then if type =~ /^const[ \t]+(.*)$/ then if type_needs_guest?($1) then return "const GUEST<#{$1}>" else return type end else return "GUEST<#{type}>" end else return type, "", "" end end def decl(type, thing=nil) t1, pre, post = guestify_type(type, @need_guest) return "#{t1} #{pre}#{thing}#{post}" end def convert_expression(expr) return expr.gsub(/\'([^\']+)\'/) {|x| "\"#{$1}\"_4"} end def declare_struct_union(what, value) @noguest_types << value["name"] @out << "#{what} #{value["name"]}" if value["members"] then @out << "{" @out << "GUEST_STRUCT;" need_guest { declare_members(value["members"]) } @out << "}" end @out << ";" if value["size"] then @out << "static_assert(sizeof(#{value["name"]}) == #{value["size"]});" end end def declare_dispatcher(value, extern:false) @available_dispatchers << value["name"] @out << "EXTERN_" if extern @out << "DISPATCHER_TRAP(#{value["name"]}, " @out << "#{hexlit(value["trap"])}, #{value["selector-location"]});\n" end def declare_lowmem(value) @out << "const LowMemGlobal<#{decl(value["type"])}> #{value["name"]}" @out << "{ #{hexlit(value["address"],12)} };\n" # @out << "LOWMEM_ACCESSOR(#{value["name"]});\n" if value["type"] =~ /^(.*)\[[^\[\]]*\]$/ then # @out << "inline GUEST<#{$1}>* LMGet#{value["name"]}() { return LM(#{value["name"]}); }\n" # @out << "NOTRAP_FUNCTION2(LMGet#{value["name"]});\n" else sz = size_of_type(value["type"]) if !sz || sz > 4 then @out << "inline void LMGet#{value["name"]}(#{decl(value["type"]+"*", "val")}) { *val = LM(#{value["name"]}); }\n" @out << "inline void LMSet#{value["name"]}(#{decl("const " + value["type"]+"*", "val")}) { LM(#{value["name"]}) = *val; }\n" else @out << "inline #{decl(value["type"])} LMGet#{value["name"]}() { return LM(#{value["name"]}); }\n" @out << "inline void LMSet#{value["name"]}(#{decl(value["type"],"val")}) { LM(#{value["name"]}) = val; }\n" end @out << "NOTRAP_FUNCTION2(LMGet#{value["name"]});\n" @out << "NOTRAP_FUNCTION2(LMSet#{value["name"]});\n" end end def handle_regcall_conv(fun) args = (fun["args"] or []) @out << (fun["returnreg"] or "void") argregs = args.map do |arg| basetype = $1 if arg["type"] =~ /^(.*)\* *$/ if arg["register"] =~ /^Out<(.*)>$/ then "Out<#{basetype}, #{$1}>" elsif arg["register"] =~ /^InOut<(.*)>$/ then "InOut<#{basetype}, #{$1}>" else arg["register"] end end @out << "(" << argregs.join(", ") << ")" @out << ", " << fun["executor_extras"] if fun["executor_extras"] end def declare_function(fun) if fun["dispatcher"] && ! @available_dispatchers.include?(fun["dispatcher"]) then disp = $global_name_map[fun["dispatcher"]] if disp and disp["dispatcher"] then declare_dispatcher(disp["dispatcher"], extern:true) end end name = fun["name"] dispatcher = (fun["dispatcher"] && $global_name_map[fun["dispatcher"]]["dispatcher"]) trap = (fun["trap"] or (dispatcher and dispatcher["trap"])) cname = name if fun["executor"] then if fun["executor"].is_a?(String) then if fun["executor"] =~ /_$/ then cname = fun["executor"] + name else cname = fun["executor"] end end end two = name == cname ? "2" : "" @out << (fun["return"] or "void") << " " << cname args = (fun["args"] or []) @out << "(" << (args.map {|arg| decl(arg["type"], arg["name"])}).join(", ") << ");" if fun["file_trap"] == "hfs" then trap_sel_disp = hexlit(Integer(trap) & 0xA0FF) else trap_sel_disp = hexlit(trap) end if fun["selector"] then sub = "SUB" trap_sel_disp += ", #{hexlit(fun["selector"])}, #{hexlit(fun["dispatcher"])}" else sub = "" end if not fun["executor"] then elsif fun["file_trap"] == "mfs" then elsif fun["file_trap"] == "hfs" then @out << "HFS_#{sub}TRAP(#{name.gsub(/^PBH/,"PB")}, #{name}, " @out << "#{fun["args"][0]["type"]}, #{trap_sel_disp});" elsif fun["file_trap"] then @out << "FILE_#{sub}TRAP(#{name}, #{fun["args"][0]["type"]}, #{trap_sel_disp});" elsif trap && (fun["executor_extras"] || fun["returnreg"] || args.any? {|arg| arg["register"]}) then if fun["variants"] then variants = fun["variants"] nflagstr = variants.size >= 3 ? "2" : "" @out << "REGISTER_#{nflagstr}FLAG_TRAP(#{cname}, #{variants.join(", ")}, " @out << "#{hexlit(trap)}, " @out << (fun["return"] or "void") args1 = variants.size >= 3 ? fun["args"][0..-3] : fun["args"][0..-2] @out << "(" << (args1.map {|arg| decl(arg["type"])}).join(", ") << ")" @out << ", " else @out << "REGISTER_#{sub}TRAP#{two}(#{name}, #{trap_sel_disp}, " end handle_regcall_conv(fun) @out << ");\n" elsif fun["selector"] then @out << "PASCAL_SUBTRAP(#{name}, #{hexlit(trap)}, " @out << "#{hexlit(fun["selector"])}, #{hexlit(fun["dispatcher"])});\n" elsif trap then if name == cname then if args.size == 0 && !fun["return"] then @out << "REGISTER_TRAP2(#{name}, #{hexlit(trap)}, void());\n" else end else @out << "PASCAL_TRAP(#{name}, #{hexlit(trap)});\n" end else @out << "NOTRAP_FUNCTION#{two}(#{name});\n" end end def declare_funptr(value) name = value["name"] args = (value["args"] or []) @out << "using #{name} = UPP<" @out << (value["return"] or "void") << "(" args = (value["args"] or []) @out << args.map {|arg|decl(arg["type"], arg["name"])}.join(", ") @out << ")" if value["returnreg"] || value["executor_extras"] || args.any? {|arg| arg["register"]} then @out << ", Register<" handle_regcall_conv(value) @out << ">" elsif value["callconv"] == "C" then @out << ", callconv::CCall" end @out << ">;\n" end def declare_verbatim(value) @out << "BEGIN_EXECUTOR_ONLY\n" @out << value.strip << "\n" @out << "END_EXECUTOR_ONLY\n" end def remap_name(name) name == "MacTypes" ? "ExMacTypes" : name end def generate_preamble(header) super @out << "#pragma once\n" #if header.name == "MacTypes" then @out << "#include \"base/mactype.h\"\n" @out << "#include \n" @out << "#include \n" #end header.included.each do |file| @out << "#include \"#{remap_name(file)}.h\"\n" end @out << "\n" @out << "#define MODULE_NAME #{header.name}\n" @out << "#include \n" @out << "\n\n" @out << "namespace Executor {\n\n" end def generate_postamble(header) @out << "} /* namespace Executor */" end def generate_header(header) @current_header = header @available_dispatchers = Set.new super end def make_api_ifdef(api) if api == "carbon" then else yield end end def generate(defs) print "Writing Headers...\n" FileUtils.mkdir_p "#{$options.output_dir}/api" FileUtils.mkdir_p "#{$options.output_dir}/trap_instances" moduleList = [] defs.topsort.each do |name| name2 = remap_name(name) moduleList << name2 formatted_file "#{$options.output_dir}/api/#{name2}.h" do |f| f << generate_header(defs.headers[name]) end formatted_file "#{$options.output_dir}/trap_instances/#{name2}.cpp" do |f| f << < // Function for preventing the linker from considering the static constructors in this module unused namespace Executor::ReferenceTraps { void #{name2}() {} } END end end formatted_file "#{$options.output_dir}/trap_instances/ReferenceAllTraps.cpp" do |f| f << "namespace Executor {\n" f << "namespace ReferenceTraps {\n" moduleList.each { |m| f << "void #{m}();\n" } f << "}\nvoid ReferenceAllTraps() {\n" moduleList.each { |m| f << "ReferenceTraps::#{m}();\n" } f << "}\n}\n" end File.open "#{$options.output_dir}/trap_instances/trap_instances.cmake", "w" do |f| f << "set(trap_instance_sources\n" f << " \"#{$options.output_dir}/trap_instances/ReferenceAllTraps.cpp\"\n" moduleList.each { |m| f << " \"#{$options.output_dir}/trap_instances/#{m}.cpp\"\n" } f << ")\n" end print "Done.\n" end end