set file [lindex $argv 0] set macro [lindex $argv 1] if {[info exists env(FINAL_PATCH)]} { set changed 0 catch { exec bash -c "hg status . | grep ." >@ stdout 2>@ stdout # If the above command exited with 0 status, that means some # files have (possibly) changed set changed 1 } if {$changed} { puts "Some files have changed -- FINAL_PATCH aborted" exit 1 } } proc append_orig {varname line} { upvar $varname orig if {[string first TEMP_CONVERSION $line] < 0} { append orig $line\n } } proc flags_header_file {file} { if {![regsub {[.]hpp$} $file {.flags.hpp} file]} { puts "Not a proper input header file $file" exit 1 } return $file } proc keep_orig_flags_macro {} { global env if {[info exists env(FINAL_PATCH)] || [info exists env(QUICK_TEST)]} { return 0 } else { return 1 } } proc temp_mark {} { set mark "" if {[keep_orig_flags_macro]} { set mark " // TEMP_CONVERSION" } return $mark } proc move_file {src dst} { if {[catch {exec cmp -s $src $dst}]} { # the files differ puts "update $dst" file rename -force $src $dst } else { puts "(same) $dst" file delete $src } } proc doit {file macro ifdef common} { global copyright all_names env foreach n {all_decl all_defn lp64_decl lp64_defn flagcond} { global $n catch {unset $n} } set all_names {} set orig "" set out "" set fd [open $file] while {![eof $fd]} { set line [gets $fd] if {[string first "\#define $macro\(" $line] >= 0} { set flagfile [flags_header_file $file] set insert "" append insert "#include \"[file tail $flagfile]\"[temp_mark]\n" set macro "" if {[keep_orig_flags_macro]} { append macro "#if 0[temp_mark]\n" } if {[keep_orig_flags_macro]} { append_orig macro $line } set data $line\n while {![eof $fd]} { set line [gets $fd] if {[keep_orig_flags_macro]} { append macro $line\n } append data $line\n if {![regexp {\\$} $line]} { append out [process $data] break } } #-------------------------------------------------- # Prepare the content of the .flags.hpp file #-------------------------------------------------- while {[regsub -all "(\n#\[^\n\]*_HPP)\n" $out "\\1_HACK\n" out]} {} set flags_hpp "" if {$ifdef != ""} { append flags_hpp "#include \"utilities/macros.hpp\"\n" append flags_hpp "#if $ifdef\n" } append flags_hpp "#include \"runtime/flags/jvmFlag.hpp\"\n" append flags_hpp [string trimright $out] if {$ifdef != ""} { append flags_hpp "\n#endif // $ifdef" } if {[info exists all_decl]} { if {[keep_orig_flags_macro]} { append orig $insert } else { append orig $flags_hpp\n } } if {[keep_orig_flags_macro]} { append macro "#endif[temp_mark]\n" } if {[keep_orig_flags_macro]} { append orig $macro } } else { append_orig orig $line } } close $fd # Change "Defines ..." to "Declares ..." regsub {Defines all global flags} $orig {Declare all global flags} orig regsub {Defines (.*specific flags)} $orig {Declare \1} orig #-------------------------------------------------- # Patch the original .hpp file #-------------------------------------------------- set fd [open $file.tmp w+] regsub -all \n+\$ $orig "" orig puts $fd $orig close $fd move_file $file.tmp $file #-------------------------------------------------- # Write the .cpp file (if file exists, add the flag definitions to the end) #-------------------------------------------------- write_c_file $file [flags_header_file $file] $ifdef $common #-------------------------------------------------- # not final: Write the .flags.hpp file #-------------------------------------------------- if {[keep_orig_flags_macro]} { set file [flags_header_file $file] if {![info exists all_decl]} { if {[file exists $file]} { puts "hg remove $file" } return } file mkdir [file dir $file] set fd [open $file.tmp w+] puts $fd $flags_hpp close $fd move_file $file.tmp $file } if {[info exists env(QUICK_TEST)]} { exit } #exit } set flags {} foreach {f n attr} { develop VMDevelop {} develop_pd VMDevelopPD {} product VMProduct {} product_pd VMProductPD {} diagnostic VMDiagnostic DIAGNOSTIC diagnostic_pd VMDiagnosticPD {DIAGNOSTIC} experimental VMExperimental EXPERIMENTAL notproduct VMNotProduct {} manageable VMManageable MANAGEABLE product_rw VMProductRW READ_WRITE lp64_product VMLP64Product LP64 } { set className($f) $n set attrs($f) $attr lappend flags $f } set prefix "" set flagdecl "(" foreach f $flags { append flagdecl $prefix$f set prefix ")|(" } append flagdecl ")" set defn_indent [format %23s ""] proc get_docs {docs n} { global defn_indent # Skip the stuff before the first $n commas (these are the type, name and optional def_value) for {set i 0} {$i < $n} {incr i} { regsub {^[^,]*,} $docs "" docs } regsub -all {^[\\ ]*} $docs "" docs regsub -all " *\\\\\n *" $docs "\n$defn_indent" docs set docs [string trim $docs] return ${defn_indent}${docs} } proc clean_slashes {text} { regsub -all {^[\\ ]*} $text "" text regsub -all " *\\\\\n *" $text "" text return [string trim $text] } # These flags are misidentified as "notproduct" in the original source code -- # they are actually used as develop flags. # foreach bad { CheckMemoryInitialization OptoBreakpointC2R OptoBreakpointOSR PrintInitialBlockList PrintOptoInlining PrintOpto PrintSystemDictionaryAtExit TestUnresponsiveErrorHandler TraceSuperWordLoopUnrollAnalysis TraceSuperWord VerifyLoopOptimizations } { set notnotproduct($bad) 1 } proc spaces {n} { return [format "%${n}s" ""] } proc replace {class match range constraint comment} { global className defn_indent attrs all_decl all_defn lp64_decl lp64_defn flagcond notnotproduct all_comments all_names set list [split $match ,] set type [string trim [lindex $list 0]] set name [string trim [lindex $list 1]] set PD "" if {[regexp {_pd$} $class]} { set defv "" set defv_sep "" set docs [get_docs $match 2] set PD _PD } else { set defv [string trim [lindex $list 2]] set defv_sep ", " set docs [get_docs $match 3] } set range [clean_slashes $range] set constraint [clean_slashes $constraint] set defv [clean_slashes $defv] set cname $className($class) # Special cases for ranges that cannot be represented in constant expressions if {[regexp "os::vm_page_size" $range]} { set kind VMPageSize if {"$constraint" != {}} { error "constraint must be empty but is $constraint" } } elseif {[regexp "os::vm_allocation_granularity" $range]} { set kind VMAllocationGranularity if {"$constraint" != {}} { error "constraint must be empty but is $constraint" } } if {"$constraint" != {}} { regsub , $constraint ", JVMFlag::" constraint regsub ":: *" $constraint "::" constraint set constraint "(void*)$constraint" } if {[regexp develop $class] || [info exists notnotproduct($name)]} { set macro_prefix DEVELOP } elseif {$class == "notproduct"} { set macro_prefix NOTPROD } else { set macro_prefix PRODUCT } set def_prefix DEFN_${macro_prefix} set my_attrs $attrs($class) if {"$type" == "ccstrlist"} { set type ccstr lappend my_attrs STRINGLIST } set decl ${macro_prefix}_FLAG${PD} set defn DEFN_$decl set attr "" set prefix "" foreach a $my_attrs { append attr "${prefix}JVMFlag::${a}" set prefix " | " } if {$range != ""} { append attr "${prefix}JVMFlag::RANGE" set prefix " | " } if {$constraint != ""} { append attr "${prefix}JVMFlag::CONSTRAINT" set prefix " | " } if {$attr == ""} { set attr JVMFlag::DEFAULT } set sspc [expr 8 - [string length $type] - [string length ${PD}]] set t "$type,[spaces $sspc]" set dec "" append dec "${decl}($t ${name}${defv_sep}${defv}, ${attr},\n" append dec "$docs);\n" set def "" append def "${defn}(${name});" if {$class == "lp64_product"} { # This is the declaration for 32-bit builds. set lp64_decl($name) "const $type $name = $defv; // !JVMFlag::LP64" } set all_decl($name) $dec set all_defn($name) $def if {$range != ""} { if {[info exists kind]} { append all_decl($name) " FLAG_CUSTOM_RANGE([spaces 2]$name, $kind);\n" } elseif {[regexp :: $range]} { set warning "TODO: to avoid circular dependency, the min/max cannot be declared in header file" append all_decl($name) " //$warning\n" append all_decl($name) " //FLAG_RANGE([spaces 9]$name, $range);\n" set list [split $range ,] append all_defn($name) "\n // $warning" append all_defn($name) "\n inline FLAG_TYPE_$name FLAG_MIN_${name}() { return [string trim [lindex $list 0]]; }" append all_defn($name) "\n inline FLAG_TYPE_$name FLAG_MAX_${name}() { return [string trim [lindex $list 1]]; }\n " } else { append all_decl($name) " FLAG_RANGE([spaces 9]$name, $range);\n" } if {[info exists kind]} { append all_defn($name) " ${def_prefix}_CUSTOM_RANGE($name);" } else { append all_defn($name) " ${def_prefix}_RANGE($name);" } } if {$constraint != ""} { append all_decl($name) " FLAG_CONSTRAINT([spaces 4]$name, $constraint);\n" append all_defn($name) " ${def_prefix}_CONSTRAINT($name);"; } if {[info exists flagcond($name)]} { set cond $flagcond($name) set all_decl($name) "${cond}($dec)\n" set all_defn($name) "${cond}($def)\n" } append all_decl($name) \n set all_comments($name) $comment lappend all_names $name } proc get_last_match {text pat} { set match "" while {[regexp $pat $text dummy match]} { regexp $pat $text "" text } return $match } proc parse_range {text} { if {[regexp {\uffff.*range *[\(](.*)} $text dummy match]} { regsub {/[*].*} $match "" match regsub {constraint[\(].*} $match "" match regsub {[\)][^\)]*$} $match "" match return $match } else { return "" } } proc check_conditionals {data} { global flagdecl flagcond set pat "(\[A-Z0-9_\]+)\[\(\]($flagdecl)" foreach line [split $data \n] { if {[regexp $pat $line dummy cond]} { set flagname [string trim [lindex [split $line ,] 1]] set flagcond($flagname) $cond } } } proc get_comments {data} { #set t $data regsub -all {/[*]} $data \uffee data regsub -all {[*]/} $data \uffef data regsub ".*\[\)\] *\\\\\n" $data "" data set data "\n$data\n" #set y $data set list {} set start "============================================================\n" set pat "\n *\uffee(\[^\uffef\]+)\uffef" while {[regexp $pat $data dummy match]} { regsub $pat $data "\n" data lappend list $match #puts $start$match #set start "" #if {[string trim $match] == "2^24"} { # puts $t # puts ==$y # exit #} } return $list } proc process {data} { global flagdecl regsub {^#define [A-Za-z0-9_]+[(][^)]+.} $data "" data set data [string trim $data] set mark_begin_pat "($flagdecl)\[(\]" # get rid of the double close parens of JFR_ONLY(product(bool, FlightRecorder, ".....")) regsub -all {\"[\)][\)] *\\} $data "\"\) \\\\" data check_conditionals $data regsub -all $mark_begin_pat $data "\ufff0\\1\ufffe" data regsub -all "\" *\[\)\] *(\\\\|$)" $data "\uffff" data set flag_pat "($flagdecl)\ufffe(\[^\uffff\]+)\uffff" set next_comment "" foreach part [split $data \ufff0] { set range "" set constraint "" set comment $next_comment set next_comment [get_comments $part] if {[regexp $flag_pat $part match class]} { regsub .*\ufffe $match "" match regsub \uffff $match "\"" match set list [split $data \ufffc] set range [parse_range $part] regexp {constraint[(]([^)]+).} $part dummy constraint set newflag [replace $class $match $range $constraint $comment] } } set data [format_output all_decl lp64_decl 1] # Remove all whitespaces and empty lines ... while {[regsub -all "\n *\\\\\n" $data "\n" data]} {} regsub -all " *\\\\\n" $data "\n" data #regsub -all "\n +" $data "\n" data #regsub -all "\n+" $data "\n" data # ... but leave an empty line before comments regsub -all ";\n/" $data ";\n\n/" data return $data } proc format_output {allarr lp64arr use_comments} { global copyright all_names upvar #0 $allarr all upvar #0 $lp64arr lp64 set out "" set list $all_names foreach name $list { if {![info exists lp64($name)]} { append out [format_one_flag $allarr $name $use_comments] } } if {[info exists lp64]} { append out "\n#ifdef _LP64\n" foreach name $list { if {[info exists lp64($name)]} { append out [format_one_flag $allarr $name $use_comments] } } if {$allarr == "all_decl"} { append out "#elif defined(IS_DECLARING_FLAG)\n" foreach name $list { if {[info exists lp64($name)]} { append out $lp64($name)\n } } } append out "#endif // _LP64\n" } regsub -all "\n\[)\]" $out ")" out return $out } proc format_one_flag {allarr name use_comments} { upvar #0 $allarr all global all_comments set cmt $all_comments($name) set comments "" if {$cmt != "" && $use_comments} { set comments "\n" foreach line $cmt { append comments " // $line\n" } } if {$use_comments} { set newline "" } else { set newline "\n" } return $comments$all($name)$newline } set copyright {/* * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */} proc write_c_file {hppfile flagsfile ifdef common} { global copyright all_decl # put the C file first so we can compile it first without waiting for the other 1000 files regsub {[.]hpp} $hppfile ".cpp" cppfile if {![info exists all_decl]} { if {[file exists $cppfile]} { puts "hg remove $cppfile" } return } set data "" if {[catch { set fd [open $cppfile] set data [read $fd] close $fd }]} { set data $copyright append data "\n" append data "#include \"precompiled.hpp\"\n" } regsub "#include \"runtime/flags/newFlagInstantiate.hpp\"\n" $data "" data if {[file tail $cppfile] != "c2_globals.cpp"} { regsub "#include \"runtime/globals.hpp\"\n" $data "" data } regsub "// -- Define all JVM flags that have been declared.*" $data "" data set data [string trimright $data] append data "\n" append data "\n" append data "// -- Define all JVM flags that have been declared in $hppfile\n\n" if {$common != ""} { append data "// Add JVMFlag::$common to the JVMFlag::attr() for all flags defined in this file\n" append data "#ifdef FLAG_COMMON_ATTRS\n" append data "#undef FLAG_COMMON_ATTRS\n" append data "#endif\n" append data "#define FLAG_COMMON_ATTRS JVMFlag::$common\n" append data "\n" } #if {$ifdef != ""} { # append data "#if $ifdef\n" #} append data "#include \"[file tail $hppfile]\"\n" append data "#include \"runtime/flags/jvmFlag.inline.hpp\"\n" append data [format_output all_defn lp64_defn 0] append data "\n" if {$common != ""} { #append data "#undef FLAG_COMMON_ATTRS\n" #append data "#define FLAG_COMMON_ATTRS 0\n" } set fd [open $cppfile.tmp w+] puts $fd "[string trim $data]" close $fd move_file $cppfile.tmp $cppfile } set allhdrs {} foreach {file macro ifdef common} { cpu/aarch64/globals_aarch64.hpp ARCH_FLAGS {} ARCH cpu/arm/globals_arm.hpp ARCH_FLAGS {} ARCH cpu/ppc/globals_ppc.hpp ARCH_FLAGS {} ARCH cpu/s390/globals_s390.hpp ARCH_FLAGS {} ARCH cpu/sparc/globals_sparc.hpp ARCH_FLAGS {} ARCH cpu/x86/globals_x86.hpp ARCH_FLAGS {} ARCH cpu/zero/globals_zero.hpp ARCH_FLAGS {} ARCH os/aix/globals_aix.hpp RUNTIME_OS_FLAGS {} {} os/bsd/globals_bsd.hpp RUNTIME_OS_FLAGS {} {} os/linux/globals_linux.hpp RUNTIME_OS_FLAGS {} {} os/solaris/globals_solaris.hpp RUNTIME_OS_FLAGS {} {} os/windows/globals_windows.hpp RUNTIME_OS_FLAGS {} {} share/c1/c1_globals.hpp C1_FLAGS COMPILER1 C1 share/gc/epsilon/epsilon_globals.hpp GC_EPSILON_FLAGS INCLUDE_EPSILONGC {} share/gc/g1/g1_globals.hpp GC_G1_FLAGS INCLUDE_G1GC {} share/gc/parallel/parallel_globals.hpp GC_PARALLEL_FLAGS INCLUDE_PARALLELGC {} share/gc/serial/serial_globals.hpp GC_SERIAL_FLAGS INCLUDE_SERIALGC {} share/gc/shared/gc_globals.hpp GC_FLAGS {} {} share/gc/shenandoah/shenandoah_globals.hpp GC_SHENANDOAH_FLAGS INCLUDE_SHENANDOAHGC {} share/gc/z/z_globals.hpp GC_Z_FLAGS INCLUDE_ZGC {} share/runtime/globals.hpp RUNTIME_FLAGS {} {} share/jvmci/jvmci_globals.hpp JVMCI_FLAGS INCLUDE_JVMCI JVMCI share/opto/c2_globals.hpp C2_FLAGS COMPILER2 C2 } { doit $file $macro $ifdef $common }