├── .github ├── configs │ └── base.yml ├── scripts │ ├── ci-build.sh │ ├── ci-check-lineends.sh │ ├── ci-checkout.sh │ ├── ci-expected-results.yml │ ├── ci-matrix-result-check.py │ ├── ci-setup.sh │ ├── ci-style.sh │ ├── ci-test-assertions.sh │ ├── ci-test-extended.sh │ ├── ci-test-forwarding-on-side.sh │ ├── ci-test-malloc-mark-sweep.sh │ ├── ci-test-mark-in-header.sh │ ├── ci-test-minimal.sh │ ├── ci-test-only-normal-no-compressed-oops.sh │ ├── ci-test-only-normal.sh │ ├── ci-test-only-weak-ref.sh │ ├── ci-test-sanity.sh │ ├── ci-test-vo-bit.sh │ ├── common.sh │ ├── patch-mmtk-dep.py │ ├── pgo-build.sh │ ├── style-check.sh │ └── visualize-expected-results.py └── workflows │ ├── build.yml │ ├── run-dacapo-2006.yml │ ├── run-dacapo-chopin.yml │ ├── stylecheck.yml │ └── test-pr.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── COPYRIGHT ├── LICENSE-APACHE ├── LICENSE-MIT ├── README-legacy.md ├── README.md ├── TESTING-legacy.md ├── ThirdPartyHeap.md ├── mmtk ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── rust-toolchain └── src │ ├── abi.rs │ ├── active_plan.rs │ ├── api.rs │ ├── build_info.rs │ ├── collection.rs │ ├── gc_work.rs │ ├── lib.rs │ ├── object_model.rs │ ├── object_scanning.rs │ ├── reference_glue.rs │ ├── scanning.rs │ ├── slots.rs │ └── vm_metadata │ ├── constants.rs │ └── mod.rs ├── openjdk ├── CompileThirdPartyHeap.gmk ├── barriers │ ├── mmtkNoBarrier.hpp │ ├── mmtkObjectBarrier.cpp │ └── mmtkObjectBarrier.hpp ├── mmtk.h ├── mmtkBarrierSet.cpp ├── mmtkBarrierSet.hpp ├── mmtkBarrierSetAssembler_x86.cpp ├── mmtkBarrierSetAssembler_x86.hpp ├── mmtkBarrierSetC1.cpp ├── mmtkBarrierSetC1.hpp ├── mmtkBarrierSetC2.cpp ├── mmtkBarrierSetC2.hpp ├── mmtkCollectorPolicy.hpp ├── mmtkCollectorThread.cpp ├── mmtkCollectorThread.hpp ├── mmtkFinalizerThread.cpp ├── mmtkFinalizerThread.hpp ├── mmtkHeap.cpp ├── mmtkHeap.hpp ├── mmtkMemoryPool.cpp ├── mmtkMemoryPool.hpp ├── mmtkMutator.cpp ├── mmtkMutator.hpp ├── mmtkRootsClosure.hpp ├── mmtkUpcalls.cpp ├── mmtkUpcalls.hpp ├── mmtkVMCompanionThread.cpp ├── mmtkVMCompanionThread.hpp ├── mmtkVMOperation.cpp ├── mmtkVMOperation.hpp ├── thirdPartyHeap.cpp ├── thirdPartyHeap.hpp ├── thirdPartyHeapArguments.cpp ├── thirdPartyHeapArguments.hpp ├── thirdPartyHeapBarrierSet.hpp ├── thirdPartyHeapBarrierSetC2.hpp ├── thirdPartyHeapMutator.hpp ├── thirdPartyHeapVMOperation.cpp └── thirdPartyHeapVMOperation.hpp └── tools └── tracing └── timeline ├── capture_openjdk.bt └── visualize_openjdk.py /.github/configs/base.yml: -------------------------------------------------------------------------------- 1 | includes: 2 | - "$RUNNING_NG_PACKAGE_DATA/base/runbms.yml" 3 | 4 | suites: 5 | dacapo-23.9-RC3-chopin-ci: 6 | type: DaCapo 7 | # Need running-ng to support 23.9 8 | release: evaluation 9 | path: "DACAPO_PATH/dacapo-23.9-RC3-chopin.jar" 10 | minheap: mmtk-openjdk-11-MarkCompact 11 | # Min heap values are from dacapo-evaluation-git-04132797 12 | minheap_values: 13 | mmtk-openjdk-11-MarkCompact: 14 | avrora: 8 15 | batik: 426 16 | biojava: 197 17 | cassandra: 117 18 | eclipse: 439 19 | fop: 24 20 | graphchi: 195 21 | h2: 1122 22 | h2o: 136 23 | jme: 236 24 | jython: 48 25 | kafka: 243 26 | luindex: 25 27 | lusearch: 36 28 | pmd: 291 29 | spring: 110 30 | sunflow: 37 31 | tradebeans: .inf 32 | tradesoap: .inf 33 | tomcat: 55 34 | xalan: 19 35 | zxing: 427 36 | nominal-heap-sizes: 37 | avrora: 7 38 | batik: 192 39 | biojava: 97 40 | cassandra: 74 41 | eclipse: 346 42 | fop: 17 43 | graphchi: 179 44 | h2: 506 45 | h2o: 102 46 | jme: 29 47 | jython: 29 48 | kafka: 207 49 | luindex: 44 50 | lusearch: 19 51 | pmd: 114 52 | spring: 47 53 | sunflow: 25 54 | tradebeans: 101 55 | tradesoap: 89 56 | tomcat: 17 57 | xalan: 9 58 | zxing: 66 59 | timing_iteration: 1 60 | timeout: 7200 61 | 62 | overrides: 63 | invocations: 1 64 | remote_host: null 65 | 66 | modifiers: 67 | mmtk_gc: 68 | type: "EnvVar" 69 | var: "MMTK_PLAN" 70 | val: "{0}" 71 | fail_on_oom: 72 | type: JVMArg 73 | val: "-XX:+CrashOnOutOfMemoryError" 74 | preserve: 75 | type: ProgramArg 76 | val: "-preserve" 77 | 78 | plugins: 79 | keep_stdout_stderr: 80 | type: CopyFile 81 | patterns: 82 | - "scratch/stdout.log" 83 | - "scratch/stderr.log" 84 | 85 | runtimes: 86 | jdk11-master: 87 | type: OpenJDK 88 | release: 11 89 | home: "/home/runner/work/mmtk-openjdk/mmtk-openjdk/bundles/jdk" 90 | 91 | configs: 92 | - "jdk11-master|ms|s|fail_on_oom|tph|preserve|mmtk_gc-SemiSpace" 93 | - "jdk11-master|ms|s|fail_on_oom|tph|preserve|mmtk_gc-GenCopy" 94 | - "jdk11-master|ms|s|fail_on_oom|tph|preserve|mmtk_gc-Immix" 95 | - "jdk11-master|ms|s|fail_on_oom|tph|preserve|mmtk_gc-GenImmix" 96 | - "jdk11-master|ms|s|fail_on_oom|tph|preserve|mmtk_gc-StickyImmix" 97 | - "jdk11-master|ms|s|fail_on_oom|tph|preserve|mmtk_gc-MarkSweep" 98 | - "jdk11-master|ms|s|fail_on_oom|tph|preserve|mmtk_gc-MarkCompact" 99 | 100 | benchmarks: 101 | dacapo-23.9-RC3-chopin-ci: 102 | -------------------------------------------------------------------------------- /.github/scripts/ci-build.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | ensure_env OPENJDK_PATH 6 | 7 | # Use fastdebug if DEBUG_LEVEL is unset 8 | DEBUG_LEVEL=${DEBUG_LEVEL:="fastdebug"} 9 | 10 | # Build target. Could be empty, or product-bundles. 11 | build_target=$1 12 | 13 | # Build product bundle 14 | cd $OPENJDK_PATH 15 | sh configure --disable-warnings-as-errors --with-debug-level=$DEBUG_LEVEL 16 | make CONF=linux-x86_64-normal-server-$DEBUG_LEVEL THIRD_PARTY_HEAP=$BINDING_PATH/openjdk $OPENJDK_BUILD_TARGET 17 | -------------------------------------------------------------------------------- /.github/scripts/ci-check-lineends.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FN=$1 4 | 5 | LAST_CHAR="$(tail -c 1 $FN | od -A n -t x1)" 6 | if test "$LAST_CHAR" != " 0a"; then 7 | echo "File does not end with newline:" $FN 8 | fi 9 | 10 | LINEEND="$(dos2unix -i $FN | awk '{print $1 " " $3}')" 11 | if test "$LINEEND" != "0 0"; then 12 | echo "File contains non-UNIX line endings:" $FN 13 | fi 14 | -------------------------------------------------------------------------------- /.github/scripts/ci-checkout.sh: -------------------------------------------------------------------------------- 1 | # ci-checkout.sh 2 | set -ex 3 | 4 | . $(dirname "$0")/common.sh 5 | 6 | OPENJDK_URL=`cargo read-manifest --manifest-path=$BINDING_PATH/mmtk/Cargo.toml | python3 -c 'import json,sys; print(json.load(sys.stdin)["metadata"]["openjdk"]["openjdk_repo"])'` 7 | OPENJDK_VERSION=`cargo read-manifest --manifest-path=$BINDING_PATH/mmtk/Cargo.toml | python3 -c 'import json,sys; print(json.load(sys.stdin)["metadata"]["openjdk"]["openjdk_version"])'` 8 | 9 | # Use default openjdk path if it is not set (this is only need when MMTk core calls the script) 10 | OPENJDK_PATH=${OPENJDK_PATH:="$BINDING_PATH/repos/openjdk"} 11 | 12 | rm -rf $OPENJDK_PATH 13 | git clone $OPENJDK_URL $OPENJDK_PATH 14 | git -C $OPENJDK_PATH checkout $OPENJDK_VERSION 15 | -------------------------------------------------------------------------------- /.github/scripts/ci-expected-results.yml: -------------------------------------------------------------------------------- 1 | results: 2 | linux-x64: 3 | fastdebug: 4 | avrora: 5 | SemiSpace: pass 6 | GenCopy: pass 7 | Immix: pass 8 | GenImmix: pass 9 | StickyImmix: pass 10 | MarkSweep: pass 11 | MarkCompact: pass 12 | batik: 13 | SemiSpace: pass 14 | GenCopy: pass 15 | Immix: pass 16 | GenImmix: pass 17 | StickyImmix: pass 18 | MarkSweep: pass 19 | MarkCompact: pass 20 | biojava: 21 | SemiSpace: pass 22 | GenCopy: pass 23 | Immix: pass 24 | GenImmix: pass 25 | StickyImmix: pass 26 | MarkSweep: pass 27 | MarkCompact: pass 28 | cassandra: 29 | SemiSpace: pass 30 | GenCopy: pass 31 | Immix: pass 32 | GenImmix: pass 33 | StickyImmix: pass 34 | MarkSweep: ignore 35 | MarkCompact: ignore 36 | eclipse: 37 | SemiSpace: pass 38 | GenCopy: pass 39 | Immix: pass 40 | GenImmix: pass 41 | StickyImmix: pass 42 | MarkSweep: ignore 43 | MarkCompact: pass 44 | fop: 45 | SemiSpace: pass 46 | GenCopy: pass 47 | Immix: pass 48 | GenImmix: pass 49 | StickyImmix: pass 50 | MarkSweep: ignore 51 | MarkCompact: pass 52 | graphchi: 53 | SemiSpace: pass 54 | GenCopy: pass 55 | Immix: pass 56 | GenImmix: pass 57 | StickyImmix: pass 58 | MarkSweep: pass 59 | MarkCompact: pass 60 | h2: 61 | SemiSpace: pass 62 | GenCopy: pass 63 | Immix: pass 64 | GenImmix: pass 65 | StickyImmix: pass 66 | MarkSweep: ignore 67 | MarkCompact: pass 68 | h2o: 69 | SemiSpace: pass 70 | GenCopy: pass 71 | Immix: pass 72 | GenImmix: pass 73 | StickyImmix: pass 74 | MarkSweep: pass 75 | MarkCompact: pass 76 | jme: 77 | SemiSpace: pass 78 | GenCopy: pass 79 | Immix: pass 80 | GenImmix: pass 81 | StickyImmix: pass 82 | MarkSweep: pass 83 | MarkCompact: pass 84 | jython: 85 | SemiSpace: pass 86 | GenCopy: pass 87 | Immix: pass 88 | GenImmix: pass 89 | StickyImmix: pass 90 | MarkSweep: ignore 91 | MarkCompact: pass 92 | kafka: 93 | SemiSpace: pass 94 | GenCopy: pass 95 | Immix: pass 96 | GenImmix: pass 97 | StickyImmix: pass 98 | MarkSweep: pass 99 | MarkCompact: ignore 100 | luindex: 101 | SemiSpace: pass 102 | GenCopy: pass 103 | Immix: pass 104 | GenImmix: pass 105 | StickyImmix: pass 106 | MarkSweep: pass 107 | MarkCompact: pass 108 | lusearch: 109 | SemiSpace: pass 110 | GenCopy: pass 111 | Immix: pass 112 | GenImmix: ignore 113 | StickyImmix: pass 114 | MarkSweep: pass 115 | MarkCompact: pass 116 | pmd: 117 | SemiSpace: pass 118 | GenCopy: pass 119 | Immix: pass 120 | GenImmix: pass 121 | StickyImmix: pass 122 | MarkSweep: pass 123 | MarkCompact: pass 124 | sunflow: 125 | SemiSpace: pass 126 | GenCopy: pass 127 | Immix: pass 128 | GenImmix: pass 129 | StickyImmix: pass 130 | MarkSweep: pass 131 | MarkCompact: pass 132 | tomcat: 133 | SemiSpace: pass 134 | GenCopy: pass 135 | Immix: pass 136 | GenImmix: pass 137 | StickyImmix: pass 138 | MarkSweep: pass 139 | MarkCompact: pass 140 | xalan: 141 | SemiSpace: pass 142 | GenCopy: pass 143 | Immix: pass 144 | GenImmix: pass 145 | StickyImmix: ignore 146 | MarkSweep: pass 147 | MarkCompact: pass 148 | zxing: 149 | SemiSpace: pass 150 | GenCopy: pass 151 | Immix: pass 152 | GenImmix: pass 153 | StickyImmix: pass 154 | MarkSweep: pass 155 | MarkCompact: pass 156 | 157 | release: 158 | avrora: 159 | SemiSpace: pass 160 | GenCopy: pass 161 | Immix: pass 162 | GenImmix: pass 163 | StickyImmix: pass 164 | MarkSweep: pass 165 | MarkCompact: pass 166 | batik: 167 | SemiSpace: pass 168 | GenCopy: pass 169 | Immix: pass 170 | GenImmix: pass 171 | StickyImmix: pass 172 | MarkSweep: pass 173 | MarkCompact: pass 174 | biojava: 175 | SemiSpace: pass 176 | GenCopy: pass 177 | Immix: pass 178 | GenImmix: pass 179 | StickyImmix: pass 180 | MarkSweep: pass 181 | MarkCompact: pass 182 | cassandra: 183 | SemiSpace: pass 184 | GenCopy: pass 185 | Immix: pass 186 | GenImmix: pass 187 | StickyImmix: pass 188 | MarkSweep: ignore 189 | MarkCompact: pass 190 | eclipse: 191 | SemiSpace: pass 192 | GenCopy: pass 193 | Immix: pass 194 | GenImmix: pass 195 | StickyImmix: pass 196 | MarkSweep: ignore 197 | MarkCompact: pass 198 | fop: 199 | SemiSpace: pass 200 | GenCopy: pass 201 | Immix: pass 202 | GenImmix: pass 203 | StickyImmix: pass 204 | MarkSweep: ignore 205 | MarkCompact: pass 206 | graphchi: 207 | SemiSpace: pass 208 | GenCopy: pass 209 | Immix: pass 210 | GenImmix: pass 211 | StickyImmix: pass 212 | MarkSweep: pass 213 | MarkCompact: pass 214 | h2: 215 | SemiSpace: pass 216 | GenCopy: pass 217 | Immix: pass 218 | GenImmix: pass 219 | StickyImmix: pass 220 | MarkSweep: ignore 221 | MarkCompact: pass 222 | h2o: 223 | SemiSpace: pass 224 | GenCopy: pass 225 | Immix: pass 226 | GenImmix: pass 227 | StickyImmix: pass 228 | MarkSweep: ignore 229 | MarkCompact: pass 230 | jme: 231 | SemiSpace: pass 232 | GenCopy: pass 233 | Immix: pass 234 | GenImmix: pass 235 | StickyImmix: pass 236 | MarkSweep: pass 237 | MarkCompact: pass 238 | jython: 239 | SemiSpace: pass 240 | GenCopy: pass 241 | Immix: pass 242 | GenImmix: pass 243 | StickyImmix: pass 244 | MarkSweep: ignore 245 | MarkCompact: pass 246 | kafka: 247 | SemiSpace: pass 248 | GenCopy: pass 249 | Immix: pass 250 | GenImmix: pass 251 | StickyImmix: pass 252 | MarkSweep: pass 253 | MarkCompact: pass 254 | luindex: 255 | SemiSpace: pass 256 | GenCopy: pass 257 | Immix: pass 258 | GenImmix: pass 259 | StickyImmix: pass 260 | MarkSweep: pass 261 | MarkCompact: pass 262 | lusearch: 263 | SemiSpace: pass 264 | GenCopy: pass 265 | Immix: pass 266 | GenImmix: pass 267 | StickyImmix: pass 268 | MarkSweep: pass 269 | MarkCompact: pass 270 | pmd: 271 | SemiSpace: pass 272 | GenCopy: pass 273 | Immix: pass 274 | GenImmix: pass 275 | StickyImmix: pass 276 | MarkSweep: pass 277 | MarkCompact: pass 278 | sunflow: 279 | SemiSpace: pass 280 | GenCopy: pass 281 | Immix: pass 282 | GenImmix: pass 283 | StickyImmix: pass 284 | MarkSweep: pass 285 | MarkCompact: pass 286 | tomcat: 287 | SemiSpace: pass 288 | GenCopy: pass 289 | Immix: pass 290 | GenImmix: ignore 291 | StickyImmix: pass 292 | MarkSweep: pass 293 | MarkCompact: pass 294 | xalan: 295 | SemiSpace: ignore 296 | GenCopy: ignore 297 | Immix: pass 298 | GenImmix: ignore 299 | StickyImmix: pass 300 | MarkSweep: pass 301 | MarkCompact: pass 302 | zxing: 303 | SemiSpace: pass 304 | GenCopy: pass 305 | Immix: pass 306 | GenImmix: pass 307 | StickyImmix: pass 308 | MarkSweep: pass 309 | MarkCompact: pass 310 | -------------------------------------------------------------------------------- /.github/scripts/ci-matrix-result-check.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import sys 3 | import os 4 | import re 5 | 6 | if len(sys.argv) < 5: 7 | raise ValueError("Invalid arguments") 8 | 9 | script_dir = os.path.dirname(os.path.abspath(__file__)); 10 | config_path = os.path.join(script_dir, "..", "configs", "base.yml") 11 | expected_results_path = os.path.join(script_dir, "ci-expected-results.yml") 12 | 13 | arch = sys.argv[1] 14 | build = sys.argv[2] 15 | benchmark = sys.argv[3] 16 | log_dir = sys.argv[4] 17 | 18 | def read_in_plans(): 19 | # Load the YAML file 20 | with open(config_path, "r") as f: 21 | data = yaml.safe_load(f) 22 | 23 | # Extract the values from the "configs" field 24 | configs = data["configs"] 25 | 26 | # Define the dictionary to store the values 27 | results = {} 28 | 29 | pattern = r"mmtk_gc-(.+?)(\||$)" 30 | 31 | # Loop through each property in configs 32 | for i, prop in enumerate(configs): 33 | # Extract the value behind "mmtk_gc-" 34 | m = re.search(pattern, prop) 35 | if m: 36 | value = m.group(1) 37 | else: 38 | raise ValueError(f"Cannot find a plan string in {prop}") 39 | 40 | # Store the value in the dictionary 41 | key = chr(97+i) 42 | results[key] = value 43 | 44 | return results 45 | 46 | def read_in_actual_results(line, plan_dict): 47 | # Read the input from stdin 48 | input_string = line.strip() 49 | 50 | # Extract the benchmark name and discard the rest 51 | benchmark_name = input_string.split()[0] 52 | input_string = input_string.removeprefix(benchmark_name) 53 | 54 | # Extract the strings from the input, like 0abcdef or 1a.c.ef 55 | pattern = r"(\d+[a-z\.]+)" 56 | matches = re.findall(pattern, input_string) 57 | 58 | # list[0] = "abcdef", list[1] = "a.cd.f", etc 59 | raw_results = list() 60 | for m in matches: 61 | print(m) 62 | index = int(m[0]) 63 | result = m[1:] 64 | assert len(raw_results) == index 65 | raw_results.append(result) 66 | 67 | # Format the raw results into a dict 68 | # dict['SemiSpace'] = true/false 69 | result_dict = {} 70 | for s in raw_results: 71 | # Start with a 72 | key = 97 73 | for c in s: 74 | plan = plan_dict[chr(key)] 75 | key += 1 76 | success = (c != '.') 77 | if plan in result_dict: 78 | result_dict[plan] = result_dict[plan] and success 79 | else: 80 | result_dict[plan] = success 81 | 82 | # Rewrite True/False into pass/fail 83 | for key in result_dict.keys(): 84 | if result_dict[key]: 85 | result_dict[key] = 'pass' 86 | else: 87 | result_dict[key] = 'fail' 88 | 89 | return result_dict 90 | 91 | def read_in_expected_results(build, benchmark): 92 | # Load the YAML file 93 | with open(expected_results_path, "r") as f: 94 | data = yaml.safe_load(f) 95 | 96 | return data["results"][arch][build][benchmark] 97 | 98 | def print_log(directory, search_string): 99 | import gzip 100 | 101 | # Check if the provided path is a directory 102 | if not os.path.isdir(directory): 103 | print(f"Error: {directory} is not a directory.") 104 | sys.exit(1) 105 | 106 | # Walk through the directory 107 | for root, dirs, files in os.walk(directory): 108 | for file in files: 109 | if search_string in file: 110 | file_path = os.path.join(root, file) 111 | # Check if the file has a .gz extension 112 | if file_path.endswith('log.gz'): 113 | with gzip.open(file_path, 'rt') as f: 114 | content = f.read() 115 | print(f"----------------------------------------------") 116 | print(f"START: {file_path}") 117 | print(content) 118 | print(f"END: {file_path}") 119 | print(f"----------------------------------------------") 120 | 121 | # dict['a'] = 'SemiSpace', etc 122 | plan_dict = read_in_plans() 123 | 124 | actual = read_in_actual_results(sys.stdin.readline(), plan_dict) 125 | expected = read_in_expected_results(build, benchmark) 126 | 127 | print("Expected:") 128 | print(expected) 129 | print("Actual:") 130 | print(actual) 131 | 132 | print("=====") 133 | 134 | # Return code. If we ignore results, we may still return 0 (no error) 135 | error_no = 0 136 | # All the failed plans. As long as the run failed, we print the log for the plan, even if the result is ignored. 137 | failed_plans = [] 138 | 139 | for plan in expected: 140 | if plan in actual: 141 | if actual[plan] == 'fail': 142 | failed_plans.append(plan) 143 | 144 | if expected[plan] == "ignore": 145 | print(f"Result for {plan} is ignored") 146 | continue 147 | 148 | if expected[plan] != actual[plan]: 149 | error_no = 1 150 | if expected[plan] == "pass": 151 | print(f"Expect {plan} to pass, but it failed.") 152 | else: 153 | print(f"Expect {plan} to fail, but it passed.") 154 | print(f"- If we have fixed a bug and expect the benchmark to run, please update ci-expected-results.yml") 155 | 156 | print(f"\nPrint logs for all failed runs: {failed_plans}\n") 157 | 158 | for failed_plan in failed_plans: 159 | print_log(log_dir, failed_plan) 160 | 161 | exit(error_no) 162 | -------------------------------------------------------------------------------- /.github/scripts/ci-setup.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | # Install nightly rust 6 | rustup toolchain install $RUSTUP_TOOLCHAIN 7 | rustup target add i686-unknown-linux-gnu --toolchain $RUSTUP_TOOLCHAIN 8 | rustup component add clippy --toolchain $RUSTUP_TOOLCHAIN 9 | rustup component add rustfmt --toolchain $RUSTUP_TOOLCHAIN 10 | rustup override set $RUSTUP_TOOLCHAIN 11 | 12 | # Install running 13 | pip3 install running-ng 14 | 15 | # Install dependencies 16 | sudo apt-get update -y 17 | sudo apt-get install dos2unix 18 | sudo apt-get install build-essential libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libasound2-dev libxrandr-dev 19 | -------------------------------------------------------------------------------- /.github/scripts/ci-style.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | export RUSTFLAGS="-D warnings" 6 | 7 | pushd $BINDING_PATH/mmtk 8 | cargo clippy 9 | cargo clippy --release 10 | 11 | cargo fmt -- --check 12 | popd 13 | 14 | find $BINDING_PATH/openjdk \ 15 | $BINDING_PATH/mmtk \ 16 | -name '*.hpp' \ 17 | -o -name '*.cpp' \ 18 | -o -name '*.rs' \ 19 | -o -name '*.toml' \ 20 | -o -name '*.gmk' \ 21 | -exec ./ci-check-lineends.sh '{}' \; 22 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-assertions.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | unset JAVA_TOOL_OPTIONS 6 | 7 | run_subset() { 8 | heap_multiplier=$1 9 | 10 | runbms_dacapo2006_with_heap_multiplier fop $heap_multiplier 11 | runbms_dacapo2006_with_heap_multiplier luindex $heap_multiplier 12 | } 13 | 14 | # -- SemiSpace -- 15 | export MMTK_PLAN=SemiSpace 16 | 17 | run_subset 4 18 | 19 | # --- Immix --- 20 | export MMTK_PLAN=Immix 21 | 22 | run_subset 4 23 | 24 | # --- GenImmix --- 25 | export MMTK_PLAN=GenImmix 26 | 27 | run_subset 4 28 | 29 | # --- StickyImmix --- 30 | export MMTK_PLAN=StickyImmix 31 | 32 | run_subset 4 33 | 34 | # -- GenCopy -- 35 | export MMTK_PLAN=GenCopy 36 | 37 | run_subset 4 38 | 39 | # -- NoGC -- 40 | export MMTK_PLAN=NoGC 41 | 42 | runbms_dacapo2006_with_heap_size fop 1000 1000 43 | runbms_dacapo2006_with_heap_size luindex 1000 1000 44 | 45 | # --- MarkSweep --- 46 | export MMTK_PLAN=MarkSweep 47 | 48 | run_subset 8 49 | 50 | # -- PageProtect -- 51 | sudo sysctl -w vm.max_map_count=655300 52 | export MMTK_PLAN=PageProtect 53 | 54 | # Note: Disable compressed pointers as it does not work well with GC plans that uses virtual memory excessively. 55 | runbms_dacapo2006_with_heap_size fop 4000 4000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 56 | runbms_dacapo2006_with_heap_size luindex 4000 4000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 57 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-extended.sh: -------------------------------------------------------------------------------- 1 | set -ex 2 | 3 | . $(dirname "$0")/common.sh 4 | cur=$BINDING_PATH/.github/scripts 5 | 6 | # This script is only used by MMTk core. 7 | # OPENJDK_PATH is the default path set in ci-checkout.sh 8 | export OPENJDK_PATH=$BINDING_PATH/repos/openjdk 9 | export DEBUG_LEVEL=fastdebug 10 | export TEST_JAVA_BIN=$OPENJDK_PATH/build/linux-x86_64-normal-server-$DEBUG_LEVEL/jdk/bin/java 11 | 12 | # Download dacapo 13 | export DACAPO_PATH=$BINDING_PATH/dacapo 14 | mkdir -p $DACAPO_PATH 15 | wget https://downloads.sourceforge.net/project/dacapobench/archive/2006-10-MR2/dacapo-2006-10-MR2.jar -O $DACAPO_PATH/dacapo-2006-10-MR2.jar 16 | 17 | # Normal build 18 | $cur/ci-build.sh 19 | # Test 20 | $cur/ci-test-only-normal.sh 21 | $cur/ci-test-only-normal-no-compressed-oops.sh 22 | $cur/ci-test-only-weak-ref.sh 23 | 24 | # Build with extreme assertions 25 | MMTK_EXTREME_ASSERTIONS=1 $cur/ci-build.sh 26 | $cur/ci-test-assertions.sh 27 | 28 | # Build with vo bit 29 | MMTK_VO_BIT=1 $cur/ci-build.sh 30 | $cur/ci-test-vo-bit.sh 31 | 32 | # Build with malloc mark sweep 33 | MMTK_EXTREME_ASSERTIONS=1 MMTK_MALLOC_MARK_SWEEP=1 $cur/ci-build.sh 34 | $cur/ci-test-malloc-mark-sweep.sh 35 | 36 | # Build with sanity 37 | MMTK_SANITY=1 $cur/ci-build.sh 38 | $cur/ci-test-sanity.sh 39 | 40 | # Build with mark in header - comment this out as it takes too long. 41 | # export MMTK_MARK_IN_HEADER=1 42 | # export MMTK_MALLOC_MARK_SWEEP=1 43 | # $cur/ci-build.sh 44 | # $cur/ci-test-malloc-mark-sweep.sh 45 | # unset MMTK_MARK_IN_HEADER 46 | # unset MMTK_MALLOC_MARK_SWEEP 47 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-forwarding-on-side.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | unset JAVA_TOOL_OPTIONS 6 | 7 | run_subset() { 8 | heap_multiplier=$1 9 | 10 | runbms_dacapo2006_with_heap_multiplier antlr $heap_multiplier 11 | runbms_dacapo2006_with_heap_multiplier fop $heap_multiplier 12 | runbms_dacapo2006_with_heap_multiplier luindex $heap_multiplier 13 | runbms_dacapo2006_with_heap_multiplier lusearch $heap_multiplier 14 | } 15 | 16 | # Run plans that involve CopySpace and ImmixSpace which use forwarding bits. 17 | MMTK_PLAN=SemiSpace run_subset 4 18 | MMTK_PLAN=Immix run_subset 4 19 | MMTK_PLAN=GenCopy run_subset 4 20 | MMTK_PLAN=GenImmix run_subset 4 21 | MMTK_PLAN=StickyImmix run_subset 4 22 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-malloc-mark-sweep.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | run_test() { 6 | export MMTK_PLAN=MarkSweep 7 | 8 | # Malloc marksweep is horribly slow. We just run fop. 9 | runbms_dacapo2006_with_heap_multiplier fop 4 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 10 | 11 | unset MMTK_PLAN 12 | } 13 | 14 | unset JAVA_TOOL_OPTIONS 15 | unset MMTK_PLAN 16 | 17 | # --- Normal test --- 18 | run_test 19 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-mark-in-header.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | unset JAVA_TOOL_OPTIONS 6 | 7 | run_subset() { 8 | heap_multiplier=$1 9 | 10 | runbms_dacapo2006_with_heap_multiplier antlr $heap_multiplier 11 | runbms_dacapo2006_with_heap_multiplier fop $heap_multiplier 12 | runbms_dacapo2006_with_heap_multiplier luindex $heap_multiplier 13 | } 14 | 15 | # --- Immix --- 16 | # export MMTK_PLAN=Immix 17 | # run_subset 4 18 | 19 | # --- GenImmix --- 20 | # export MMTK_PLAN=GenImmix 21 | # run_subset 4 22 | 23 | # --- StickyImmix --- 24 | # export MMTK_PLAN=StickyImmix 25 | # run_subset 4 26 | 27 | # --- MarkSweep --- 28 | export MMTK_PLAN=MarkSweep 29 | 30 | run_subset 8 31 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-minimal.sh: -------------------------------------------------------------------------------- 1 | set -ex 2 | 3 | . $(dirname "$0")/common.sh 4 | cur=$BINDING_PATH/.github/scripts 5 | 6 | # This script is only used by MMTk core. 7 | # OPENJDK_PATH is the default path set in ci-checkout.sh 8 | export OPENJDK_PATH=$BINDING_PATH/repos/openjdk 9 | export DEBUG_LEVEL=fastdebug 10 | export TEST_JAVA_BIN=$OPENJDK_PATH/build/linux-x86_64-normal-server-$DEBUG_LEVEL/jdk/bin/java 11 | 12 | # Download dacapo 13 | export DACAPO_PATH=$BINDING_PATH/dacapo 14 | mkdir -p $DACAPO_PATH 15 | wget https://downloads.sourceforge.net/project/dacapobench/archive/2006-10-MR2/dacapo-2006-10-MR2.jar -O $DACAPO_PATH/dacapo-2006-10-MR2.jar 16 | 17 | # Normal build 18 | $cur/ci-build.sh 19 | # Test 20 | MMTK_PLAN=SemiSpace runbms_dacapo2006_with_heap_multiplier fop 4 21 | MMTK_PLAN=Immix runbms_dacapo2006_with_heap_multiplier fop 4 22 | MMTK_PLAN=GenImmix runbms_dacapo2006_with_heap_multiplier fop 4 23 | MMTK_PLAN=StickyImmix runbms_dacapo2006_with_heap_multiplier fop 4 24 | MMTK_PLAN=GenCopy runbms_dacapo2006_with_heap_multiplier fop 4 25 | MMTK_PLAN=MarkCompact runbms_dacapo2006_with_heap_multiplier fop 4 26 | MMTK_PLAN=MarkSweep runbms_dacapo2006_with_heap_multiplier fop 8 27 | MMTK_PLAN=NoGC runbms_dacapo2006_with_heap_size fop 1000 1000 28 | # Test heap resizing 29 | MMTK_PLAN=GenImmix runbms_dacapo2006_with_heap_size fop 20 100 30 | # Test compressed oops with heap range > 4GB 31 | MMTK_PLAN=GenImmix runbms_dacapo2006_with_heap_size fop 20 5000 32 | # Test no compressed oop 33 | MMTK_PLAN=GenImmix runbms_dacapo2006_with_heap_multiplier fop 4 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 34 | 35 | # Build with vo bit 36 | MMTK_VO_BIT=1 $cur/ci-build.sh 37 | # Test 38 | MMTK_PLAN=GenImmix runbms_dacapo2006_with_heap_multiplier fop 4 39 | 40 | # Build with on-the-side forwarding bits 41 | MMTK_FORWARDING_ON_SIDE=1 $cur/ci-build.sh 42 | # Test 43 | MMTK_PLAN=SemiSpace runbms_dacapo2006_with_heap_multiplier lusearch 4 44 | MMTK_PLAN=Immix runbms_dacapo2006_with_heap_multiplier lusearch 4 45 | MMTK_PLAN=GenCopy runbms_dacapo2006_with_heap_multiplier lusearch 4 46 | MMTK_PLAN=GenImmix runbms_dacapo2006_with_heap_multiplier lusearch 4 47 | MMTK_PLAN=StickyImmix runbms_dacapo2006_with_heap_multiplier lusearch 4 48 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-only-normal-no-compressed-oops.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | unset JAVA_TOOL_OPTIONS 6 | 7 | run_all_no_compressed_oop() { 8 | heap_multiplier=$1 9 | 10 | runbms_dacapo2006_with_heap_multiplier antlr $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 11 | runbms_dacapo2006_with_heap_multiplier fop $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 12 | runbms_dacapo2006_with_heap_multiplier luindex $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 13 | runbms_dacapo2006_with_heap_multiplier lusearch $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 14 | runbms_dacapo2006_with_heap_multiplier pmd $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 15 | runbms_dacapo2006_with_heap_multiplier hsqldb $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 16 | runbms_dacapo2006_with_heap_multiplier eclipse $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 17 | runbms_dacapo2006_with_heap_multiplier xalan $heap_multiplier -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 18 | } 19 | 20 | # --- SemiSpace --- 21 | export MMTK_PLAN=SemiSpace 22 | 23 | run_all_no_compressed_oop 4 24 | 25 | # Test heap resizing 26 | runbms_dacapo2006_with_heap_size fop 20 100 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 27 | 28 | # --- Immix --- 29 | export MMTK_PLAN=Immix 30 | 31 | run_all_no_compressed_oop 4 32 | 33 | # Test heap resizing 34 | runbms_dacapo2006_with_heap_size fop 20 100 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 35 | 36 | # --- Immix --- 37 | export MMTK_PLAN=GenImmix 38 | 39 | run_all_no_compressed_oop 4 40 | 41 | # Test heap resizing 42 | runbms_dacapo2006_with_heap_size fop 20 100 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 43 | 44 | # --- StickyImmix --- 45 | export MMTK_PLAN=StickyImmix 46 | 47 | run_all_no_compressed_oop 4 48 | 49 | # --- GenCopy --- 50 | export MMTK_PLAN=GenCopy 51 | 52 | run_all_no_compressed_oop 4 53 | 54 | # --- NoGC --- 55 | 56 | # Build 57 | export MMTK_PLAN=NoGC 58 | 59 | # Test - the benchmarks that are commented out do not work yet 60 | # Note: We could increase heap size when mmtk core can work for larger heap. We may get more benchmarks running. 61 | 62 | runbms_dacapo2006_with_heap_size antlr 1000 1000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 63 | runbms_dacapo2006_with_heap_size fop 1000 1000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 64 | runbms_dacapo2006_with_heap_size luindex 1000 1000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 65 | 66 | # --- MarkCompact --- 67 | export MMTK_PLAN=MarkCompact 68 | 69 | run_all_no_compressed_oop 4 70 | 71 | # --- MarkSweep --- 72 | export MMTK_PLAN=MarkSweep 73 | 74 | run_all_no_compressed_oop 4 75 | 76 | # --- PageProtect --- 77 | # Make sure this runs last in our tests unless we want to set it back to the default limit. 78 | sudo sysctl -w vm.max_map_count=655300 79 | 80 | export MMTK_PLAN=PageProtect 81 | 82 | # Note: Disable compressed pointers as it does not work well with GC plans that uses virtual memory excessively. 83 | runbms_dacapo2006_with_heap_size antlr 4000 4000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 84 | runbms_dacapo2006_with_heap_size fop 4000 4000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 85 | runbms_dacapo2006_with_heap_size luindex 4000 4000 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers 86 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-only-normal.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | unset JAVA_TOOL_OPTIONS 6 | 7 | run_all() { 8 | heap_multiplier=$1 9 | 10 | runbms_dacapo2006_with_heap_multiplier antlr $heap_multiplier 11 | runbms_dacapo2006_with_heap_multiplier fop $heap_multiplier 12 | runbms_dacapo2006_with_heap_multiplier luindex $heap_multiplier 13 | runbms_dacapo2006_with_heap_multiplier lusearch $heap_multiplier 14 | runbms_dacapo2006_with_heap_multiplier pmd $heap_multiplier 15 | runbms_dacapo2006_with_heap_multiplier hsqldb $heap_multiplier 16 | runbms_dacapo2006_with_heap_multiplier eclipse $heap_multiplier 17 | } 18 | 19 | # --- SemiSpace --- 20 | export MMTK_PLAN=SemiSpace 21 | 22 | run_all 4 23 | 24 | # Test heap resizing 25 | runbms_dacapo2006_with_heap_size fop 20 100 26 | 27 | # --- Immix --- 28 | export MMTK_PLAN=Immix 29 | 30 | run_all 4 31 | 32 | # Test heap resizing 33 | runbms_dacapo2006_with_heap_size fop 20 100 34 | 35 | # --- GenImmix --- 36 | export MMTK_PLAN=GenImmix 37 | 38 | run_all 4 39 | 40 | # Test heap resizing 41 | runbms_dacapo2006_with_heap_size fop 20 100 42 | 43 | # --- StickyImmix --- 44 | export MMTK_PLAN=StickyImmix 45 | 46 | run_all 4 47 | 48 | # --- GenCopy --- 49 | export MMTK_PLAN=GenCopy 50 | 51 | run_all 4 52 | 53 | # --- NoGC --- 54 | export MMTK_PLAN=NoGC 55 | 56 | runbms_dacapo2006_with_heap_size antlr 1000 1000 57 | runbms_dacapo2006_with_heap_size fop 1000 1000 58 | runbms_dacapo2006_with_heap_size luindex 1000 1000 59 | 60 | # --- MarkCompact --- 61 | export MMTK_PLAN=MarkCompact 62 | 63 | run_all 4 64 | 65 | # --- MarkSweep --- 66 | export MMTK_PLAN=MarkSweep 67 | 68 | run_all 8 69 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-only-weak-ref.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | # Just run everything in ci-test-only-normal.sh, but with reference processing enabled. 4 | export MMTK_NO_REFERENCE_TYPES=false 5 | . $(dirname "$0")/ci-test-only-normal.sh 6 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-sanity.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | unset JAVA_TOOL_OPTIONS 6 | 7 | MMTK_PLAN=Immix runbms_dacapo2006_with_heap_multiplier fop 4 8 | -------------------------------------------------------------------------------- /.github/scripts/ci-test-vo-bit.sh: -------------------------------------------------------------------------------- 1 | set -xe 2 | 3 | . $(dirname "$0")/common.sh 4 | 5 | unset JAVA_TOOL_OPTIONS 6 | 7 | run_subset() { 8 | heap_multiplier=$1 9 | 10 | runbms_dacapo2006_with_heap_multiplier antlr $heap_multiplier 11 | runbms_dacapo2006_with_heap_multiplier fop $heap_multiplier 12 | runbms_dacapo2006_with_heap_multiplier luindex $heap_multiplier 13 | } 14 | 15 | # --- SemiSpace --- 16 | export MMTK_PLAN=SemiSpace 17 | 18 | run_subset 4 19 | 20 | # --- Immix --- 21 | export MMTK_PLAN=Immix 22 | 23 | run_subset 4 24 | 25 | # --- GenImmix --- 26 | export MMTK_PLAN=GenImmix 27 | 28 | run_subset 4 29 | 30 | # --- StickyImmix --- 31 | export MMTK_PLAN=StickyImmix 32 | 33 | run_subset 4 34 | 35 | # --- GenCopy --- 36 | export MMTK_PLAN=GenCopy 37 | 38 | run_subset 4 39 | 40 | # --- MarkSweep --- 41 | export MMTK_PLAN=MarkSweep 42 | 43 | run_subset 8 44 | 45 | # --- NoGC --- 46 | 47 | export MMTK_PLAN=NoGC 48 | 49 | runbms_dacapo2006_with_heap_size antlr 1000 1000 50 | runbms_dacapo2006_with_heap_size fop 1000 1000 51 | runbms_dacapo2006_with_heap_size luindex 1000 1000 52 | -------------------------------------------------------------------------------- /.github/scripts/common.sh: -------------------------------------------------------------------------------- 1 | BINDING_PATH=$(realpath $(dirname "$0"))/../.. 2 | RUSTUP_TOOLCHAIN=`cat $BINDING_PATH/mmtk/rust-toolchain` 3 | 4 | # dacapo2006 min heap for mark compact 5 | MINHEAP_ANTLR=5 6 | MINHEAP_FOP=13 7 | MINHEAP_LUINDEX=6 8 | MINHEAP_LUSEARCH=8 9 | MINHEAP_PMD=24 10 | MINHEAP_HSQLDB=117 11 | MINHEAP_ECLIPSE=23 12 | MINHEAP_XALAN=21 13 | 14 | # ensure_env 'var_name' 15 | ensure_env() { 16 | env_var=$1 17 | 18 | if ! [[ -v $env_var ]]; then 19 | echo "Environment Variable "$env_var" is required. " 20 | exit 1 21 | fi 22 | } 23 | 24 | runbms_dacapo2006_with_heap_multiplier() 25 | { 26 | benchmark=$1 27 | heap_multiplier=$2 28 | 29 | minheap_env="MINHEAP_${benchmark^^}" 30 | minheap_value="${!minheap_env}" 31 | heap_size=$((minheap_value * heap_multiplier)) 32 | 33 | shift 2 34 | 35 | runbms_dacapo2006_with_heap_size $benchmark $heap_size $heap_size $@ 36 | } 37 | 38 | runbms_dacapo2006_with_heap_size() 39 | { 40 | benchmark=$1 41 | min_heap=$2 42 | max_heap=$3 43 | 44 | min_heap_str="${min_heap}M" 45 | max_heap_str="${max_heap}M" 46 | 47 | shift 3 48 | 49 | ensure_env TEST_JAVA_BIN 50 | ensure_env DACAPO_PATH 51 | 52 | $TEST_JAVA_BIN -XX:+UseThirdPartyHeap -server -XX:MetaspaceSize=100M -Xms$min_heap_str -Xmx$max_heap_str $@ -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar $benchmark 53 | } 54 | -------------------------------------------------------------------------------- /.github/scripts/patch-mmtk-dep.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import tomlkit 3 | 4 | def modify_cargo_toml(cargo_path, ref, repo=None): 5 | # Read Cargo.toml 6 | with open(cargo_path, 'r') as file: 7 | data = tomlkit.parse(file.read()) 8 | 9 | # Modify the mmtk dependency 10 | mmtk_dependency = data['dependencies'].get('mmtk') 11 | if mmtk_dependency: 12 | if repo: 13 | mmtk_dependency['git'] = f'https://github.com/{repo}.git' 14 | mmtk_dependency['rev'] = ref 15 | 16 | # Write the modified Cargo.toml 17 | with open(cargo_path, 'w') as file: 18 | file.write(tomlkit.dumps(data)) 19 | 20 | if __name__ == "__main__": 21 | if len(sys.argv) < 3: 22 | print("Usage: python script.py [repo]") 23 | sys.exit(1) 24 | 25 | cargo_toml = sys.argv[1] 26 | ref = sys.argv[2] 27 | repo = sys.argv[3] if len(sys.argv) > 3 else None 28 | 29 | modify_cargo_toml(cargo_toml, ref, repo) 30 | -------------------------------------------------------------------------------- /.github/scripts/pgo-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # PGO seems to have problems with incremental compilation or something else similar. 4 | # PGO build might fail with error messages such as 5 | # error: file `/tmp/$USER/pgo-data/merged.profdata` passed to `-C profile-use` does not exist. 6 | # when the file clearly exists on disk. 7 | # This happens on both 1.71.1 and 1.66.1, and running cargo clean prior to building seems to reliably work around the problem. 8 | # We can remove this once the compiler bug is fixed. 9 | pushd ../mmtk-openjdk/mmtk 10 | cargo clean 11 | popd 12 | 13 | # Compile with profiling support 14 | RUSTFLAGS="-Cprofile-generate=/tmp/$USER/pgo-data" make CONF=linux-x86_64-normal-server-release THIRD_PARTY_HEAP=$PWD/../mmtk-openjdk/openjdk images 15 | 16 | # Remove extraneous profiling data 17 | rm -rf /tmp/$USER/pgo-data/* 18 | 19 | # Profile using fop 20 | MMTK_PLAN=GenImmix MMTK_STRESS_FACTOR=16777216 MMTK_PRECISE_STRESS=false ./build/linux-x86_64-normal-server-release/images/jdk/bin/java -XX:MetaspaceSize=500M -XX:+DisableExplicitGC -XX:-TieredCompilation -Xcomp -XX:+UseThirdPartyHeap -Xms60M -Xmx60M -jar /usr/share/benchmarks/dacapo/dacapo-23.9-RC3-chopin.jar -n 5 fop 21 | 22 | # Merge profiling data 23 | /opt/rust/toolchains/1.71.1-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata merge -o /tmp/$USER/pgo-data/merged.profdata /tmp/$USER/pgo-data 24 | 25 | pushd ../mmtk-openjdk/mmtk 26 | cargo clean 27 | popd 28 | 29 | # Compile using profiling data 30 | RUSTFLAGS="-Cprofile-use=/tmp/$USER/pgo-data/merged.profdata -Cllvm-args=-pgo-warn-missing-function" make CONF=linux-x86_64-normal-server-release THIRD_PARTY_HEAP=$PWD/../mmtk-openjdk/openjdk images 31 | -------------------------------------------------------------------------------- /.github/scripts/style-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | . $(dirname "$0")/new-common.sh 6 | 7 | export RUSTFLAGS="-D warnings" 8 | 9 | pushd $BINDING_PATH/mmtk 10 | cargo clippy || exit $? 11 | cargo clippy --release || exit $? 12 | 13 | cargo fmt -- --check || exit $? 14 | popd 15 | 16 | find $BINDING_PATH/openjdk \ 17 | $BINDING_PATH/mmtk \ 18 | -name '*.hpp' \ 19 | -o -name '*.cpp' \ 20 | -o -name '*.rs' \ 21 | -o -name '*.toml' \ 22 | -o -name '*.gmk' \ 23 | -exec $(dirname "$0")/ci-check-lineends.sh '{}' \; 24 | 25 | -------------------------------------------------------------------------------- /.github/scripts/visualize-expected-results.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import sys 3 | 4 | 5 | def convert_result_to_emoji(result): 6 | """Convert result to corresponding emoji.""" 7 | conversion = { 8 | 'pass': ':white_check_mark:', 9 | 'fail': ':x:', 10 | 'ignore': ':question:' 11 | } 12 | return conversion.get(result, result) 13 | 14 | 15 | def yaml_to_markdown_table(file_path): 16 | # Load YAML data from the given file path 17 | with open(file_path, 'r') as f: 18 | data = yaml.safe_load(f) 19 | 20 | markdown_tables = "" 21 | 22 | # Process each platform separately 23 | for platform_name in data['results'].keys(): 24 | 25 | # Dynamically extract configurations 26 | configurations = list(data['results'][platform_name].keys()) 27 | 28 | # Dynamically extract plan names from the data 29 | sample_test = list(data['results'][platform_name][configurations[0]].keys())[0] 30 | plans = list(data['results'][platform_name][configurations[0]][sample_test].keys()) 31 | 32 | # Define the header for the markdown table 33 | header = f"### {platform_name}\n\n" 34 | header += "| Test Name |" 35 | for plan in plans: 36 | for config in configurations: 37 | header += f" {plan} ({config}) |" 38 | header += "\n|" + "-----------|" * (len(plans) * len(configurations) + 1) + "\n" 39 | 40 | # Extract data and construct the table content 41 | table_content = "" 42 | for test_name in data['results'][platform_name][configurations[0]].keys(): 43 | row = f"| {test_name} |" 44 | for plan in plans: 45 | for config in configurations: 46 | result = data['results'][platform_name][config][test_name].get(plan, '') 47 | row += f" {convert_result_to_emoji(result)} |" 48 | table_content += row + "\n" 49 | 50 | # Append the table for the current platform to the final result 51 | markdown_tables += header + table_content + "\n\n" 52 | 53 | return markdown_tables 54 | 55 | # Load YAML from a given file path 56 | file_path = sys.argv[1] 57 | 58 | markdown_tables = yaml_to_markdown_table(file_path) 59 | print(markdown_tables) 60 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build OpenJDK Binding 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | debug-level: 7 | required: true 8 | type: string 9 | build-env-var: 10 | required: false 11 | type: string 12 | mmtk-core-repo: 13 | required: false 14 | type: string 15 | mmtk-core-ref: 16 | required: false 17 | type: string 18 | 19 | jobs: 20 | build-linux-x64: 21 | name: linux-x64 22 | runs-on: ubuntu-22.04 23 | steps: 24 | - name: Checkout MMTk OpenJDK binding 25 | uses: actions/checkout@v4 26 | with: 27 | path: ./git/mmtk-openjdk 28 | - name: Extract OpenJDK revision 29 | id: extract-openjdk-revision 30 | run: | 31 | OPENJDK_VERSION=`sed -n 's/^openjdk_version.=."\(.*\)"$/\1/p' < git/mmtk-openjdk/mmtk/Cargo.toml` 32 | echo "openjdk-revision=$OPENJDK_VERSION" >> $GITHUB_OUTPUT 33 | - name: Checkout OpenJDK 34 | uses: actions/checkout@v4 35 | with: 36 | repository: mmtk/openjdk 37 | path: ./git/openjdk 38 | ref: ${{ steps.extract-openjdk-revision.outputs.openjdk-revision }} 39 | # Patch mmtk-core version if needed 40 | - name: Patch mmtk-core version 41 | if: ${{ inputs.mmtk-core-repo != '' || inputs.mmtk-core-ref != '' }} 42 | run: | 43 | pip3 install tomlkit 44 | python3 .github/scripts/patch-mmtk-dep.py mmtk/Cargo.toml ${{ inputs.mmtk-core-ref }} ${{ inputs.mmtk-core-repo }} 45 | cat mmtk/Cargo.toml 46 | working-directory: ./git/mmtk-openjdk 47 | - name: Setup environment 48 | run: ./.github/scripts/ci-setup.sh 49 | working-directory: ./git/mmtk-openjdk 50 | - name: Export build environemnt variables 51 | if: ${{ inputs.build-env-var != '' }} 52 | run: | 53 | echo "${{ inputs.build-env-var }}" >> $GITHUB_ENV 54 | - name: Export build suffix 55 | run: | 56 | if [ -z "${{ inputs.build-env-var }}" ]; then 57 | echo "BUILD_SUFFIX=normal" >> $GITHUB_ENV 58 | else 59 | escaped_build=$(echo "${{ inputs.build-env-var }}" | sed 's/ /_/g') 60 | echo "BUILD_SUFFIX=$escaped_build" >> $GITHUB_ENV 61 | fi 62 | - name: Build MMTk OpenJDK ${{ inputs.debug-level }} 63 | run: | 64 | OPENJDK_PATH=$GITHUB_WORKSPACE/git/openjdk DEBUG_LEVEL=${{ inputs.debug-level }} OPENJDK_BUILD_TARGET=product-bundles ./.github/scripts/ci-build.sh 65 | working-directory: ./git/mmtk-openjdk 66 | - name: Upload bundles 67 | uses: actions/upload-artifact@v4 68 | with: 69 | name: linux-x86_64-server-${{ inputs.debug-level }}-bundles-${{ env.BUILD_SUFFIX }} 70 | path: | 71 | ./git/openjdk/build/linux-x86_64-normal-server-${{ inputs.debug-level }}/bundles/*_bin.tar.gz 72 | ./git/openjdk/build/linux-x86_64-normal-server-${{ inputs.debug-level }}/bundles/*_bin-debug.tar.gz 73 | retention-days: 2 74 | -------------------------------------------------------------------------------- /.github/workflows/run-dacapo-2006.yml: -------------------------------------------------------------------------------- 1 | name: "Test with DaCapo 2006" 2 | 3 | on: 4 | workflow_call: 5 | workflow_dispatch: 6 | inputs: 7 | mmtk-core-repo: 8 | required: false 9 | type: string 10 | mmtk-core-ref: 11 | required: false 12 | type: string 13 | 14 | env: 15 | DACAPO_VERSION: dacapo-2006-10-MR2 16 | DACAPO_FILE: dacapo-2006-10-MR2.jar 17 | DACAPO_DOWNLOAD_URL: https://downloads.sourceforge.net/project/dacapobench/archive/2006-10-MR2/dacapo-2006-10-MR2.jar 18 | 19 | jobs: 20 | cache-dacapo: 21 | runs-on: ubuntu-22.04 22 | steps: 23 | - name: Check ${{ env.DACAPO_VERSION }} cache 24 | id: check-cache 25 | uses: actions/cache@v3 26 | with: 27 | path: dacapo/${{ env.DACAPO_FILE }} 28 | key: ${{ env.DACAPO_VERSION }} 29 | lookup-only: true 30 | - name: Install ${{ env.DACAPO_VERSION }} 31 | if: steps.check-cache.outputs.cache-hit != 'true' 32 | run: | 33 | mkdir -p dacapo 34 | pushd dacapo 35 | wget -q "${{ env.DACAPO_DOWNLOAD_URL }}" -O ${{ env.DACAPO_FILE }} 36 | popd 37 | 38 | test-normal-build: 39 | name: Test normal build 40 | runs-on: ubuntu-22.04 41 | env: 42 | build-debug-level: fastdebug 43 | needs: 44 | - cache-dacapo 45 | strategy: 46 | fail-fast: false 47 | matrix: 48 | test-script: ["ci-test-only-normal", "ci-test-only-normal-no-compressed-oops", "ci-test-only-weak-ref"] 49 | steps: 50 | # We need to check out the binding repo to get the running configs and test scripts 51 | - name: Checkout MMTk OpenJDK binding 52 | uses: actions/checkout@v4 53 | - name: Setup environment 54 | run: | 55 | pip3 install running-ng 56 | sudo apt-get update -y 57 | sudo apt-get install -y build-essential libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libasound2-dev libxrandr-dev 58 | - name: Fetch ${{ env.DACAPO_VERSION }} cache 59 | id: fetch-cache 60 | uses: actions/cache@v3 61 | with: 62 | path: dacapo/${{ env.DACAPO_FILE }} 63 | key: ${{ env.DACAPO_VERSION }} 64 | - name: Download bundles 65 | uses: actions/download-artifact@v4 66 | with: 67 | name: linux-x86_64-server-${{ env.build-debug-level }}-bundles-normal 68 | path: bundles 69 | - name: Extract OpenJDK 70 | run: | 71 | pushd bundles 72 | tar xvf *.tar.gz 73 | BIN_DIR=`find . -name bin` 74 | mv `dirname $BIN_DIR` jdk 75 | popd 76 | - name: Test ${{ matrix.test-script }} 77 | run: | 78 | export TEST_JAVA_BIN=$GITHUB_WORKSPACE/bundles/jdk/bin/java 79 | export DACAPO_PATH=$GITHUB_WORKSPACE/dacapo 80 | ./.github/scripts/${{ matrix.test-script }}.sh 81 | 82 | test-feature-build: 83 | name: Test feature build 84 | runs-on: ubuntu-22.04 85 | needs: 86 | - cache-dacapo 87 | env: 88 | build-debug-level: fastdebug 89 | strategy: 90 | fail-fast: false 91 | matrix: 92 | test-script: 93 | - ci-test-vo-bit 94 | - ci-test-assertions 95 | - ci-test-malloc-mark-sweep 96 | - ci-test-mark-in-header 97 | - ci-test-forwarding-on-side 98 | include: 99 | - test-script: ci-test-vo-bit 100 | build-suffix: MMTK_VO_BIT=1 101 | - test-script: ci-test-assertions 102 | build-suffix: MMTK_EXTREME_ASSERTIONS=1 103 | - test-script: ci-test-malloc-mark-sweep 104 | build-suffix: MMTK_MALLOC_MARK_SWEEP=1_MMTK_EXTREME_ASSERTIONS=1 105 | - test-script: ci-test-mark-in-header 106 | build-suffix: MMTK_MALLOC_MARK_SWEEP=1_MMTK_MARK_IN_HEADER=1 107 | - test-script: ci-test-forwarding-on-side 108 | build-suffix: MMTK_FORWARDING_ON_SIDE=1 109 | steps: 110 | - name: Checkout MMTk OpenJDK binding 111 | uses: actions/checkout@v4 112 | - name: Fetch ${{ env.DACAPO_VERSION }} cache 113 | id: fetch-cache 114 | uses: actions/cache@v3 115 | with: 116 | path: dacapo/${{ env.DACAPO_FILE }} 117 | key: ${{ env.DACAPO_VERSION }} 118 | - name: Download bundles 119 | uses: actions/download-artifact@v4 120 | with: 121 | name: linux-x86_64-server-${{ env.build-debug-level }}-bundles-${{ matrix.build-suffix }} 122 | path: bundles 123 | - name: Extract OpenJDK 124 | run: | 125 | pushd bundles 126 | tar xvf *.tar.gz 127 | BIN_DIR=`find . -name bin` 128 | mv `dirname $BIN_DIR` jdk 129 | popd 130 | - name: Test ${{ matrix.test-script }} 131 | run: | 132 | export TEST_JAVA_BIN=$GITHUB_WORKSPACE/bundles/jdk/bin/java 133 | export DACAPO_PATH=$GITHUB_WORKSPACE/dacapo 134 | ./.github/scripts/${{ matrix.test-script }}.sh 135 | -------------------------------------------------------------------------------- /.github/workflows/run-dacapo-chopin.yml: -------------------------------------------------------------------------------- 1 | name: "Test with DaCapo Chopin" 2 | 3 | on: 4 | workflow_call: 5 | 6 | env: 7 | DACAPO_VERSION: dacapo-23.9-RC3-chopin 8 | DACAPO_FILE: dacapo-23.9-RC3-chopin.zip 9 | DACAPO_DOWNLOAD_URL: https://download.dacapobench.org/chopin/dacapo-23.9-RC3-chopin.zip 10 | 11 | jobs: 12 | cache-dacapo: 13 | runs-on: ubuntu-22.04 14 | steps: 15 | - name: Check ${{ env.DACAPO_VERSION }} cache 16 | id: check-cache 17 | uses: actions/cache@v3 18 | with: 19 | path: dacapo/${{ env.DACAPO_FILE }} 20 | key: ${{ env.DACAPO_VERSION }} 21 | lookup-only: true 22 | - name: Install ${{ env.DACAPO_VERSION }} 23 | if: steps.check-cache.outputs.cache-hit != 'true' 24 | run: | 25 | mkdir -p dacapo 26 | pushd dacapo 27 | wget -q "${{ env.DACAPO_DOWNLOAD_URL }}" -O ${{ env.DACAPO_FILE }} 28 | popd 29 | 30 | test-normal-build: 31 | needs: 32 | - cache-dacapo 33 | runs-on: ubuntu-22.04 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | debug-level: ["fastdebug", "release"] 38 | benchmark: 39 | - avrora 40 | - batik 41 | - biojava 42 | - cassandra 43 | - eclipse 44 | - fop 45 | - graphchi 46 | - h2 47 | - h2o 48 | - jme 49 | - jython 50 | - kafka 51 | - luindex 52 | - lusearch 53 | - pmd 54 | # spring 55 | - sunflow 56 | - tomcat 57 | # tradebeans 58 | # tradesoap 59 | - xalan 60 | - zxing 61 | steps: 62 | - name: Check free space 63 | run: df -h 64 | - name: Maximize build space 65 | uses: easimon/maximize-build-space@master 66 | with: 67 | remove-dotnet: true 68 | remove-android: true 69 | remove-haskell: true 70 | remove-codeql: true 71 | remove-docker-images: true 72 | # Leave some room for the runner for logging in /dev/root 73 | root-reserve-mb: 6000 74 | temp-reserve-mb: 1024 75 | - name: Check free space 76 | run: df -h 77 | - name: Checkout MMTk OpenJDK binding 78 | uses: actions/checkout@v4 79 | - name: Setup environment 80 | run: | 81 | pip3 install running-ng 82 | sudo apt-get update -y 83 | sudo apt-get install -y build-essential libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libasound2-dev libxrandr-dev 84 | - name: Check free space and runner log path 85 | run: | 86 | df -h 87 | df /home/runner/runners 88 | - name: Fetch ${{ env.DACAPO_VERSION }} cache 89 | id: fetch-cache 90 | uses: actions/cache@v3 91 | with: 92 | path: dacapo/${{ env.DACAPO_FILE }} 93 | key: ${{ env.DACAPO_VERSION }} 94 | # fail-on-cache-miss: true # We should never have a cache miss here as we cache DaCapo in an earlier job 95 | # Temporarily change this to false in case the cache download gets 96 | # stuck -- if the cache download is stuck then we go straight to 97 | # upstream and fetch the zip file 98 | fail-on-cache-miss: false 99 | - name: Install ${{ env.DACAPO_VERSION }} 100 | if: steps.fetch-cache.outputs.cache-hit != 'true' 101 | run: | 102 | mkdir -p dacapo 103 | pushd dacapo 104 | wget -q "${{ env.DACAPO_DOWNLOAD_URL }}" -O ${{ env.DACAPO_FILE }} 105 | popd 106 | - name: Unzip ${{ env.DACAPO_VERSION }} 107 | run: | 108 | pushd dacapo 109 | unzip ${{ env.DACAPO_FILE }} 110 | rm ${{ env.DACAPO_FILE }} 111 | popd 112 | - name: Check free space 113 | run: df -h 114 | - name: Download bundles 115 | uses: actions/download-artifact@v4 116 | with: 117 | name: linux-x86_64-server-${{ matrix.debug-level }}-bundles-normal 118 | path: bundles 119 | - name: Extract OpenJDK 120 | run: | 121 | pushd bundles 122 | tar xvf *.tar.gz 123 | BIN_DIR=`find . -name bin` 124 | mv `dirname $BIN_DIR` jdk 125 | popd 126 | - name: Check free space 127 | run: df -h 128 | - name: Run ${{ env.DACAPO_VERSION }} ${{ matrix.benchmark }} on MMTk OpenJDK ${{ matrix.debug-level }} with 2.5x MarkCompact minheap 129 | run: | 130 | DACAPO_PATH=`realpath ./dacapo` 131 | sed -i "s;DACAPO_PATH;$DACAPO_PATH;g" .github/configs/base.yml 132 | echo " - ${{ matrix.benchmark }}" >> .github/configs/base.yml 133 | set -o pipefail 134 | running runbms /tmp .github/configs/base.yml -s 2.5 -p linux-x86_64-${{ matrix.benchmark }}-${{ matrix.debug-level }} | tee /tmp/running.stdout 135 | - name: Extract running run id 136 | id: extract-running-run-id 137 | run: | 138 | RUN_ID=`sed -n 's/^Run id:.\(.*\)$/\1/p' < /tmp/running.stdout` 139 | echo "run-id=$RUN_ID" >> $GITHUB_OUTPUT 140 | - name: Upload running artifacts 141 | uses: actions/upload-artifact@v4 142 | with: 143 | name: linux-x86_64-${{ matrix.benchmark }}-${{ matrix.debug-level }} 144 | path: /tmp/${{ steps.extract-running-run-id.outputs.run-id }}/ 145 | - name: Check for test failures 146 | run: | 147 | RUNNING_OUTPUT=`sed -n "s/^\(${{ matrix.benchmark }} .*\)$/\1/p" < /tmp/running.stdout` 148 | echo $RUNNING_OUTPUT 149 | pip3 install pyyaml 150 | echo $RUNNING_OUTPUT | python3 .github/scripts/ci-matrix-result-check.py linux-x64 ${{ matrix.debug-level }} ${{ matrix.benchmark }} /tmp/${{ steps.extract-running-run-id.outputs.run-id }}/ 151 | -------------------------------------------------------------------------------- /.github/workflows/stylecheck.yml: -------------------------------------------------------------------------------- 1 | name: Style check 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | style-check: 14 | runs-on: ubuntu-22.04 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Setup environments 18 | run: ./.github/scripts/ci-setup.sh 19 | - name: Style checks 20 | run: ./.github/scripts/ci-style.sh 21 | 22 | msrv: 23 | runs-on: ubuntu-22.04 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: Install Rust toolchain 27 | uses: actions-rs/toolchain@v1 28 | with: 29 | toolchain: stable 30 | override: true 31 | - name: Install cargo-msrv 32 | run: cargo install cargo-msrv 33 | # Verify the MSRV defined in Cargo.toml 34 | - name: Verify MSRV 35 | run: cargo msrv verify --path mmtk 36 | # If the previous step fails, find MSRV 37 | - name: Find MSRV 38 | if: failure() 39 | run: cargo msrv find --path mmtk 40 | -------------------------------------------------------------------------------- /.github/workflows/test-pr.yml: -------------------------------------------------------------------------------- 1 | name: DaCapo Tests 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | # Normal build: build both fastdebug and release 14 | build-normal-fastdebug: 15 | uses: ./.github/workflows/build.yml 16 | with: 17 | debug-level: fastdebug 18 | 19 | build-normal-release: 20 | uses: ./.github/workflows/build.yml 21 | with: 22 | debug-level: release 23 | 24 | # Feature build: only build fastdebug 25 | build-vo-bit: 26 | uses: ./.github/workflows/build.yml 27 | with: 28 | build-env-var: MMTK_VO_BIT=1 29 | debug-level: fastdebug 30 | 31 | build-extreme-assertions: 32 | uses: ./.github/workflows/build.yml 33 | with: 34 | build-env-var: MMTK_EXTREME_ASSERTIONS=1 35 | debug-level: fastdebug 36 | 37 | build-malloc-mark-sweep: 38 | uses: ./.github/workflows/build.yml 39 | with: 40 | # Test malloc mark sweep with extreme assertions 41 | build-env-var: MMTK_MALLOC_MARK_SWEEP=1 MMTK_EXTREME_ASSERTIONS=1 42 | debug-level: fastdebug 43 | 44 | build-mark-in-header: 45 | uses: ./.github/workflows/build.yml 46 | with: 47 | # Before we get other plans work with mark in header, we only test with malloc mark sweep. 48 | build-env-var: MMTK_MALLOC_MARK_SWEEP=1 MMTK_MARK_IN_HEADER=1 49 | debug-level: fastdebug 50 | 51 | build-forwarding-on-side: 52 | uses: ./.github/workflows/build.yml 53 | with: 54 | build-env-var: MMTK_FORWARDING_ON_SIDE=1 55 | debug-level: fastdebug 56 | 57 | run-dacapo-2006: 58 | needs: 59 | - build-normal-fastdebug 60 | - build-vo-bit 61 | - build-extreme-assertions 62 | - build-malloc-mark-sweep 63 | - build-mark-in-header 64 | - build-forwarding-on-side 65 | uses: ./.github/workflows/run-dacapo-2006.yml 66 | 67 | run-dacapo-chopin: 68 | needs: 69 | - build-normal-fastdebug 70 | - build-normal-release 71 | uses: ./.github/workflows/run-dacapo-chopin.yml 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # will have compiled files and executables 2 | target/ 3 | 4 | # These are backup files generated by rustfmt 5 | **/*.rs.bk 6 | 7 | # Intellij 8 | /.idea/ 9 | /mmtk.iml 10 | 11 | # VSCode 12 | /.vscode/ 13 | 14 | # build.py & bench.sh 15 | /*.dylib 16 | /*.so 17 | 18 | /repos/mmtk-core 19 | 20 | __pycache__ 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtk/mmtk-openjdk/cf7879fb2ee95d3661d764386a9380c6cb79bf79/.gitmodules -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the MMTk project are retained by their contributors. No 2 | copyright assignment is required to contribute to the MMTk project. 3 | 4 | Some files may include explicit copyright notices and/or license notices. 5 | For full authorship information, see the version control history. 6 | 7 | Except as otherwise noted (below and/or in individual files), MMTk is 8 | licensed under the Apache License, Version 2.0 or 9 | or the MIT license 10 | or , at your option. 11 | 12 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README-legacy.md: -------------------------------------------------------------------------------- 1 | ## Progress Summary: 2 | 3 | ### Introduced a runtime argument -XX:+UseMMTk : 4 | We are on the way to complete building an interface between the JVM and the rust-mmtk. We are calling it `MMTkHeap`. It is enabled by a command line argument `-XX:+UseMMTk`. make, javac, and java (when this argument is not given) work the same way as before. Only difference is that we have to run an `export` command for every new terminal that intends to execute `make`, `javac`, or `java`. 5 | 6 | ### Partially implemented BarrierSet and CollectedHeap for MMTk: 7 | Currently `MMTkHeap` tries to `allocate` from rust-mmtk, but there are some unimplemented methods from its superclass, so core dump occurs. We created a `BarrierSet` named `NoBarrier`. We modified several CPU level methods to introduce `NoBarrier` there. There are several classes which require support from rust-mmtk. After the support is added, the implementations of those classes can be completed. 8 | 9 | ### Testing our work: 10 | The latest commit (**Commit 1b48c800** in mmtk branch) is a buildable and runnable version. We are attaching a [document](./Testing_Openjdk_MMTk_Branch.md) that has instructions to test our code. 11 | 12 | 13 | ## In Details: 14 | 15 | ### Warm-up and environment setup: 16 | The first several weeks we had to spend some time to explore the *openjdk-10* codebase. We had explored openjdk-8 previously, but back then we didn't have any intention to make such big changes. However, we found a build procedure with rust-mmtk integrated very soon, thanks to Pavel and Isaac. 17 | 18 | ### First attempt to allocate with rust-mmtk: 19 | At first we tested injecting the allocation codes into the existing system. It was able to allocate using rust-mmtk allocator. But `make` and `javac` also need memory allocation. As it replaced the default allocator, it created some conflicts with the build process of openjdk. We knew that we would need a runtime parameter to select mmtk allocator. 20 | 21 | ### Runtime argument for enabling MMTk: 22 | Earlier in January, we introduced a runtime parameter to enable rust-mmtk allocator. At first it was running the built-in Parallel GC behind the scene. The best part of this parameter is that a user will not feel existence of our work unless they add this argument from command line. `make` and `javac` work as they did before. So does `java` unless we add `-XX:+UseMMTk` argument from command line. 23 | 24 | ### Implementing MMTkHeap as a subclass of ParallelScavengeHeap: 25 | JVM needs a data structure named `CollectedHeap` to work properly. Every garbage collector has an instance of this data structure. `CollectedHeap` has some pure abstract methods. So its subclasses need to implement some methods. For example, Parallel GC uses `ParallelScavengeHeap` that extends this class. 26 | 27 | So we wanted to create an abstraction of a Heap that would communicate with rust-mmtk. We named it `MMTkHeap`. For the beginning phase we created a class named `MMTkHeap` that extended `ParallelScavengeHeap`. We intended to override the necessary components. 28 | As it had some components of `ParallelScavengeHeap`, it created some conflicts when the VM didn't find what it expected. For example, there are methods like *`block_size`*, *`amount_of_space_used`* etc. When we replaced the allocator with rust-mmtk allocator, some of them were not functioning properly. We discussed it with **Rifat**, our advisor in Bangladesh. He suggested to create `MMTkHeap` without any dependence on any other GC. 29 | 30 | ### Partial implementation of independent MMTkHeap and NoBarrier: 31 | Therefore, we have made `MMTkHeap` a direct subclass of `CollectedHeap`. As a result we are left with a bunch of *pure abstract methods*. There were also some issue related to barriers. We created a class `NoBarrier` and introduced it to the CPU level methods which perform barrier related tasks before and after memory accesses. However, currently the `NoBarrier` is supported on *JVM for x86 processors only*. Later we will need to add this support for other processors as well. 32 | 33 | ### Why MMTkHeap, NoBarrier, and MMTkMemoryPool?: 34 | Directly quoted form [http://openjdk.java.net/jeps/304](http://openjdk.java.net/jeps/304) 35 | >More specifically, a garbage collector implementation will have to provide: 36 | ■ The heap, a subclass of CollectedHeap 37 | ■ The barrier set, a subclass of BarrierSet, which implements the various barriers for the runtime 38 | ■ An implementation of CollectorPolicy 39 | ■ An implementation of GCInterpreterSupport, which implements the various barriers for a GC for the interpreter (using assembler instructions) 40 | ■ An implementation of GCC1Support, which implements the various barriers for a GC for the C1 compiler 41 | ■ An implementation of GCC2Support, which implements the various barriers for a GC for the C2 compiler 42 | ■ Initialization of eventual GC specific arguments 43 | ■ Setup of a MemoryService, the related memory pools, memory managers, etc. ” 44 | 45 | In simple words, the VM has significant dependence on several GC related classes. We will need to implement abstractions of a `CollectedHeap`, `MemoryPool`, `BarrierSet`, and some other classes to connect rust-mmtk with the JVM. But the actual GC related tasks will be handled by rust-mmtk. 46 | 47 | ## Issues Ahead: 48 | We think the following tasks will be necessary: 49 | - Complete implementation of `MMTkHeap` 50 | - Complete implementation of `NoBarrier` 51 | - Complete implementation of `MMTkMemoryPool` 52 | - `NoBarrier` support for all processors 53 | 54 | 55 | We need some support from Rust-MMTK. Pavel told us that he would look into it. Our vm requires some attributes of the heap at runtime through some abstract methods specified in `ColectedHeap`. These methods are called by JVM and Universe. Currently we believe our vm crashes due to these lackings. 56 | 57 | 58 | __Allocation Requirements:__ 59 | 60 | char* _base; 61 | size_t _size; 62 | size_t Used_bytes 63 | size_t max_capacity (It is the total_space - capacity_of_to_space in Semispace ) 64 | size_t _noaccess_prefix; 65 | size_t _alignment; 66 | bool executable; 67 | int _fd_for_heap; //File descriptor for the heap.We will provide this to Rust-MMTK. 68 | 69 | __GC Requirements:__ (when GC is completed in Rust) 70 | 71 | Last_gc_time 72 | 73 | Some other things may be required. We will know for sure when we start incorporating it. 74 | When Pavel gives us methods to access these attributes we can proceed to the garbage collection part. 75 | 76 | __Making facilities for GC:__ 77 | Pavel told us we need to provide the following two things for GC. 78 | 79 | __1.Finding Roots :__ 80 | For roots, we have made a plan with Rifat. We will follow the way psMarkSweep does it. We will incorporate it after allocation gets bug free. We have gone through the codes extensively to understand how this works. We will simply recreate what it does. 81 | 82 | What it does is it pushes all its roots in a stack called `marking_stack`. We will do something similar and pass the data structure. 83 | 84 | 85 | __2.Specifying which class members are pointers:__ 86 | We will go through the class OOP for solving this. This class is for handling objects and holds object attributes. We have not started working for it yet. Rifat told us to look into it after allocation is successful. 87 | 88 | --- 89 | *Thank You* 90 | >*--Abdullah Al Mamun 91 | and --Tanveer Hannan* -------------------------------------------------------------------------------- /TESTING-legacy.md: -------------------------------------------------------------------------------- 1 | # Testing OpenJDK+MMTk on the Momas 2 | 3 | > Last tested: OpenJDK@c76b64be MMTk@e02d62d6 2018-07-14 by Felix Friedlander 4 | 5 | ## Environment and dependencies 6 | 7 | GCC 7.3 should already be installed, but it will not be the default. When 8 | running `configure`, we will need to pass `CC` and `CXX` explicitly. 9 | 10 | OpenJDK 8 is installed, but we want a newer boot JDK. Download OpenJDK 10 from 11 | [java.net](http://jdk.java.net/10/) and extract it: 12 | 13 | ```console 14 | $ curl -O https://download.java.net/java/GA/jdk10/10.0.2/19aef61b38124481863b1413dce1855f/13/openjdk-10.0.2_linux-x64_bin.tar.gz 15 | $ tar -xf openjdk-10.0.2_linux-x64_bin.tar.gz 16 | ``` 17 | 18 | An appropriate version of Rust should already be installed. You can check this 19 | using `rustup`: 20 | 21 | ```console 22 | $ rustup show 23 | ``` 24 | 25 | ## Building (debug) 26 | 27 | `` can be one of `release`, `fastdebug`, `slowdebug` and `optimized`. 28 | 29 | ```bash 30 | cd openjdk 31 | # Build MMTk 32 | cd mmtk 33 | cargo +nightly build 34 | cd .. 35 | # Build OpenJDK 36 | bash configure --disable-warnings-as-errors --with-debug-level= 37 | CONF=linux-x86_64-normal-server- make 38 | # JDK is at `build/linux-x86_64-normal-server-/jdk` 39 | ``` 40 | 41 | ## Building (release) 42 | 43 | ```bash 44 | cd openjdk 45 | # Build MMTk 46 | cd mmtk 47 | cargo +nightly build --release 48 | cd .. 49 | # Build OpenJDK 50 | bash configure --disable-warnings-as-errors 51 | CONF=linux-x86_64-normal-server-release make 52 | # JDK is at `build/linux-x86_64-normal-server-release/jdk` 53 | ``` 54 | 55 | ## Testing 56 | 57 | 1. `java` binary is at `build/linux-x86_64-normal-server-/jdk/bin/java`. 58 | 2. Set env `LD_LIBRARY_PATH` to include `$PWD/mmtk/vmbindings/openjdk/target/debug` (or `$PWD/mmtk/vmbindings/openjdk/target/release` if openjdk is built with debug level `release`). 59 | 3. To enable MMTk, pass `-XX:+UseMMTk -XX:-UseCompressedOops` to `java`. 60 | 61 | e.g.: 62 | 63 | * If `DEBUG_LEVEL` = `fastdebug`, `slowdebug` or `optimized`: 64 | ```bash 65 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/mmtk/vmbindings/openjdk/target/debug 66 | build/linux-x86_64-normal-server-fastdebug/jdk/bin/java -XX:+UseMMTk -XX:-UseCompressedOops HelloWorld 67 | ``` 68 | 69 | * If `DEBUG_LEVEL` = `release`: 70 | ```bash 71 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/mmtk/vmbindings/openjdk/target/release 72 | build/linux-x86_64-normal-server-release/jdk/bin/java -XX:+UseMMTk -XX:-UseCompressedOops HelloWorld 73 | ``` 74 | 75 | > Original instructions by Abdullah Al Mamun and Tanveer Hannan 76 | > 77 | > Updated Sep 2018 by Felix Friedlander 78 | > 79 | > Updated Feb 2020 by Wenyu Zhao -------------------------------------------------------------------------------- /ThirdPartyHeap.md: -------------------------------------------------------------------------------- 1 | # OpenJDK's Third-Party Heap Design 2 | 3 | 4 | 5 | ## Build System Integration 6 | 7 | #### 0. Suppose our implementation of third-party heap is under folder `$PWD/my_third_party_heap/` 8 | 9 | #### 1. Enable build with third-party heap 10 | 11 | * Build with command `make THIRD_PARTY_HEAP=$PWD/my_third_party_heap`. 12 | * This will search for, and include `$PWD/my_third_party_heap/CompileThirdPartyHeap.gmk` 13 | 14 | #### 2. Setup `my_third_party_heap/CompileThirdPartyHeap.gmk` 15 | 16 | ```makefile 17 | # TOPDIR points to openjdk root directory 18 | JVM_SRC_DIRS += $(TOPDIR)/my_third_party_heap 19 | JVM_CFLAGS += -DINCLUDE_THIRD_PARTY_HEAP -DTHIRD_PARTY_HEAP_SRC=$(TOPDIR)/my_third_party_heap 20 | ``` 21 | This will compile every `.cpp` files under `$PWD/my_third_party_heap` and link to _libjava.so_. 22 | 23 | #### 3. (Optional) Add custom build target before building _libjava.so_ 24 | 25 | This is useful for mmtk to build the _libmmtk.so_ building _libjava.so_ 26 | 27 | Add this to `CompileThirdPartyHeap.gmk`: 28 | 29 | ```makefile 30 | lib_mmtk: 31 | echo "your build commands here" 32 | 33 | $(BUILD_LIBJVM): lib_mmtk 34 | ``` 35 | 36 | ## Third-Party Heap Interface 37 | 38 | Currently, we need to add a cpp file in `my_third_party_heap` and implement 2 interfaces: 39 | 40 | ```cpp 41 | #include "gc/shared/thirdPartyHeap.hpp" 42 | 43 | namespace third_party_heap { 44 | 45 | class MutatorContext; 46 | 47 | MutatorContext* bind_mutator(::Thread* current) { 48 | // Returns a pointer of a thread-local storage 49 | } 50 | 51 | GCArguments* new_gc_arguments() { 52 | // Return your inherited GCArguments instance 53 | } 54 | 55 | }; 56 | ``` 57 | 58 | * An implementation of `GCArguments` is responsible for create a `CollectedHeap*`. 59 | 1. So you need to define a implementation of `CollectedHeap` as well. 60 | 2. And implement `CollectedHeap::mem_allocate` method for object allocation 61 | 1. Allocate objects either by: 62 | * Allocate with global synchronization 63 | * Get pre-created `MutatorContext*`, and allocate without synchronization. 64 | 2. (Possibly) triggers a gc manually within this method 65 | 66 | 67 | ## TODO: Barrier Support for Third-party Heap 68 | 69 | We only have no-barrier support... 70 | 71 | ## TODO: Performance 72 | 73 | `CollectedHeap::mem_allocate` without `UseTLAB` seems have bad performance... 74 | -------------------------------------------------------------------------------- /mmtk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mmtk_openjdk" 3 | version = "0.31.0" 4 | authors = [" <>"] 5 | rust-version = "1.74.1" 6 | build = "build.rs" 7 | edition = "2021" 8 | 9 | [lib] 10 | name = "mmtk_openjdk" 11 | # be careful - LTO is only allowed for certain crate types 12 | crate-type = ["cdylib"] 13 | 14 | [profile.release] 15 | lto = true 16 | 17 | # Metadata for the OpenJDK repository 18 | [package.metadata.openjdk] 19 | # Our CI matches the following line and extract mmtk/openjdk. If this line is updated, please check ci yaml files and make sure it works. 20 | openjdk_repo = "https://github.com/mmtk/openjdk.git" 21 | openjdk_version = "28e56ee32525c32c5a88391d0b01f24e5cd16c0f" 22 | 23 | [dependencies] 24 | libc = "0.2" 25 | lazy_static = "1.1" 26 | once_cell = "1.10.0" 27 | atomic = "0.6.0" 28 | memoffset = "0.9.0" 29 | cfg-if = "1.0" 30 | probe = "0.5" 31 | 32 | # Be very careful to commit any changes to the following mmtk dependency, as our CI scripts (including mmtk-core CI) 33 | # rely on matching these lines to modify them: e.g. comment out the git dependency and use the local path. 34 | # These changes are safe: 35 | # - change branch 36 | # - change repo name 37 | # But other changes including adding/removing whitespaces in commented lines may break the CI. 38 | mmtk = { git = "https://github.com/mmtk/mmtk-core.git", rev = "c5ead72a87bcc8cc49b5e7a62cf71d848b4b4c9b" } 39 | # Uncomment the following to build locally 40 | # mmtk = { path = "../repos/mmtk-core" } 41 | 42 | [build-dependencies] 43 | built = { version = "0.7.7", features = ["git2"] } 44 | 45 | [features] 46 | default = [] 47 | mmtk_extreme_assertions = ["mmtk/extreme_assertions"] 48 | nogc_lock_free = ["mmtk/nogc_lock_free"] 49 | nogc_no_zeroing = ["mmtk/nogc_no_zeroing"] 50 | # Use the env var MMTK_VO_BIT=1 when building OpenJDK so the fastpath for setting the alloc bit will be compiled in. 51 | # See README. 52 | vo_bit = ["mmtk/vo_bit"] 53 | 54 | # Place the mark bit in the header of objects instead of on the side. 55 | mark_bit_in_header = [] 56 | 57 | # Place the forwarding bits on the side instead of in the header of objects. 58 | forwarding_bits_on_side = [] 59 | 60 | # Use malloc mark sweep - we should only run marksweep with this feature turned on. 61 | malloc_mark_sweep = ["mmtk/malloc_mark_sweep"] 62 | 63 | # We can select plan at runtime. So no need to use any of these features. 64 | # However, if any of these is provided during build-time, we will ignore any runtime flag and 65 | # always run this plan. Performance-wise there is no difference. The main reason for these features 66 | # is to temporarily allow running performance tests without changing performance scripts. 67 | nogc = [] 68 | semispace = [] 69 | gencopy = [] 70 | marksweep = [] 71 | pageprotect = [] 72 | immix = [] 73 | genimmix = [] 74 | stickyimmix = [] 75 | markcompact = [] 76 | -------------------------------------------------------------------------------- /mmtk/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | built::write_built_file().expect("Failed to acquire build-time information"); 3 | } 4 | -------------------------------------------------------------------------------- /mmtk/rust-toolchain: -------------------------------------------------------------------------------- 1 | 1.83.0 2 | -------------------------------------------------------------------------------- /mmtk/src/active_plan.rs: -------------------------------------------------------------------------------- 1 | use crate::MutatorClosure; 2 | use crate::OpenJDK; 3 | use crate::UPCALLS; 4 | use mmtk::util::opaque_pointer::*; 5 | use mmtk::vm::ActivePlan; 6 | use mmtk::Mutator; 7 | use std::collections::VecDeque; 8 | use std::marker::PhantomData; 9 | 10 | struct OpenJDKMutatorIterator<'a, const COMPRESSED: bool> { 11 | mutators: VecDeque<&'a mut Mutator>>, 12 | phantom_data: PhantomData<&'a ()>, 13 | } 14 | 15 | impl OpenJDKMutatorIterator<'_, COMPRESSED> { 16 | fn new() -> Self { 17 | let mut mutators = VecDeque::new(); 18 | unsafe { 19 | ((*UPCALLS).get_mutators)(MutatorClosure::from_rust_closure(&mut |mutator| { 20 | mutators.push_back(mutator); 21 | })); 22 | } 23 | Self { 24 | mutators, 25 | phantom_data: PhantomData, 26 | } 27 | } 28 | } 29 | 30 | impl<'a, const COMPRESSED: bool> Iterator for OpenJDKMutatorIterator<'a, COMPRESSED> { 31 | type Item = &'a mut Mutator>; 32 | 33 | fn next(&mut self) -> Option { 34 | self.mutators.pop_front() 35 | } 36 | } 37 | 38 | pub struct VMActivePlan {} 39 | 40 | impl ActivePlan> for VMActivePlan { 41 | fn is_mutator(tls: VMThread) -> bool { 42 | unsafe { ((*UPCALLS).is_mutator)(tls) } 43 | } 44 | 45 | fn mutator(tls: VMMutatorThread) -> &'static mut Mutator> { 46 | unsafe { 47 | let m = ((*UPCALLS).get_mmtk_mutator)(tls); 48 | &mut *(m as *mut Mutator>) 49 | } 50 | } 51 | 52 | fn mutators<'a>() -> Box>> + 'a> { 53 | Box::new(OpenJDKMutatorIterator::::new()) 54 | } 55 | 56 | fn number_of_mutators() -> usize { 57 | unsafe { ((*UPCALLS).number_of_mutators)() } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /mmtk/src/build_info.rs: -------------------------------------------------------------------------------- 1 | mod raw { 2 | // The include imports a full list of the constants in built.rs from https://docs.rs/built/latest/built/index.html 3 | include!(concat!(env!("OUT_DIR"), "/built.rs")); 4 | } 5 | 6 | lazy_static! { 7 | // Owned string for the binding version, such as MMTk OpenJDK 0.14.0 (cfc755f-dirty) 8 | static ref BINDING_VERSION_STRING: String = match (raw::GIT_COMMIT_HASH, raw::GIT_DIRTY) { 9 | (Some(hash), Some(dirty)) => format!("MMTk OpenJDK {} ({}{})", raw::PKG_VERSION, hash.split_at(7).0, if dirty { "-dirty" } else { "" }), 10 | (Some(hash), None) => format!("MMTk OpenJDK {} ({}{})", raw::PKG_VERSION, hash.split_at(7).0, "-?"), 11 | _ => format!("MMTk OpenJDK {}", raw::PKG_VERSION), 12 | }; 13 | // Owned string for both binding and core version. 14 | static ref MMTK_OPENJDK_FULL_VERSION_STRING: String = format!("{}, using {}", *BINDING_VERSION_STRING, *mmtk::build_info::MMTK_FULL_BUILD_INFO); 15 | 16 | // Exposed &str for the full version. 17 | pub static ref MMTK_OPENJDK_FULL_VERSION: &'static str = &MMTK_OPENJDK_FULL_VERSION_STRING; 18 | } 19 | -------------------------------------------------------------------------------- /mmtk/src/collection.rs: -------------------------------------------------------------------------------- 1 | use mmtk::util::alloc::AllocationError; 2 | use mmtk::util::opaque_pointer::*; 3 | use mmtk::vm::{Collection, GCThreadContext}; 4 | use mmtk::Mutator; 5 | 6 | use crate::UPCALLS; 7 | use crate::{MutatorClosure, OpenJDK}; 8 | 9 | pub struct VMCollection {} 10 | 11 | const GC_THREAD_KIND_WORKER: libc::c_int = 1; 12 | 13 | impl Collection> for VMCollection { 14 | fn stop_all_mutators(tls: VMWorkerThread, mut mutator_visitor: F) 15 | where 16 | F: FnMut(&'static mut Mutator>), 17 | { 18 | unsafe { 19 | ((*UPCALLS).stop_all_mutators)( 20 | tls, 21 | MutatorClosure::from_rust_closure::<_, COMPRESSED>(&mut mutator_visitor), 22 | ); 23 | } 24 | } 25 | 26 | fn resume_mutators(tls: VMWorkerThread) { 27 | unsafe { 28 | ((*UPCALLS).resume_mutators)(tls); 29 | } 30 | } 31 | 32 | fn block_for_gc(_tls: VMMutatorThread) { 33 | unsafe { 34 | ((*UPCALLS).block_for_gc)(); 35 | } 36 | } 37 | 38 | fn spawn_gc_thread(tls: VMThread, ctx: GCThreadContext>) { 39 | let (ctx_ptr, kind) = match ctx { 40 | GCThreadContext::Worker(w) => { 41 | (Box::into_raw(w) as *mut libc::c_void, GC_THREAD_KIND_WORKER) 42 | } 43 | }; 44 | unsafe { 45 | ((*UPCALLS).spawn_gc_thread)(tls, kind, ctx_ptr); 46 | } 47 | } 48 | 49 | fn out_of_memory(tls: VMThread, err_kind: AllocationError) { 50 | unsafe { 51 | ((*UPCALLS).out_of_memory)(tls, err_kind); 52 | } 53 | } 54 | 55 | fn schedule_finalization(_tls: VMWorkerThread) { 56 | unsafe { 57 | ((*UPCALLS).schedule_finalizer)(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mmtk/src/gc_work.rs: -------------------------------------------------------------------------------- 1 | use crate::scanning; 2 | use crate::scanning::to_slots_closure; 3 | use crate::OpenJDK; 4 | use crate::OpenJDKSlot; 5 | use crate::UPCALLS; 6 | use mmtk::scheduler::*; 7 | use mmtk::util::Address; 8 | use mmtk::vm::RootsWorkFactory; 9 | use mmtk::vm::*; 10 | use mmtk::MMTK; 11 | 12 | macro_rules! scan_roots_work { 13 | ($struct_name: ident, $func_name: ident) => { 14 | pub struct $struct_name> { 15 | factory: F, 16 | _p: std::marker::PhantomData, 17 | } 18 | 19 | impl> $struct_name { 20 | pub fn new(factory: F) -> Self { 21 | Self { 22 | factory, 23 | _p: std::marker::PhantomData, 24 | } 25 | } 26 | } 27 | 28 | impl> GCWork for $struct_name { 29 | fn do_work(&mut self, _worker: &mut GCWorker, _mmtk: &'static MMTK) { 30 | unsafe { 31 | ((*UPCALLS).$func_name)(to_slots_closure(&mut self.factory)); 32 | } 33 | } 34 | } 35 | }; 36 | } 37 | 38 | scan_roots_work!(ScanUniverseRoots, scan_universe_roots); 39 | scan_roots_work!(ScanJNIHandlesRoots, scan_jni_handle_roots); 40 | scan_roots_work!(ScanObjectSynchronizerRoots, scan_object_synchronizer_roots); 41 | scan_roots_work!(ScanManagementRoots, scan_management_roots); 42 | scan_roots_work!(ScanJvmtiExportRoots, scan_jvmti_export_roots); 43 | scan_roots_work!(ScanAOTLoaderRoots, scan_aot_loader_roots); 44 | scan_roots_work!(ScanSystemDictionaryRoots, scan_system_dictionary_roots); 45 | scan_roots_work!(ScanStringTableRoots, scan_string_table_roots); 46 | scan_roots_work!( 47 | ScanClassLoaderDataGraphRoots, 48 | scan_class_loader_data_graph_roots 49 | ); 50 | scan_roots_work!(ScanWeakProcessorRoots, scan_weak_processor_roots); 51 | scan_roots_work!(ScanVMThreadRoots, scan_vm_thread_roots); 52 | 53 | pub struct ScanCodeCacheRoots>> 54 | { 55 | factory: F, 56 | } 57 | 58 | impl>> 59 | ScanCodeCacheRoots 60 | { 61 | pub fn new(factory: F) -> Self { 62 | Self { factory } 63 | } 64 | } 65 | 66 | impl>> 67 | GCWork> for ScanCodeCacheRoots 68 | { 69 | fn do_work( 70 | &mut self, 71 | _worker: &mut GCWorker>, 72 | mmtk: &'static MMTK>, 73 | ) { 74 | let is_current_gc_nursery = mmtk 75 | .get_plan() 76 | .generational() 77 | .is_some_and(|gen| gen.is_current_gc_nursery()); 78 | 79 | let mut slots = Vec::with_capacity(scanning::WORK_PACKET_CAPACITY); 80 | 81 | let mut nursery_slots = 0; 82 | let mut mature_slots = 0; 83 | 84 | let mut add_roots = |roots: &[Address]| { 85 | for root in roots { 86 | slots.push(OpenJDKSlot::::from(*root)); 87 | if slots.len() >= scanning::WORK_PACKET_CAPACITY { 88 | self.factory 89 | .create_process_roots_work(std::mem::take(&mut slots)); 90 | } 91 | } 92 | }; 93 | 94 | { 95 | let mut mature = crate::MATURE_CODE_CACHE_ROOTS.lock().unwrap(); 96 | 97 | // Only scan mature roots in full-heap collections. 98 | if !is_current_gc_nursery { 99 | for roots in mature.values() { 100 | mature_slots += roots.len(); 101 | add_roots(roots); 102 | } 103 | } 104 | 105 | { 106 | let mut nursery = crate::NURSERY_CODE_CACHE_ROOTS.lock().unwrap(); 107 | for (key, roots) in nursery.drain() { 108 | nursery_slots += roots.len(); 109 | add_roots(&roots); 110 | mature.insert(key, roots); 111 | } 112 | } 113 | } 114 | 115 | probe!(mmtk_openjdk, code_cache_roots, nursery_slots, mature_slots); 116 | 117 | if !slots.is_empty() { 118 | self.factory.create_process_roots_work(slots); 119 | } 120 | // Use the following code to scan CodeCache directly, instead of scanning the "remembered set". 121 | // unsafe { 122 | // ((*UPCALLS).scan_code_cache_roots)(to_slots_closure(&mut self.factory)); 123 | // } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /mmtk/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | #[macro_use] 4 | extern crate probe; 5 | 6 | use std::collections::HashMap; 7 | use std::ptr::null_mut; 8 | use std::sync::Mutex; 9 | 10 | use libc::{c_char, c_void, uintptr_t}; 11 | use mmtk::util::alloc::AllocationError; 12 | use mmtk::util::constants::LOG_BYTES_IN_GBYTE; 13 | use mmtk::util::heap::vm_layout::VMLayout; 14 | use mmtk::util::{conversions, opaque_pointer::*}; 15 | use mmtk::util::{Address, ObjectReference}; 16 | use mmtk::vm::slot::Slot; 17 | use mmtk::vm::VMBinding; 18 | use mmtk::{MMTKBuilder, Mutator, MMTK}; 19 | pub use slots::use_compressed_oops; 20 | use slots::{OpenJDKSlot, OpenJDKSlotRange}; 21 | 22 | mod abi; 23 | pub mod active_plan; 24 | pub mod api; 25 | mod build_info; 26 | pub mod collection; 27 | mod gc_work; 28 | pub mod object_model; 29 | mod object_scanning; 30 | pub mod reference_glue; 31 | pub mod scanning; 32 | mod slots; 33 | pub(crate) mod vm_metadata; 34 | 35 | #[repr(C)] 36 | pub struct NewBuffer { 37 | pub ptr: *mut Address, 38 | pub capacity: usize, 39 | } 40 | 41 | /// A closure for reporting mutators. The C++ code should pass `data` back as the last argument. 42 | #[repr(C)] 43 | pub struct MutatorClosure { 44 | pub func: extern "C" fn(mutator: *mut libc::c_void, data: *mut libc::c_void), 45 | pub data: *mut libc::c_void, 46 | } 47 | 48 | impl MutatorClosure { 49 | fn from_rust_closure(callback: &mut F) -> Self 50 | where 51 | F: FnMut(&'static mut Mutator>), 52 | { 53 | Self { 54 | func: Self::call_rust_closure::, 55 | data: callback as *mut F as *mut libc::c_void, 56 | } 57 | } 58 | 59 | extern "C" fn call_rust_closure( 60 | mutator: *mut libc::c_void, 61 | callback_ptr: *mut libc::c_void, 62 | ) where 63 | F: FnMut(&'static mut Mutator>), 64 | { 65 | let mutator = mutator as *mut Mutator>; 66 | let callback: &mut F = unsafe { &mut *(callback_ptr as *mut F) }; 67 | callback(unsafe { &mut *mutator }); 68 | } 69 | } 70 | 71 | /// A closure for reporting root slots. The C++ code should pass `data` back as the last argument. 72 | #[repr(C)] 73 | pub struct SlotsClosure { 74 | pub func: extern "C" fn( 75 | buf: *mut Address, 76 | size: usize, 77 | cap: usize, 78 | data: *mut libc::c_void, 79 | ) -> NewBuffer, 80 | pub data: *const libc::c_void, 81 | } 82 | 83 | #[repr(C)] 84 | pub struct OpenJDK_Upcalls { 85 | pub stop_all_mutators: extern "C" fn(tls: VMWorkerThread, closure: MutatorClosure), 86 | pub resume_mutators: extern "C" fn(tls: VMWorkerThread), 87 | pub spawn_gc_thread: extern "C" fn(tls: VMThread, kind: libc::c_int, ctx: *mut libc::c_void), 88 | pub block_for_gc: extern "C" fn(), 89 | pub out_of_memory: extern "C" fn(tls: VMThread, err_kind: AllocationError), 90 | pub get_mutators: extern "C" fn(closure: MutatorClosure), 91 | pub scan_object: extern "C" fn(trace: *mut c_void, object: ObjectReference, tls: OpaquePointer), 92 | pub dump_object: extern "C" fn(object: ObjectReference), 93 | pub get_object_size: extern "C" fn(object: ObjectReference) -> usize, 94 | pub get_mmtk_mutator: extern "C" fn(tls: VMMutatorThread) -> *mut libc::c_void, 95 | pub is_mutator: extern "C" fn(tls: VMThread) -> bool, 96 | pub harness_begin: extern "C" fn(), 97 | pub harness_end: extern "C" fn(), 98 | pub compute_klass_mem_layout_checksum: extern "C" fn() -> usize, 99 | pub offset_of_static_fields: extern "C" fn() -> i32, 100 | pub static_oop_field_count_offset: extern "C" fn() -> i32, 101 | pub referent_offset: extern "C" fn() -> i32, 102 | pub discovered_offset: extern "C" fn() -> i32, 103 | pub dump_object_string: extern "C" fn(object: ObjectReference) -> *const c_char, 104 | pub scan_roots_in_all_mutator_threads: extern "C" fn(closure: SlotsClosure), 105 | pub scan_roots_in_mutator_thread: extern "C" fn(closure: SlotsClosure, tls: VMMutatorThread), 106 | pub scan_universe_roots: extern "C" fn(closure: SlotsClosure), 107 | pub scan_jni_handle_roots: extern "C" fn(closure: SlotsClosure), 108 | pub scan_object_synchronizer_roots: extern "C" fn(closure: SlotsClosure), 109 | pub scan_management_roots: extern "C" fn(closure: SlotsClosure), 110 | pub scan_jvmti_export_roots: extern "C" fn(closure: SlotsClosure), 111 | pub scan_aot_loader_roots: extern "C" fn(closure: SlotsClosure), 112 | pub scan_system_dictionary_roots: extern "C" fn(closure: SlotsClosure), 113 | pub scan_code_cache_roots: extern "C" fn(closure: SlotsClosure), 114 | pub scan_string_table_roots: extern "C" fn(closure: SlotsClosure), 115 | pub scan_class_loader_data_graph_roots: extern "C" fn(closure: SlotsClosure), 116 | pub scan_weak_processor_roots: extern "C" fn(closure: SlotsClosure), 117 | pub scan_vm_thread_roots: extern "C" fn(closure: SlotsClosure), 118 | pub number_of_mutators: extern "C" fn() -> usize, 119 | pub schedule_finalizer: extern "C" fn(), 120 | pub prepare_for_roots_re_scanning: extern "C" fn(), 121 | pub enqueue_references: extern "C" fn(objects: *const ObjectReference, len: usize), 122 | } 123 | 124 | pub static mut UPCALLS: *const OpenJDK_Upcalls = null_mut(); 125 | 126 | #[no_mangle] 127 | pub static GLOBAL_SIDE_METADATA_BASE_ADDRESS: uintptr_t = 128 | mmtk::util::metadata::side_metadata::GLOBAL_SIDE_METADATA_BASE_ADDRESS.as_usize(); 129 | 130 | #[no_mangle] 131 | pub static GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS: uintptr_t = 132 | mmtk::util::metadata::side_metadata::GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS.as_usize(); 133 | 134 | #[no_mangle] 135 | pub static VO_BIT_ADDRESS: uintptr_t = 136 | mmtk::util::metadata::side_metadata::VO_BIT_SIDE_METADATA_ADDR.as_usize(); 137 | 138 | #[no_mangle] 139 | pub static FREE_LIST_ALLOCATOR_SIZE: uintptr_t = 140 | std::mem::size_of::>>(); 141 | 142 | #[derive(Default)] 143 | pub struct OpenJDK; 144 | 145 | impl VMBinding for OpenJDK { 146 | type VMObjectModel = object_model::VMObjectModel; 147 | type VMScanning = scanning::VMScanning; 148 | type VMCollection = collection::VMCollection; 149 | type VMActivePlan = active_plan::VMActivePlan; 150 | type VMReferenceGlue = reference_glue::VMReferenceGlue; 151 | 152 | type VMSlot = OpenJDKSlot; 153 | type VMMemorySlice = OpenJDKSlotRange; 154 | 155 | const MIN_ALIGNMENT: usize = 8; 156 | const MAX_ALIGNMENT: usize = 8; 157 | const USE_ALLOCATION_OFFSET: bool = false; 158 | } 159 | 160 | use std::sync::atomic::AtomicBool; 161 | use std::sync::atomic::Ordering; 162 | 163 | pub static MMTK_INITIALIZED: AtomicBool = AtomicBool::new(false); 164 | 165 | lazy_static! { 166 | pub static ref BUILDER: Mutex = Mutex::new(MMTKBuilder::new_no_env_vars()); 167 | pub static ref SINGLETON_COMPRESSED: MMTK> = { 168 | assert!(use_compressed_oops()); 169 | let mut builder = BUILDER.lock().unwrap(); 170 | assert!(!MMTK_INITIALIZED.load(Ordering::Relaxed)); 171 | set_compressed_pointer_vm_layout(&mut builder); 172 | let ret = mmtk::memory_manager::mmtk_init(&builder); 173 | MMTK_INITIALIZED.store(true, std::sync::atomic::Ordering::SeqCst); 174 | slots::initialize_compressed_oops_base_and_shift(); 175 | *ret 176 | }; 177 | pub static ref SINGLETON_UNCOMPRESSED: MMTK> = { 178 | assert!(!use_compressed_oops()); 179 | let builder = BUILDER.lock().unwrap(); 180 | assert!(!MMTK_INITIALIZED.load(Ordering::Relaxed)); 181 | let ret = mmtk::memory_manager::mmtk_init(&builder); 182 | MMTK_INITIALIZED.store(true, std::sync::atomic::Ordering::SeqCst); 183 | *ret 184 | }; 185 | } 186 | 187 | fn singleton() -> &'static MMTK> { 188 | if COMPRESSED { 189 | unsafe { 190 | &*(&*SINGLETON_COMPRESSED as *const MMTK> 191 | as *const MMTK>) 192 | } 193 | } else { 194 | unsafe { 195 | &*(&*SINGLETON_UNCOMPRESSED as *const MMTK> 196 | as *const MMTK>) 197 | } 198 | } 199 | } 200 | 201 | #[no_mangle] 202 | pub static MMTK_MARK_COMPACT_HEADER_RESERVED_IN_BYTES: usize = 203 | mmtk::util::alloc::MarkCompactAllocator::>::HEADER_RESERVED_IN_BYTES; 204 | 205 | lazy_static! { 206 | /// A global storage for all the cached CodeCache roots added since the last GC. 207 | static ref NURSERY_CODE_CACHE_ROOTS: Mutex>> = Mutex::new(HashMap::new()); 208 | /// A global storage for all the cached CodeCache roots added before the last GC. 209 | static ref MATURE_CODE_CACHE_ROOTS: Mutex>> = Mutex::new(HashMap::new()); 210 | } 211 | 212 | fn set_compressed_pointer_vm_layout(builder: &mut MMTKBuilder) { 213 | let max_heap_size = builder.options.gc_trigger.max_heap_size(); 214 | assert!( 215 | max_heap_size <= (32usize << LOG_BYTES_IN_GBYTE), 216 | "Heap size is larger than 32 GB" 217 | ); 218 | let start = 0x4000_0000; 219 | let end = match start + max_heap_size { 220 | end if end <= (4usize << 30) => 4usize << 30, 221 | end if end <= (32usize << 30) => 32usize << 30, 222 | _ => 0x4000_0000 + (32usize << 30), 223 | }; 224 | let constants = VMLayout { 225 | log_address_space: 35, 226 | heap_start: conversions::chunk_align_down(unsafe { Address::from_usize(start) }), 227 | heap_end: conversions::chunk_align_up(unsafe { Address::from_usize(end) }), 228 | log_space_extent: 31, 229 | force_use_contiguous_spaces: false, 230 | }; 231 | builder.set_vm_layout(constants); 232 | } 233 | -------------------------------------------------------------------------------- /mmtk/src/object_model.rs: -------------------------------------------------------------------------------- 1 | use crate::abi::Oop; 2 | use crate::UPCALLS; 3 | use crate::{vm_metadata, OpenJDK}; 4 | use mmtk::util::alloc::fill_alignment_gap; 5 | use mmtk::util::copy::*; 6 | use mmtk::util::{Address, ObjectReference}; 7 | use mmtk::vm::*; 8 | 9 | pub struct VMObjectModel {} 10 | 11 | impl ObjectModel> for VMObjectModel { 12 | const GLOBAL_LOG_BIT_SPEC: VMGlobalLogBitSpec = vm_metadata::LOGGING_SIDE_METADATA_SPEC; 13 | 14 | const LOCAL_FORWARDING_POINTER_SPEC: VMLocalForwardingPointerSpec = 15 | vm_metadata::FORWARDING_POINTER_METADATA_SPEC; 16 | const LOCAL_FORWARDING_BITS_SPEC: VMLocalForwardingBitsSpec = 17 | vm_metadata::FORWARDING_BITS_METADATA_SPEC; 18 | const LOCAL_MARK_BIT_SPEC: VMLocalMarkBitSpec = vm_metadata::MARKING_METADATA_SPEC; 19 | const LOCAL_LOS_MARK_NURSERY_SPEC: VMLocalLOSMarkNurserySpec = vm_metadata::LOS_METADATA_SPEC; 20 | 21 | const UNIFIED_OBJECT_REFERENCE_ADDRESS: bool = true; 22 | const OBJECT_REF_OFFSET_LOWER_BOUND: isize = 0; 23 | 24 | fn copy( 25 | from: ObjectReference, 26 | copy: CopySemantics, 27 | copy_context: &mut GCWorkerCopyContext>, 28 | ) -> ObjectReference { 29 | let bytes = unsafe { Oop::from(from).size::() }; 30 | let dst = copy_context.alloc_copy(from, bytes, ::std::mem::size_of::(), 0, copy); 31 | debug_assert!(!dst.is_zero()); 32 | // Copy 33 | let src = from.to_raw_address(); 34 | unsafe { std::ptr::copy_nonoverlapping::(src.to_ptr(), dst.to_mut_ptr(), bytes) } 35 | // Note on onsafe: `alloc_copy` never returns 0. 36 | let to_obj = unsafe { ObjectReference::from_raw_address_unchecked(dst) }; 37 | copy_context.post_copy(to_obj, bytes, copy); 38 | to_obj 39 | } 40 | 41 | fn copy_to(from: ObjectReference, to: ObjectReference, region: Address) -> Address { 42 | let need_copy = from != to; 43 | let bytes = unsafe { Oop::from(from).size::() }; 44 | if need_copy { 45 | // copy obj to target 46 | let dst = to.to_raw_address(); 47 | // Copy 48 | let src = from.to_raw_address(); 49 | for i in 0..bytes { 50 | unsafe { (dst + i).store((src + i).load::()) }; 51 | } 52 | } 53 | let start = Self::ref_to_object_start(to); 54 | if region != Address::ZERO { 55 | fill_alignment_gap::>(region, start); 56 | } 57 | start + bytes 58 | } 59 | 60 | fn get_reference_when_copied_to(_from: ObjectReference, to: Address) -> ObjectReference { 61 | debug_assert!(!to.is_zero()); 62 | unsafe { ObjectReference::from_raw_address_unchecked(to) } 63 | } 64 | 65 | fn get_current_size(object: ObjectReference) -> usize { 66 | unsafe { Oop::from(object).size::() } 67 | } 68 | 69 | fn get_size_when_copied(object: ObjectReference) -> usize { 70 | Self::get_current_size(object) 71 | } 72 | 73 | fn get_align_when_copied(_object: ObjectReference) -> usize { 74 | // FIXME figure out the proper alignment 75 | ::std::mem::size_of::() 76 | } 77 | 78 | fn get_align_offset_when_copied(_object: ObjectReference) -> usize { 79 | 0 80 | } 81 | 82 | fn get_type_descriptor(_reference: ObjectReference) -> &'static [i8] { 83 | unimplemented!() 84 | } 85 | 86 | fn ref_to_object_start(object: ObjectReference) -> Address { 87 | object.to_raw_address() 88 | } 89 | 90 | fn ref_to_header(object: ObjectReference) -> Address { 91 | object.to_raw_address() 92 | } 93 | 94 | fn dump_object(object: ObjectReference) { 95 | unsafe { 96 | ((*UPCALLS).dump_object)(object); 97 | } 98 | } 99 | 100 | fn is_object_sane(object: ObjectReference) -> bool { 101 | let oop = Oop::from(object); 102 | // It is only valid if klass.id is between 0 and 5 (see KlassID in openjdk/src/hotspot/share/oops/klass.hpp) 103 | // If oop.klass is not a valid pointer, we may segfault here. 104 | let klass_id = oop.klass::().id as i32; 105 | (0..6).contains(&klass_id) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /mmtk/src/object_scanning.rs: -------------------------------------------------------------------------------- 1 | use crate::OpenJDKSlot; 2 | 3 | use super::abi::*; 4 | use super::UPCALLS; 5 | use mmtk::util::opaque_pointer::*; 6 | use mmtk::util::{Address, ObjectReference}; 7 | use mmtk::vm::SlotVisitor; 8 | use std::cell::UnsafeCell; 9 | use std::{mem, slice}; 10 | 11 | type S = OpenJDKSlot; 12 | 13 | trait OopIterate: Sized { 14 | fn oop_iterate( 15 | &self, 16 | oop: Oop, 17 | closure: &mut impl SlotVisitor>, 18 | ); 19 | } 20 | 21 | impl OopIterate for OopMapBlock { 22 | fn oop_iterate( 23 | &self, 24 | oop: Oop, 25 | closure: &mut impl SlotVisitor>, 26 | ) { 27 | let log_bytes_in_oop = if COMPRESSED { 2 } else { 3 }; 28 | let start = oop.get_field_address(self.offset); 29 | for i in 0..self.count as usize { 30 | let slot = (start + (i << log_bytes_in_oop)).into(); 31 | closure.visit_slot(slot); 32 | } 33 | } 34 | } 35 | 36 | impl OopIterate for InstanceKlass { 37 | fn oop_iterate( 38 | &self, 39 | oop: Oop, 40 | closure: &mut impl SlotVisitor>, 41 | ) { 42 | let oop_maps = self.nonstatic_oop_maps(); 43 | for map in oop_maps { 44 | map.oop_iterate::(oop, closure) 45 | } 46 | } 47 | } 48 | 49 | impl OopIterate for InstanceMirrorKlass { 50 | fn oop_iterate( 51 | &self, 52 | oop: Oop, 53 | closure: &mut impl SlotVisitor>, 54 | ) { 55 | self.instance_klass.oop_iterate::(oop, closure); 56 | 57 | // static fields 58 | let start = Self::start_of_static_fields(oop); 59 | let len = Self::static_oop_field_count(oop); 60 | if COMPRESSED { 61 | let start: *const NarrowOop = start.to_ptr::(); 62 | let slice = unsafe { slice::from_raw_parts(start, len as _) }; 63 | for narrow_oop in slice { 64 | closure.visit_slot(narrow_oop.slot().into()); 65 | } 66 | } else { 67 | let start: *const Oop = start.to_ptr::(); 68 | let slice = unsafe { slice::from_raw_parts(start, len as _) }; 69 | for oop in slice { 70 | closure.visit_slot(Address::from_ref(oop as &Oop).into()); 71 | } 72 | } 73 | } 74 | } 75 | 76 | impl OopIterate for InstanceClassLoaderKlass { 77 | fn oop_iterate( 78 | &self, 79 | oop: Oop, 80 | closure: &mut impl SlotVisitor>, 81 | ) { 82 | self.instance_klass.oop_iterate::(oop, closure); 83 | } 84 | } 85 | 86 | impl OopIterate for ObjArrayKlass { 87 | fn oop_iterate( 88 | &self, 89 | oop: Oop, 90 | closure: &mut impl SlotVisitor>, 91 | ) { 92 | let array = unsafe { oop.as_array_oop() }; 93 | if COMPRESSED { 94 | for narrow_oop in unsafe { array.data::(BasicType::T_OBJECT) } { 95 | closure.visit_slot(narrow_oop.slot().into()); 96 | } 97 | } else { 98 | for oop in unsafe { array.data::(BasicType::T_OBJECT) } { 99 | closure.visit_slot(Address::from_ref(oop as &Oop).into()); 100 | } 101 | } 102 | } 103 | } 104 | 105 | impl OopIterate for TypeArrayKlass { 106 | fn oop_iterate( 107 | &self, 108 | _oop: Oop, 109 | _closure: &mut impl SlotVisitor>, 110 | ) { 111 | // Performance tweak: We skip processing the klass pointer since all 112 | // TypeArrayKlasses are guaranteed processed via the null class loader. 113 | } 114 | } 115 | 116 | impl OopIterate for InstanceRefKlass { 117 | fn oop_iterate( 118 | &self, 119 | oop: Oop, 120 | closure: &mut impl SlotVisitor>, 121 | ) { 122 | use crate::abi::*; 123 | use crate::api::{add_phantom_candidate, add_soft_candidate, add_weak_candidate}; 124 | self.instance_klass.oop_iterate::(oop, closure); 125 | 126 | if Self::should_scan_weak_refs::() { 127 | let reference = ObjectReference::from(oop); 128 | match self.instance_klass.reference_type { 129 | ReferenceType::None => { 130 | panic!("oop_iterate on InstanceRefKlass with reference_type as None") 131 | } 132 | ReferenceType::Weak => add_weak_candidate(reference), 133 | ReferenceType::Soft => add_soft_candidate(reference), 134 | ReferenceType::Phantom => add_phantom_candidate(reference), 135 | // Process these two types normally (as if they are strong refs) 136 | // We will handle final reference later 137 | ReferenceType::Final | ReferenceType::Other => { 138 | Self::process_ref_as_strong(oop, closure) 139 | } 140 | } 141 | } else { 142 | Self::process_ref_as_strong(oop, closure); 143 | } 144 | } 145 | } 146 | 147 | impl InstanceRefKlass { 148 | fn should_scan_weak_refs() -> bool { 149 | !*crate::singleton::() 150 | .get_options() 151 | .no_reference_types 152 | } 153 | fn process_ref_as_strong( 154 | oop: Oop, 155 | closure: &mut impl SlotVisitor>, 156 | ) { 157 | let referent_addr = Self::referent_address::(oop); 158 | closure.visit_slot(referent_addr); 159 | let discovered_addr = Self::discovered_address::(oop); 160 | closure.visit_slot(discovered_addr); 161 | } 162 | } 163 | 164 | #[allow(unused)] 165 | fn oop_iterate_slow>>( 166 | oop: Oop, 167 | closure: &mut V, 168 | tls: OpaquePointer, 169 | ) { 170 | unsafe { 171 | CLOSURE.with(|x| *x.get() = closure as *mut V as *mut u8); 172 | ((*UPCALLS).scan_object)( 173 | mem::transmute::<*const unsafe extern "C" fn(Address), *mut libc::c_void>( 174 | scan_object_fn:: as *const unsafe extern "C" fn(slot: Address), 175 | ), 176 | mem::transmute::<&OopDesc, ObjectReference>(oop), 177 | tls, 178 | ); 179 | } 180 | } 181 | 182 | fn oop_iterate(oop: Oop, closure: &mut impl SlotVisitor>) { 183 | let klass = oop.klass::(); 184 | let klass_id = klass.id; 185 | assert!( 186 | klass_id as i32 >= 0 && (klass_id as i32) < 6, 187 | "Invalid klass-id: {:x} for oop: {:x}", 188 | klass_id as i32, 189 | unsafe { mem::transmute::(oop) } 190 | ); 191 | match klass_id { 192 | KlassID::Instance => { 193 | let instance_klass = unsafe { klass.cast::() }; 194 | instance_klass.oop_iterate::(oop, closure); 195 | } 196 | KlassID::InstanceClassLoader => { 197 | let instance_klass = unsafe { klass.cast::() }; 198 | instance_klass.oop_iterate::(oop, closure); 199 | } 200 | KlassID::InstanceMirror => { 201 | let instance_klass = unsafe { klass.cast::() }; 202 | instance_klass.oop_iterate::(oop, closure); 203 | } 204 | KlassID::ObjArray => { 205 | let array_klass = unsafe { klass.cast::() }; 206 | array_klass.oop_iterate::(oop, closure); 207 | } 208 | KlassID::TypeArray => { 209 | // Skip scanning primitive arrays as they contain no reference fields. 210 | } 211 | KlassID::InstanceRef => { 212 | let instance_klass = unsafe { klass.cast::() }; 213 | instance_klass.oop_iterate::(oop, closure); 214 | } 215 | } 216 | } 217 | 218 | thread_local! { 219 | static CLOSURE: UnsafeCell<*mut u8> = const { UnsafeCell::new(std::ptr::null_mut()) }; 220 | } 221 | 222 | pub unsafe extern "C" fn scan_object_fn< 223 | const COMPRESSED: bool, 224 | V: SlotVisitor>, 225 | >( 226 | slot: Address, 227 | ) { 228 | let ptr: *mut u8 = CLOSURE.with(|x| *x.get()); 229 | let closure = &mut *(ptr as *mut V); 230 | closure.visit_slot(slot.into()); 231 | } 232 | 233 | pub fn scan_object( 234 | object: ObjectReference, 235 | closure: &mut impl SlotVisitor>, 236 | _tls: VMWorkerThread, 237 | ) { 238 | unsafe { 239 | oop_iterate::(mem::transmute::(object), closure) 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /mmtk/src/reference_glue.rs: -------------------------------------------------------------------------------- 1 | use crate::abi::{InstanceRefKlass, Oop}; 2 | use crate::OpenJDK; 3 | use crate::UPCALLS; 4 | use mmtk::util::opaque_pointer::VMWorkerThread; 5 | use mmtk::util::ObjectReference; 6 | use mmtk::vm::slot::Slot; 7 | use mmtk::vm::ReferenceGlue; 8 | 9 | pub struct VMReferenceGlue {} 10 | 11 | impl ReferenceGlue> for VMReferenceGlue { 12 | type FinalizableType = ObjectReference; 13 | 14 | fn set_referent(reff: ObjectReference, referent: ObjectReference) { 15 | let oop = Oop::from(reff); 16 | InstanceRefKlass::referent_address::(oop).store(referent); 17 | } 18 | fn get_referent(object: ObjectReference) -> Option { 19 | let oop = Oop::from(object); 20 | InstanceRefKlass::referent_address::(oop).load() 21 | } 22 | fn enqueue_references(references: &[ObjectReference], _tls: VMWorkerThread) { 23 | unsafe { 24 | ((*UPCALLS).enqueue_references)(references.as_ptr(), references.len()); 25 | } 26 | } 27 | fn clear_referent(new_reference: ObjectReference) { 28 | let oop = Oop::from(new_reference); 29 | InstanceRefKlass::referent_address::(oop).store_null(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mmtk/src/scanning.rs: -------------------------------------------------------------------------------- 1 | use crate::gc_work::*; 2 | use crate::Slot; 3 | use crate::{NewBuffer, OpenJDKSlot, UPCALLS}; 4 | use crate::{OpenJDK, SlotsClosure}; 5 | use mmtk::memory_manager; 6 | use mmtk::scheduler::WorkBucketStage; 7 | use mmtk::util::opaque_pointer::*; 8 | use mmtk::util::{Address, ObjectReference}; 9 | use mmtk::vm::{RootsWorkFactory, Scanning, SlotVisitor}; 10 | use mmtk::Mutator; 11 | use mmtk::MutatorContext; 12 | 13 | pub struct VMScanning {} 14 | 15 | pub(crate) const WORK_PACKET_CAPACITY: usize = mmtk::scheduler::EDGES_WORK_BUFFER_SIZE; 16 | 17 | extern "C" fn report_slots_and_renew_buffer>( 18 | ptr: *mut Address, 19 | length: usize, 20 | capacity: usize, 21 | factory_ptr: *mut libc::c_void, 22 | ) -> NewBuffer { 23 | if !ptr.is_null() { 24 | // Note: Currently OpenJDKSlot has the same layout as Address. If the layout changes, we 25 | // should fix the Rust-to-C interface. 26 | let buf = unsafe { Vec::::from_raw_parts(ptr as _, length, capacity) }; 27 | let factory: &mut F = unsafe { &mut *(factory_ptr as *mut F) }; 28 | factory.create_process_roots_work(buf); 29 | } 30 | let (ptr, _, capacity) = { 31 | // TODO: Use Vec::into_raw_parts() when the method is available. 32 | use std::mem::ManuallyDrop; 33 | let new_vec = Vec::with_capacity(WORK_PACKET_CAPACITY); 34 | let mut me = ManuallyDrop::new(new_vec); 35 | (me.as_mut_ptr(), me.len(), me.capacity()) 36 | }; 37 | NewBuffer { ptr, capacity } 38 | } 39 | 40 | pub(crate) fn to_slots_closure>(factory: &mut F) -> SlotsClosure { 41 | SlotsClosure { 42 | func: report_slots_and_renew_buffer::, 43 | data: factory as *mut F as *mut libc::c_void, 44 | } 45 | } 46 | 47 | impl Scanning> for VMScanning { 48 | fn scan_object>>( 49 | tls: VMWorkerThread, 50 | object: ObjectReference, 51 | slot_visitor: &mut SV, 52 | ) { 53 | crate::object_scanning::scan_object::(object, slot_visitor, tls); 54 | } 55 | 56 | fn notify_initial_thread_scan_complete(_partial_scan: bool, _tls: VMWorkerThread) { 57 | // unimplemented!() 58 | // TODO 59 | } 60 | 61 | fn scan_roots_in_mutator_thread( 62 | _tls: VMWorkerThread, 63 | mutator: &'static mut Mutator>, 64 | mut factory: impl RootsWorkFactory>, 65 | ) { 66 | let tls = mutator.get_tls(); 67 | unsafe { 68 | ((*UPCALLS).scan_roots_in_mutator_thread)(to_slots_closure(&mut factory), tls); 69 | } 70 | } 71 | 72 | fn scan_vm_specific_roots( 73 | _tls: VMWorkerThread, 74 | factory: impl RootsWorkFactory>, 75 | ) { 76 | memory_manager::add_work_packets( 77 | crate::singleton::(), 78 | WorkBucketStage::Prepare, 79 | vec![ 80 | Box::new(ScanUniverseRoots::new(factory.clone())) as _, 81 | Box::new(ScanJNIHandlesRoots::new(factory.clone())) as _, 82 | Box::new(ScanObjectSynchronizerRoots::new(factory.clone())) as _, 83 | Box::new(ScanManagementRoots::new(factory.clone())) as _, 84 | Box::new(ScanJvmtiExportRoots::new(factory.clone())) as _, 85 | Box::new(ScanAOTLoaderRoots::new(factory.clone())) as _, 86 | Box::new(ScanSystemDictionaryRoots::new(factory.clone())) as _, 87 | Box::new(ScanCodeCacheRoots::new(factory.clone())) as _, 88 | Box::new(ScanStringTableRoots::new(factory.clone())) as _, 89 | Box::new(ScanClassLoaderDataGraphRoots::new(factory.clone())) as _, 90 | Box::new(ScanWeakProcessorRoots::new(factory.clone())) as _, 91 | Box::new(ScanVMThreadRoots::new(factory)) as _, 92 | ], 93 | ); 94 | } 95 | 96 | fn supports_return_barrier() -> bool { 97 | unimplemented!() 98 | } 99 | 100 | fn prepare_for_roots_re_scanning() { 101 | unsafe { 102 | ((*UPCALLS).prepare_for_roots_re_scanning)(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /mmtk/src/vm_metadata/constants.rs: -------------------------------------------------------------------------------- 1 | use mmtk::{util::metadata::MetadataSpec, vm::*}; 2 | 3 | #[cfg(target_pointer_width = "64")] 4 | #[allow(unused)] 5 | pub(crate) const FORWARDING_BITS_OFFSET: isize = 56; 6 | #[cfg(target_pointer_width = "32")] 7 | #[allow(unused)] 8 | pub(crate) const FORWARDING_BITS_OFFSET: isize = unimplemented!(); 9 | 10 | pub(crate) const FORWARDING_POINTER_OFFSET: isize = 0; 11 | 12 | // Global MetadataSpecs - Start 13 | 14 | /// Global logging bit metadata spec 15 | /// 1 bit per object 16 | pub(crate) const LOGGING_SIDE_METADATA_SPEC: VMGlobalLogBitSpec = VMGlobalLogBitSpec::side_first(); 17 | 18 | // Global MetadataSpecs - End 19 | 20 | // PolicySpecific MetadataSpecs - Start 21 | 22 | /// PolicySpecific forwarding pointer metadata spec 23 | /// 1 word per object 24 | pub(crate) const FORWARDING_POINTER_METADATA_SPEC: VMLocalForwardingPointerSpec = 25 | VMLocalForwardingPointerSpec::in_header(FORWARDING_POINTER_OFFSET); 26 | 27 | cfg_if::cfg_if! { 28 | if #[cfg(feature = "mark_bit_in_header")] { 29 | /// PolicySpecific mark bit metadata spec 30 | /// 1 bit per object 31 | pub(crate) const MARKING_METADATA_SPEC: VMLocalMarkBitSpec = 32 | VMLocalMarkBitSpec::in_header(FORWARDING_BITS_OFFSET); 33 | 34 | #[allow(unused)] 35 | const LAST_SIDE_SPEC_BEFORE_MARK: &MetadataSpec = LOS_METADATA_SPEC.as_spec(); 36 | } else { 37 | /// PolicySpecific mark bit metadata spec 38 | /// 1 bit per object 39 | pub(crate) const MARKING_METADATA_SPEC: VMLocalMarkBitSpec = 40 | VMLocalMarkBitSpec::side_after(LOS_METADATA_SPEC.as_spec()); 41 | 42 | #[allow(unused)] 43 | const LAST_SIDE_SPEC_BEFORE_MARK: &MetadataSpec = MARKING_METADATA_SPEC.as_spec(); 44 | } 45 | } 46 | 47 | cfg_if::cfg_if! { 48 | if #[cfg(feature = "forwarding_bits_on_side")] { 49 | /// PolicySpecific object forwarding status metadata spec 50 | /// 2 bits per object 51 | pub(crate) const FORWARDING_BITS_METADATA_SPEC: VMLocalForwardingBitsSpec = 52 | VMLocalForwardingBitsSpec::side_after(LAST_SIDE_SPEC_BEFORE_MARK); 53 | } else { 54 | /// PolicySpecific object forwarding status metadata spec 55 | /// 2 bits per object 56 | pub(crate) const FORWARDING_BITS_METADATA_SPEC: VMLocalForwardingBitsSpec = 57 | VMLocalForwardingBitsSpec::in_header(FORWARDING_BITS_OFFSET); 58 | } 59 | } 60 | 61 | /// PolicySpecific mark-and-nursery bits metadata spec 62 | /// 2-bits per object 63 | pub(crate) const LOS_METADATA_SPEC: VMLocalLOSMarkNurserySpec = 64 | VMLocalLOSMarkNurserySpec::side_first(); 65 | 66 | // PolicySpecific MetadataSpecs - End 67 | -------------------------------------------------------------------------------- /mmtk/src/vm_metadata/mod.rs: -------------------------------------------------------------------------------- 1 | mod constants; 2 | 3 | pub(crate) use self::constants::*; 4 | -------------------------------------------------------------------------------- /openjdk/CompileThirdPartyHeap.gmk: -------------------------------------------------------------------------------- 1 | # Misc variables 2 | YELLOW='\033[1;33m' 3 | NC='\033[0m' 4 | 5 | # THIRD_PARTY_HEAP points to mmtk-openjdk/openjdk 6 | MMTK_RUST_ROOT = $(THIRD_PARTY_HEAP)/../mmtk 7 | MMTK_CPP_ROOT = $(THIRD_PARTY_HEAP) 8 | 9 | # Grab OpenJDK version specified in mmtk/Cargo.toml and local OpenJDK version 10 | OPENJDK_VERSION=`cd $(MMTK_RUST_ROOT) ; cargo read-manifest --manifest-path=Cargo.toml | python3 -c 'import json,sys; print(json.load(sys.stdin)["metadata"]["openjdk"]["openjdk_version"])'` 11 | OPENJDK_LOCAL_VERSION=`git rev-parse HEAD` 12 | 13 | # Get the current host triple. This is used for the PGO build as mentioned in 14 | # the best practices for PGO here: 15 | # https://doc.rust-lang.org/rustc/profile-guided-optimization.html#a-complete-cargo-workflow 16 | HOST_TRIPLE=`rustc -vV | grep host | cut -d' ' -f2` 17 | 18 | ifdef MMTK_PLAN 19 | GC_FEATURES=--features $(MMTK_PLAN) 20 | endif 21 | 22 | ifeq ($(MMTK_VO_BIT), 1) 23 | ifndef GC_FEATURES 24 | GC_FEATURES=--features vo_bit 25 | else 26 | GC_FEATURES:=$(strip $(GC_FEATURES))",vo_bit" 27 | endif 28 | endif 29 | 30 | ifeq ($(MMTK_MARK_IN_HEADER), 1) 31 | ifndef GC_FEATURES 32 | GC_FEATURES=--features mark_bit_in_header 33 | else 34 | GC_FEATURES:=$(strip $(GC_FEATURES))",mark_bit_in_header" 35 | endif 36 | endif 37 | 38 | ifeq ($(MMTK_FORWARDING_ON_SIDE), 1) 39 | ifndef GC_FEATURES 40 | GC_FEATURES=--features forwarding_bits_on_side 41 | else 42 | GC_FEATURES:=$(strip $(GC_FEATURES))",forwarding_bits_on_side" 43 | endif 44 | endif 45 | 46 | ifeq ($(MMTK_EXTREME_ASSERTIONS), 1) 47 | ifndef GC_FEATURES 48 | GC_FEATURES=--features mmtk_extreme_assertions 49 | else 50 | GC_FEATURES:=$(strip $(GC_FEATURES))",mmtk_extreme_assertions" 51 | endif 52 | endif 53 | 54 | ifeq ($(MMTK_MALLOC_MARK_SWEEP), 1) 55 | ifndef GC_FEATURES 56 | GC_FEATURES=--features malloc_mark_sweep 57 | else 58 | GC_FEATURES:=$(strip $(GC_FEATURES))",malloc_mark_sweep" 59 | endif 60 | endif 61 | 62 | ifeq ($(MMTK_SANITY), 1) 63 | ifndef GC_FEATURES 64 | GC_FEATURES=--features mmtk/sanity 65 | else 66 | GC_FEATURES:=$(strip $(GC_FEATURES))",mmtk/sanity" 67 | endif 68 | endif 69 | 70 | LIB_MMTK := $(JVM_LIB_OUTPUTDIR)/libmmtk_openjdk.so 71 | 72 | ifeq ($(DEBUG_LEVEL), release) 73 | CARGO_PROFILE = release 74 | CARGO_PROFILE_FLAG = --release 75 | else 76 | CARGO_PROFILE = debug 77 | endif 78 | 79 | $(LIB_MMTK): FORCE 80 | if [[ "$(OPENJDK_VERSION)" != "$(OPENJDK_LOCAL_VERSION)" ]]; then \ 81 | echo -e $(YELLOW)WARNING: Local OpenJDK version does not match version specified in mmtk/Cargo.toml$(NC); \ 82 | echo -e $(YELLOW)Local OpenJDK version $(OPENJDK_LOCAL_VERSION)$(NC); \ 83 | echo -e $(YELLOW)mmtk/Cargo.toml OpenJDK version $(OPENJDK_VERSION)$(NC); \ 84 | fi 85 | echo "cd $(MMTK_RUST_ROOT) && cargo --version && cargo build $(CARGO_PROFILE_FLAG) --target $(HOST_TRIPLE) $(GC_FEATURES)" 86 | cd $(MMTK_RUST_ROOT) && cargo --version && cargo build $(CARGO_PROFILE_FLAG) --target $(HOST_TRIPLE) $(GC_FEATURES) 87 | cp $(MMTK_RUST_ROOT)/target/$(HOST_TRIPLE)/$(CARGO_PROFILE)/libmmtk_openjdk.so $(LIB_MMTK) 88 | 89 | JVM_LIBS += -L$(JVM_LIB_OUTPUTDIR) -lmmtk_openjdk 90 | JVM_LDFLAGS += '-Wl,-rpath,$$ORIGIN' 91 | 92 | FORCE: 93 | 94 | TARGETS += $(LIB_MMTK) 95 | JVM_SRC_DIRS += $(MMTK_CPP_ROOT) $(MMTK_CPP_ROOT)/barriers 96 | JVM_CFLAGS += -std=c++11 -DINCLUDE_THIRD_PARTY_HEAP -DTHIRD_PARTY_HEAP_SRC=$(MMTK_CPP_ROOT) 97 | ifeq ($(MMTK_VO_BIT), 1) 98 | JVM_CFLAGS += -DMMTK_ENABLE_VO_BIT 99 | endif 100 | 101 | $(BUILD_LIBJVM): $(LIB_MMTK) 102 | -------------------------------------------------------------------------------- /openjdk/barriers/mmtkNoBarrier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_BARRIERS_MMTK_NO_BARRIER_HPP 2 | #define MMTK_OPENJDK_BARRIERS_MMTK_NO_BARRIER_HPP 3 | 4 | #include "../mmtkBarrierSet.hpp" 5 | #include "../mmtkBarrierSetAssembler_x86.hpp" 6 | #include "../mmtkBarrierSetC1.hpp" 7 | #include "../mmtkBarrierSetC2.hpp" 8 | 9 | class MMTkNoBarrierSetRuntime: public MMTkBarrierSetRuntime {}; 10 | 11 | class MMTkNoBarrierSetAssembler: public MMTkBarrierSetAssembler {}; 12 | 13 | class MMTkNoBarrierSetC1: public MMTkBarrierSetC1 {}; 14 | 15 | class MMTkNoBarrierSetC2: public MMTkBarrierSetC2 {}; 16 | 17 | struct MMTkNoBarrier: MMTkBarrierImpl< 18 | MMTkNoBarrierSetRuntime, 19 | MMTkNoBarrierSetAssembler, 20 | MMTkNoBarrierSetC1, 21 | MMTkNoBarrierSetC2 22 | > {}; 23 | 24 | #endif // MMTK_OPENJDK_BARRIERS_MMTK_NO_BARRIER_HPP 25 | -------------------------------------------------------------------------------- /openjdk/barriers/mmtkObjectBarrier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_BARRIERS_MMTK_OBJECT_BARRIER_HPP 2 | #define MMTK_OPENJDK_BARRIERS_MMTK_OBJECT_BARRIER_HPP 3 | 4 | #include "../mmtk.h" 5 | #include "../mmtkBarrierSet.hpp" 6 | #include "../mmtkBarrierSetAssembler_x86.hpp" 7 | #include "../mmtkBarrierSetC1.hpp" 8 | #include "../mmtkBarrierSetC2.hpp" 9 | #include "c1/c1_LIRAssembler.hpp" 10 | #include "c1/c1_MacroAssembler.hpp" 11 | #include "gc/shared/barrierSet.hpp" 12 | #include "opto/callnode.hpp" 13 | #include "opto/idealKit.hpp" 14 | 15 | #define SIDE_METADATA_WORST_CASE_RATIO_LOG 1 16 | #define LOG_BYTES_IN_CHUNK 22 17 | #define CHUNK_MASK ((1L << LOG_BYTES_IN_CHUNK) - 1) 18 | 19 | const intptr_t SIDE_METADATA_BASE_ADDRESS = (intptr_t) GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS; 20 | 21 | class MMTkObjectBarrierSetRuntime: public MMTkBarrierSetRuntime { 22 | public: 23 | // Interfaces called by `MMTkBarrierSet::AccessBarrier` 24 | virtual void object_reference_write_post(oop src, oop* slot, oop target) const override; 25 | virtual void object_reference_array_copy_post(oop* src, oop* dst, size_t count) const override { 26 | object_reference_array_copy_post_call((void*) src, (void*) dst, count); 27 | } 28 | virtual void object_probable_write(oop new_obj) const override; 29 | }; 30 | 31 | class MMTkObjectBarrierSetAssembler: public MMTkBarrierSetAssembler { 32 | protected: 33 | virtual void object_reference_write_post(MacroAssembler* masm, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, bool compensate_val_reg) const override; 34 | public: 35 | virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) override; 36 | virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) override; 37 | }; 38 | 39 | class MMTkObjectBarrierSetC1: public MMTkBarrierSetC1 { 40 | protected: 41 | virtual void object_reference_write_post(LIRAccess& access, LIR_Opr src, LIR_Opr slot, LIR_Opr new_val) const override; 42 | 43 | virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register) override { 44 | return MMTkBarrierSetC1::resolve_address_in_register(access, resolve_in_register); 45 | } 46 | }; 47 | 48 | class MMTkObjectBarrierSetC2: public MMTkBarrierSetC2 { 49 | protected: 50 | virtual void object_reference_write_post(GraphKit* kit, Node* src, Node* slot, Node* val) const override; 51 | }; 52 | 53 | struct MMTkObjectBarrier: MMTkBarrierImpl< 54 | MMTkObjectBarrierSetRuntime, 55 | MMTkObjectBarrierSetAssembler, 56 | MMTkObjectBarrierSetC1, 57 | MMTkObjectBarrierSetC2 58 | > {}; 59 | 60 | #endif // MMTK_OPENJDK_BARRIERS_MMTK_OBJECT_BARRIER_HPP 61 | -------------------------------------------------------------------------------- /openjdk/mmtk.h: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_MMTK_H 2 | #define MMTK_OPENJDK_MMTK_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | typedef void* MMTk_Mutator; 13 | typedef void* MMTk_TraceLocal; 14 | 15 | // This has the same layout as mmtk::util::alloc::AllocationError 16 | typedef enum { 17 | HeapOutOfMemory, 18 | MmapOutOfMemory, 19 | } MMTkAllocationError; 20 | 21 | extern const uintptr_t GLOBAL_SIDE_METADATA_BASE_ADDRESS; 22 | extern const uintptr_t GLOBAL_SIDE_METADATA_VM_BASE_ADDRESS; 23 | extern const uintptr_t VO_BIT_ADDRESS; 24 | extern const size_t MMTK_MARK_COMPACT_HEADER_RESERVED_IN_BYTES; 25 | extern const uintptr_t FREE_LIST_ALLOCATOR_SIZE; 26 | 27 | extern const char* get_mmtk_version(); 28 | 29 | /** 30 | * Allocation 31 | */ 32 | extern MMTk_Mutator bind_mutator(void *tls); 33 | extern void destroy_mutator(MMTk_Mutator mutator); 34 | extern void flush_mutator(MMTk_Mutator mutator); 35 | 36 | extern void* alloc(MMTk_Mutator mutator, size_t size, 37 | size_t align, size_t offset, int allocator); 38 | 39 | extern void* alloc_slow_bump_monotone_immortal(MMTk_Mutator mutator, size_t size, 40 | size_t align, size_t offset); 41 | extern void* alloc_slow_bump_monotone_copy(MMTk_Mutator mutator, size_t size, 42 | size_t align, size_t offset); 43 | extern void* alloc_slow_largeobject(MMTk_Mutator mutator, size_t size, 44 | size_t align, size_t offset); 45 | 46 | extern void post_alloc(MMTk_Mutator mutator, void* refer, 47 | size_t bytes, int allocator); 48 | 49 | /// Full pre-barrier 50 | extern void mmtk_object_reference_write_pre(MMTk_Mutator mutator, void* src, void* slot, void* target); 51 | 52 | /// Full post-barrier 53 | extern void mmtk_object_reference_write_post(MMTk_Mutator mutator, void* src, void* slot, void* target); 54 | 55 | /// Generic slow-path 56 | extern void mmtk_object_reference_write_slow(MMTk_Mutator mutator, void* src, void* slot, void* target); 57 | 58 | /// Full array-copy pre-barrier 59 | extern void mmtk_array_copy_pre(MMTk_Mutator mutator, void* src, void* dst, size_t count); 60 | 61 | /// Full array-copy post-barrier 62 | extern void mmtk_array_copy_post(MMTk_Mutator mutator, void* src, void* dst, size_t count); 63 | 64 | /// C2 slowpath allocation barrier 65 | extern void mmtk_object_probable_write(MMTk_Mutator mutator, void* obj); 66 | 67 | extern void release_buffer(void** buffer, size_t len, size_t cap); 68 | 69 | extern bool is_in_mmtk_spaces(void* ref); 70 | extern bool is_mapped_address(void* addr); 71 | 72 | // This type declaration needs to match AllocatorSelector in mmtk-core 73 | struct AllocatorSelector { 74 | uint8_t tag; 75 | uint8_t index; 76 | }; 77 | 78 | #define TAG_BUMP_POINTER 0 79 | #define TAG_LARGE_OBJECT 1 80 | #define TAG_MALLOC 2 81 | #define TAG_IMMIX 3 82 | #define TAG_MARK_COMPACT 4 83 | #define TAG_FREE_LIST 5 84 | 85 | extern AllocatorSelector get_allocator_mapping(int allocator); 86 | extern size_t get_max_non_los_default_alloc_bytes(); 87 | 88 | /** 89 | * Finalization 90 | */ 91 | extern void add_finalizer(void* obj); 92 | extern void* get_finalized_object(); 93 | 94 | /** 95 | * Misc 96 | */ 97 | extern char* mmtk_active_barrier(); 98 | extern void initialize_collection(void *tls); 99 | extern void gc_init(size_t heap_size); 100 | extern bool will_never_move(void* object); 101 | extern bool process(char* name, char* value); 102 | extern bool process_bulk(char* options); 103 | extern void scan_region(); 104 | extern void handle_user_collection_request(void *tls); 105 | 106 | extern void start_control_collector(void *tls, void *context); 107 | extern void start_worker(void *tls, void* worker); 108 | 109 | extern size_t mmtk_add_nmethod_oop(void* object); 110 | extern size_t mmtk_register_nmethod(void* nm); 111 | extern size_t mmtk_unregister_nmethod(void* nm); 112 | 113 | /** 114 | * VM Accounting 115 | */ 116 | extern size_t free_bytes(); 117 | extern size_t total_bytes(); 118 | 119 | typedef struct { 120 | void** buf; 121 | size_t cap; 122 | } NewBuffer; 123 | 124 | struct MutatorClosure { 125 | void (*func)(MMTk_Mutator mutator, void* data); 126 | void* data; 127 | 128 | void invoke(MMTk_Mutator mutator) { 129 | func(mutator, data); 130 | } 131 | }; 132 | 133 | struct SlotsClosure { 134 | NewBuffer (*func)(void** buf, size_t size, size_t capa, void* data); 135 | void* data; 136 | 137 | NewBuffer invoke(void** buf, size_t size, size_t capa) { 138 | return func(buf, size, capa, data); 139 | } 140 | }; 141 | 142 | /** 143 | * OpenJDK-specific 144 | */ 145 | typedef struct { 146 | void (*stop_all_mutators) (void *tls, MutatorClosure closure); 147 | void (*resume_mutators) (void *tls); 148 | void (*spawn_gc_thread) (void *tls, int kind, void *ctx); 149 | void (*block_for_gc) (); 150 | void (*out_of_memory) (void *tls, MMTkAllocationError err_kind); 151 | void (*get_mutators) (MutatorClosure closure); 152 | void (*scan_object) (void* trace, void* object, void* tls); 153 | void (*dump_object) (void* object); 154 | size_t (*get_object_size) (void* object); 155 | void* (*get_mmtk_mutator) (void* tls); 156 | bool (*is_mutator) (void* tls); 157 | void (*harness_begin) (); 158 | void (*harness_end) (); 159 | size_t (*compute_klass_mem_layout_checksum) (); 160 | int (*offset_of_static_fields) (); 161 | int (*static_oop_field_count_offset) (); 162 | int (*referent_offset) (); 163 | int (*discovered_offset) (); 164 | char* (*dump_object_string) (void* object); 165 | void (*scan_roots_in_all_mutator_threads)(SlotsClosure closure); 166 | void (*scan_roots_in_mutator_thread)(SlotsClosure closure, void* tls); 167 | void (*scan_universe_roots) (SlotsClosure closure); 168 | void (*scan_jni_handle_roots) (SlotsClosure closure); 169 | void (*scan_object_synchronizer_roots) (SlotsClosure closure); 170 | void (*scan_management_roots) (SlotsClosure closure); 171 | void (*scan_jvmti_export_roots) (SlotsClosure closure); 172 | void (*scan_aot_loader_roots) (SlotsClosure closure); 173 | void (*scan_system_dictionary_roots) (SlotsClosure closure); 174 | void (*scan_code_cache_roots) (SlotsClosure closure); 175 | void (*scan_string_table_roots) (SlotsClosure closure); 176 | void (*scan_class_loader_data_graph_roots) (SlotsClosure closure); 177 | void (*scan_weak_processor_roots) (SlotsClosure closure); 178 | void (*scan_vm_thread_roots) (SlotsClosure closure); 179 | size_t (*number_of_mutators)(); 180 | void (*schedule_finalizer)(); 181 | void (*prepare_for_roots_re_scanning)(); 182 | void (*enqueue_references)(void** objects, size_t len); 183 | } OpenJDK_Upcalls; 184 | 185 | extern void openjdk_gc_init(OpenJDK_Upcalls *calls); 186 | extern bool openjdk_is_gc_initialized(); 187 | 188 | extern bool mmtk_set_heap_size(size_t min, size_t max); 189 | 190 | extern bool mmtk_enable_compressed_oops(); 191 | extern void* mmtk_narrow_oop_base(); 192 | extern size_t mmtk_narrow_oop_shift(); 193 | extern size_t mmtk_set_compressed_klass_base_and_shift(void* base, size_t shift); 194 | 195 | extern size_t used_bytes(); 196 | extern void* starting_heap_address(); 197 | extern void* last_heap_address(); 198 | extern void iterator(); // ??? 199 | 200 | 201 | // (It is the total_space - capacity_of_to_space in Semispace ) 202 | // PZ: It shouldn't be ...? 203 | extern size_t openjdk_max_capacity(); 204 | extern size_t _noaccess_prefix(); // ??? 205 | extern size_t _alignment(); // ??? 206 | extern bool executable(); 207 | 208 | /** 209 | * Reference Processing 210 | */ 211 | extern void add_weak_candidate(void* ref, void* referent); 212 | extern void add_soft_candidate(void* ref, void* referent); 213 | extern void add_phantom_candidate(void* ref, void* referent); 214 | 215 | extern void mmtk_harness_begin_impl(); 216 | extern void mmtk_harness_end_impl(); 217 | 218 | extern void mmtk_builder_read_env_var_settings(); 219 | extern void mmtk_builder_set_threads(size_t value); 220 | extern void mmtk_builder_set_transparent_hugepages(bool value); 221 | 222 | #ifdef __cplusplus 223 | } 224 | #endif 225 | 226 | #endif // MMTK_OPENJDK_MMTK_H 227 | -------------------------------------------------------------------------------- /openjdk/mmtkBarrierSet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "barriers/mmtkNoBarrier.hpp" 27 | #include "barriers/mmtkObjectBarrier.hpp" 28 | #include "mmtkBarrierSet.hpp" 29 | #include "mmtkBarrierSetAssembler_x86.hpp" 30 | #include "runtime/interfaceSupport.inline.hpp" 31 | #ifdef COMPILER1 32 | #include "mmtkBarrierSetC1.hpp" 33 | #endif 34 | #ifdef COMPILER2 35 | #include "mmtkBarrierSetC2.hpp" 36 | #endif 37 | 38 | MMTkAllocatorOffsets get_tlab_top_and_end_offsets(AllocatorSelector selector) { 39 | int tlab_top_offset, tlab_end_offset; 40 | int allocators_base_offset = in_bytes(JavaThread::third_party_heap_mutator_offset()) 41 | + in_bytes(byte_offset_of(MMTkMutatorContext, allocators)); 42 | 43 | if (selector.tag == TAG_IMMIX) { 44 | int allocator_base_offset = allocators_base_offset 45 | + in_bytes(byte_offset_of(Allocators, immix)) 46 | + selector.index * sizeof(ImmixAllocator); 47 | tlab_top_offset = allocator_base_offset + in_bytes(byte_offset_of(ImmixAllocator, cursor)); 48 | tlab_end_offset = allocator_base_offset + in_bytes(byte_offset_of(ImmixAllocator, limit)); 49 | } else if (selector.tag == TAG_BUMP_POINTER) { 50 | int allocator_base_offset = allocators_base_offset 51 | + in_bytes(byte_offset_of(Allocators, bump_pointer)) 52 | + selector.index * sizeof(BumpAllocator); 53 | tlab_top_offset = allocator_base_offset + in_bytes(byte_offset_of(BumpAllocator, cursor)); 54 | tlab_end_offset = allocator_base_offset + in_bytes(byte_offset_of(BumpAllocator, limit)); 55 | } else if (selector.tag == TAG_MARK_COMPACT) { 56 | int allocator_base_offset = allocators_base_offset 57 | + in_bytes(byte_offset_of(Allocators, markcompact)) 58 | + selector.index * sizeof(MarkCompactAllocator) 59 | + in_bytes(byte_offset_of(MarkCompactAllocator, bump_allocator)); 60 | tlab_top_offset = allocator_base_offset + in_bytes(byte_offset_of(BumpAllocator, cursor)); 61 | tlab_end_offset = allocator_base_offset + in_bytes(byte_offset_of(BumpAllocator, limit)); 62 | } else { 63 | fatal("Unimplemented allocator fastpath\n"); 64 | // Setting values to make compiler happy about unitialized variables. This 65 | // case should never be reached in practice, however. 66 | tlab_top_offset = 0; 67 | tlab_end_offset = 0; 68 | } 69 | 70 | MMTkAllocatorOffsets alloc_offsets; 71 | alloc_offsets.tlab_top_offset = tlab_top_offset; 72 | alloc_offsets.tlab_end_offset = tlab_end_offset; 73 | return alloc_offsets; 74 | } 75 | 76 | MMTkBarrierBase* get_selected_barrier() { 77 | static MMTkBarrierBase* selected_barrier = NULL; 78 | if (selected_barrier) return selected_barrier; 79 | const char* barrier = mmtk_active_barrier(); 80 | if (strcmp(barrier, "NoBarrier") == 0) selected_barrier = new MMTkNoBarrier(); 81 | else if (strcmp(barrier, "ObjectBarrier") == 0) selected_barrier = new MMTkObjectBarrier(); 82 | else guarantee(false, "Unimplemented"); 83 | return selected_barrier; 84 | } 85 | 86 | MMTkBarrierSet::MMTkBarrierSet(MemRegion whole_heap): 87 | BarrierSet(get_selected_barrier()->create_assembler(), 88 | get_selected_barrier()->create_c1(), 89 | get_selected_barrier()->create_c2(), 90 | BarrierSet::FakeRtti(BarrierSet::ThirdPartyHeapBarrierSet)), 91 | _whole_heap(whole_heap), 92 | _runtime(get_selected_barrier()->create_runtime()) {} 93 | 94 | void MMTkBarrierSet::write_ref_array_work(MemRegion mr) { 95 | guarantee(false, "NoBarrier::write_ref_arrey_work not supported"); 96 | } 97 | 98 | // Inform the BarrierSet that the the covered heap region that starts 99 | // with "base" has been changed to have the given size (possibly from 0, 100 | // for initialization.) 101 | void MMTkBarrierSet::resize_covered_region(MemRegion new_region) { 102 | guarantee(false, "NoBarrier::resize_covered_region not supported"); 103 | } 104 | 105 | 106 | void MMTkBarrierSet::on_thread_destroy(Thread* thread) { 107 | thread->third_party_heap_mutator.flush(); 108 | thread->third_party_heap_mutator.destroy(); 109 | } 110 | 111 | void MMTkBarrierSet::on_thread_attach(JavaThread* thread) { 112 | thread->third_party_heap_mutator.flush(); 113 | } 114 | 115 | void MMTkBarrierSet::on_thread_detach(JavaThread* thread) { 116 | thread->third_party_heap_mutator.flush(); 117 | } 118 | 119 | 120 | // If the barrier set imposes any alignment restrictions on boundaries 121 | // within the heap, this function tells whether they are met. 122 | bool MMTkBarrierSet::is_aligned(HeapWord* addr) { 123 | return true; 124 | } 125 | 126 | // Print a description of the memory for the barrier set 127 | void MMTkBarrierSet::print_on(outputStream* st) const { 128 | 129 | } 130 | 131 | bool MMTkBarrierSet::is_slow_path_call(address call) { 132 | return runtime()->is_slow_path_call(call); 133 | } 134 | 135 | void MMTkBarrierSetRuntime::object_reference_write_pre_call(void* src, void* slot, void* target) { 136 | ::mmtk_object_reference_write_pre((MMTk_Mutator) &Thread::current()->third_party_heap_mutator, src, slot, target); 137 | } 138 | 139 | void MMTkBarrierSetRuntime::object_reference_write_post_call(void* src, void* slot, void* target) { 140 | ::mmtk_object_reference_write_post((MMTk_Mutator) &Thread::current()->third_party_heap_mutator, src, slot, target); 141 | } 142 | 143 | void MMTkBarrierSetRuntime::object_reference_write_slow_call(void* src, void* slot, void* target) { 144 | ::mmtk_object_reference_write_slow((MMTk_Mutator) &Thread::current()->third_party_heap_mutator, src, slot, target); 145 | } 146 | 147 | void MMTkBarrierSetRuntime::object_reference_array_copy_pre_call(void* src, void* dst, size_t count) { 148 | ::mmtk_array_copy_pre((MMTk_Mutator) &Thread::current()->third_party_heap_mutator, src, dst, count); 149 | } 150 | 151 | void MMTkBarrierSetRuntime::object_reference_array_copy_post_call(void* src, void* dst, size_t count) { 152 | ::mmtk_array_copy_post((MMTk_Mutator) &Thread::current()->third_party_heap_mutator, src, dst, count); 153 | } 154 | -------------------------------------------------------------------------------- /openjdk/mmtkBarrierSetAssembler_x86.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "asm/macroAssembler.inline.hpp" 27 | #include "interpreter/interp_masm.hpp" 28 | #include "mmtkBarrierSet.hpp" 29 | #include "mmtkBarrierSetAssembler_x86.hpp" 30 | #include "mmtkBarrierSetC1.hpp" 31 | #include "mmtkMutator.hpp" 32 | #include "runtime/sharedRuntime.hpp" 33 | #include "utilities/macros.hpp" 34 | #include "c1/c1_LIRAssembler.hpp" 35 | 36 | #define __ masm-> 37 | 38 | void MMTkBarrierSetAssembler::eden_allocate(MacroAssembler* masm, Register thread, Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Label& slow_case) { 39 | assert(obj == rax, "obj must be in rax, for cmpxchg"); 40 | assert_different_registers(obj, var_size_in_bytes, t1); 41 | 42 | if (!MMTK_ENABLE_ALLOCATION_FASTPATH) { 43 | __ jmp(slow_case); 44 | } else { 45 | // MMTk size check. If the alloc size is larger than the allowed max size for non los, 46 | // we jump to slow path and allodate with LOS in slowpath. 47 | // Note that OpenJDK has a slow path check. Search for layout_helper_needs_slow_path and FastAllocateSizeLimit. 48 | // I tried to set FastAllocateSizeLimit in MMTkHeap::initialize(). But there are still large objects allocated into the 49 | // default space. 50 | assert(MMTkMutatorContext::max_non_los_default_alloc_bytes != 0, "max_non_los_default_alloc_bytes hasn't been initialized"); 51 | size_t max_non_los_bytes = MMTkMutatorContext::max_non_los_default_alloc_bytes; 52 | size_t extra_header = 0; 53 | // fastpath, we only use default allocator 54 | Allocator allocator = AllocatorDefault; 55 | // We need to figure out which allocator we are using by querying MMTk. 56 | AllocatorSelector selector = get_allocator_mapping(allocator); 57 | if (selector.tag == TAG_MARK_COMPACT) extra_header = MMTK_MARK_COMPACT_HEADER_RESERVED_IN_BYTES; 58 | 59 | if (var_size_in_bytes == noreg) { 60 | // constant alloc size. If it is larger than max_non_los_bytes, we directly go to slowpath. 61 | if ((size_t)con_size_in_bytes > max_non_los_bytes - extra_header) { 62 | __ jmp(slow_case); 63 | return; 64 | } 65 | } else { 66 | // var alloc size. We compare with max_non_los_bytes and conditionally jump to slowpath. 67 | __ cmpptr(var_size_in_bytes, max_non_los_bytes - extra_header); 68 | __ jcc(Assembler::aboveEqual, slow_case); 69 | } 70 | 71 | if (selector.tag == TAG_MALLOC || selector.tag == TAG_LARGE_OBJECT || selector.tag == TAG_FREE_LIST) { 72 | __ jmp(slow_case); 73 | return; 74 | } 75 | 76 | // Calculate offsets of TLAB top and end 77 | Address cursor, limit; 78 | MMTkAllocatorOffsets alloc_offsets = get_tlab_top_and_end_offsets(selector); 79 | 80 | cursor = Address(r15_thread, alloc_offsets.tlab_top_offset); 81 | limit = Address(r15_thread, alloc_offsets.tlab_end_offset); 82 | 83 | // obj = load lab.cursor 84 | __ movptr(obj, cursor); 85 | if (selector.tag == TAG_MARK_COMPACT) __ addptr(obj, extra_header); 86 | // end = obj + size 87 | Register end = t1; 88 | if (var_size_in_bytes == noreg) { 89 | __ lea(end, Address(obj, con_size_in_bytes)); 90 | } else { 91 | __ lea(end, Address(obj, var_size_in_bytes, Address::times_1)); 92 | } 93 | // slowpath if end < obj 94 | __ cmpptr(end, obj); 95 | __ jcc(Assembler::below, slow_case); 96 | // slowpath if end > lab.limit 97 | __ cmpptr(end, limit); 98 | __ jcc(Assembler::above, slow_case); 99 | // lab.cursor = end 100 | __ movptr(cursor, end); 101 | bool enable_vo_bit = false; 102 | #ifdef MMTK_ENABLE_VO_BIT 103 | enable_vo_bit = true; 104 | #endif 105 | if (enable_vo_bit || selector.tag == TAG_MARK_COMPACT) { 106 | Register tmp3 = rdi; 107 | Register tmp2 = rscratch1; 108 | assert_different_registers(obj, tmp2, tmp3, rcx); 109 | 110 | // tmp2 = load-byte (SIDE_METADATA_BASE_ADDRESS + (obj >> 6)); 111 | __ movptr(tmp3, obj); 112 | __ shrptr(tmp3, 6); 113 | __ movptr(tmp2, VO_BIT_BASE_ADDRESS); 114 | __ movb(tmp2, Address(tmp2, tmp3)); 115 | // tmp3 = 1 << ((obj >> 3) & 7) 116 | // 1. rcx = (obj >> 3) & 7 117 | __ movptr(rcx, obj); 118 | __ shrptr(rcx, 3); 119 | __ andptr(rcx, 7); 120 | // 2. tmp3 = 1 << rcx 121 | __ movptr(tmp3, 1); 122 | __ shlptr(tmp3); 123 | // tmp2 = tmp2 | tmp3 124 | __ orptr(tmp2, tmp3); 125 | 126 | // store-byte tmp2 (SIDE_METADATA_BASE_ADDRESS + (obj >> 6)) 127 | __ movptr(tmp3, obj); 128 | __ shrptr(tmp3, 6); 129 | __ movptr(rcx, VO_BIT_BASE_ADDRESS); 130 | __ movb(Address(rcx, tmp3), tmp2); 131 | } 132 | 133 | // BarrierSetAssembler::incr_allocated_bytes 134 | if (var_size_in_bytes->is_valid()) { 135 | __ addq(Address(r15_thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes); 136 | } else { 137 | __ addq(Address(r15_thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes); 138 | } 139 | __ addq(Address(r15_thread, in_bytes(JavaThread::allocated_bytes_offset())), extra_header); 140 | } 141 | } 142 | 143 | #undef __ 144 | 145 | #define __ sasm-> 146 | 147 | void MMTkBarrierSetAssembler::generate_c1_write_barrier_runtime_stub(StubAssembler* sasm) const { 148 | __ prologue("mmtk_write_barrier", false); 149 | 150 | Address store_addr(rbp, 4*BytesPerWord); 151 | 152 | Label done, runtime; 153 | 154 | __ push(c_rarg0); 155 | __ push(c_rarg1); 156 | __ push(c_rarg2); 157 | __ push(rax); 158 | 159 | __ load_parameter(0, c_rarg0); 160 | __ load_parameter(1, c_rarg1); 161 | __ load_parameter(2, c_rarg2); 162 | 163 | __ bind(runtime); 164 | 165 | __ save_live_registers_no_oop_map(true); 166 | 167 | #if MMTK_ENABLE_BARRIER_FASTPATH 168 | __ call_VM_leaf_base(FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_slow_call), 3); 169 | #else 170 | __ call_VM_leaf_base(FN_ADDR(MMTkBarrierSetRuntime::object_reference_write_post_call), 3); 171 | #endif 172 | 173 | __ restore_live_registers(true); 174 | 175 | __ bind(done); 176 | __ pop(rax); 177 | __ pop(c_rarg2); 178 | __ pop(c_rarg1); 179 | __ pop(c_rarg0); 180 | 181 | __ epilogue(); 182 | } 183 | 184 | #undef __ 185 | 186 | #define __ ce->masm()-> 187 | 188 | void MMTkBarrierSetAssembler::generate_c1_write_barrier_stub_call(LIR_Assembler* ce, MMTkC1BarrierStub* stub) { 189 | MMTkBarrierSetC1* bs = (MMTkBarrierSetC1*) BarrierSet::barrier_set()->barrier_set_c1(); 190 | __ bind(*stub->entry()); 191 | ce->store_parameter(stub->src->as_pointer_register(), 0); 192 | ce->store_parameter(stub->slot->as_pointer_register(), 1); 193 | ce->store_parameter(stub->new_val->as_pointer_register(), 2); 194 | __ call(RuntimeAddress(bs->_write_barrier_c1_runtime_code_blob->code_begin())); 195 | __ jmp(*stub->continuation()); 196 | } 197 | 198 | #undef __ 199 | -------------------------------------------------------------------------------- /openjdk/mmtkBarrierSetAssembler_x86.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_MMTK_BARRIER_SET_ASSEMBLER_X86_HPP 2 | #define MMTK_OPENJDK_MMTK_BARRIER_SET_ASSEMBLER_X86_HPP 3 | 4 | #include "asm/macroAssembler.hpp" 5 | #include "gc/shared/barrierSetAssembler.hpp" 6 | 7 | class MMTkBarrierSetC1; 8 | class MMTkC1BarrierStub; 9 | class LIR_Assembler; 10 | class StubAssembler; 11 | 12 | class MMTkBarrierSetAssembler: public BarrierSetAssembler { 13 | friend class MMTkBarrierSetC1; 14 | 15 | protected: 16 | /// Full pre-barrier 17 | virtual void object_reference_write_pre(MacroAssembler* masm, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2) const {} 18 | /// Full post-barrier 19 | /// `compensate_val_reg` is true if this function is called after `BarrierSetAssembler::store_at` which compresses the pointer in the `val` register in place. 20 | virtual void object_reference_write_post(MacroAssembler* masm, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, bool compensate_val_reg) const {} 21 | 22 | /// Barrier elision test 23 | virtual bool can_remove_barrier(DecoratorSet decorators, Register val, bool skip_const_null) const { 24 | bool in_heap = (decorators & IN_HEAP) != 0; 25 | bool as_normal = (decorators & AS_NORMAL) != 0; 26 | assert((decorators & IS_DEST_UNINITIALIZED) == 0, "unsupported"); 27 | return !in_heap || (skip_const_null && val == noreg); 28 | } 29 | 30 | /// Generate C1 write barrier slow-call assembly code 31 | virtual void generate_c1_write_barrier_runtime_stub(StubAssembler* sasm) const; 32 | 33 | public: 34 | virtual void eden_allocate(MacroAssembler* masm, Register thread, Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Label& slow_case) override; 35 | virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2) override { 36 | if (type == T_OBJECT || type == T_ARRAY) object_reference_write_pre(masm, decorators, dst, val, tmp1, tmp2); 37 | BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); 38 | // BarrierSetAssembler::store_at modifies val and make it compressed if UseCompressedOops is true. 39 | // We need to compensate for this change and decode it in object_reference_write_post. 40 | if (type == T_OBJECT || type == T_ARRAY) object_reference_write_post(masm, decorators, dst, val, tmp1, tmp2, true); 41 | } 42 | 43 | /// Generate C1 write barrier slow-call stub 44 | static void generate_c1_write_barrier_stub_call(LIR_Assembler* ce, MMTkC1BarrierStub* stub); 45 | }; 46 | #endif // MMTK_OPENJDK_MMTK_BARRIER_SET_ASSEMBLER_X86_HPP 47 | -------------------------------------------------------------------------------- /openjdk/mmtkBarrierSetC1.cpp: -------------------------------------------------------------------------------- 1 | #include "c1/c1_CodeStubs.hpp" 2 | #include "gc/shared/c1/barrierSetC1.hpp" 3 | #include "mmtkBarrierSetAssembler_x86.hpp" 4 | #include "mmtkBarrierSetC1.hpp" 5 | 6 | void MMTkBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) { 7 | class MMTkBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { 8 | virtual OopMapSet* generate_code(StubAssembler* sasm) override { 9 | MMTkBarrierSetAssembler* bs = (MMTkBarrierSetAssembler*) BarrierSet::barrier_set()->barrier_set_assembler(); 10 | bs->generate_c1_write_barrier_runtime_stub(sasm); 11 | return NULL; 12 | } 13 | }; 14 | MMTkBarrierCodeGenClosure write_code_gen_cl; 15 | _write_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1, "write_code_gen_cl", false, &write_code_gen_cl); 16 | } 17 | 18 | void MMTkC1BarrierStub::emit_code(LIR_Assembler* ce) { 19 | MMTkBarrierSetAssembler* bs = (MMTkBarrierSetAssembler*) BarrierSet::barrier_set()->barrier_set_assembler(); 20 | bs->generate_c1_write_barrier_stub_call(ce, this); 21 | } 22 | -------------------------------------------------------------------------------- /openjdk/mmtkBarrierSetC1.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_MMTK_BARRIER_SET_C1_HPP 2 | #define MMTK_OPENJDK_MMTK_BARRIER_SET_C1_HPP 3 | 4 | #include "c1/c1_CodeStubs.hpp" 5 | #include "gc/shared/c1/barrierSetC1.hpp" 6 | 7 | class MMTkBarrierSetAssembler; 8 | 9 | class MMTkBarrierSetC1 : public BarrierSetC1 { 10 | friend class MMTkBarrierSetAssembler; 11 | 12 | protected: 13 | CodeBlob* _write_barrier_c1_runtime_code_blob; 14 | 15 | /// Full pre-barrier 16 | virtual void object_reference_write_pre(LIRAccess& access, LIR_Opr src, LIR_Opr slot, LIR_Opr new_val) const {} 17 | /// Full post-barrier 18 | virtual void object_reference_write_post(LIRAccess& access, LIR_Opr src, LIR_Opr slot, LIR_Opr new_val) const {} 19 | 20 | /// Substituting write barrier 21 | virtual void store_at_resolved(LIRAccess& access, LIR_Opr value) override { 22 | if (access.is_oop()) object_reference_write_pre(access, access.base().opr(), access.resolved_addr(), value); 23 | BarrierSetC1::store_at_resolved(access, value); 24 | if (access.is_oop()) object_reference_write_post(access, access.base().opr(), access.resolved_addr(), value); 25 | } 26 | 27 | /// Substituting write barrier (cmpxchg) 28 | virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) override { 29 | if (access.is_oop()) object_reference_write_pre(access, access.base().opr(), access.resolved_addr(), new_value.result()); 30 | LIR_Opr result = BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value); 31 | if (access.is_oop()) object_reference_write_post(access, access.base().opr(), access.resolved_addr(), new_value.result()); 32 | return result; 33 | } 34 | 35 | /// Substituting write barrier (xchg) 36 | virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) override { 37 | if (access.is_oop()) object_reference_write_pre(access, access.base().opr(), access.resolved_addr(), value.result()); 38 | LIR_Opr result = BarrierSetC1::atomic_xchg_at_resolved(access, value); 39 | if (access.is_oop()) object_reference_write_post(access, access.base().opr(), access.resolved_addr(), value.result()); 40 | return result; 41 | } 42 | 43 | virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register) override { 44 | return BarrierSetC1::resolve_address(access, resolve_in_register); 45 | } 46 | 47 | /// Helper function for C1 barrier implementations to resolve address in registers 48 | LIR_Opr resolve_address_in_register(LIRAccess& access, bool resolve_in_register) { 49 | DecoratorSet decorators = access.decorators(); 50 | bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; 51 | bool is_write = (decorators & C1_WRITE_ACCESS) != 0; 52 | bool is_array = (decorators & IS_ARRAY) != 0; 53 | bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; 54 | bool precise = is_array || on_anonymous; 55 | resolve_in_register |= !needs_patching && is_write && access.is_oop() && precise; 56 | return BarrierSetC1::resolve_address(access, resolve_in_register); 57 | } 58 | 59 | public: 60 | 61 | MMTkBarrierSetC1() {} 62 | 63 | /// Generate C1 write barrier slow-call C1-LIR code 64 | virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob) override; 65 | }; 66 | 67 | /// C1 write barrier slow-call stub. 68 | /// The default behaviour is to call `MMTkBarrierSetRuntime::object_reference_write_post_call` and pass all the three args. 69 | /// Barrier implementations may inherit from this class, and override `emit_code` to perform a specialized slow-path call. 70 | struct MMTkC1BarrierStub: CodeStub { 71 | LIR_Opr src, slot, new_val; 72 | 73 | MMTkC1BarrierStub(LIR_Opr src, LIR_Opr slot, LIR_Opr new_val): src(src), slot(slot), new_val(new_val) {} 74 | 75 | virtual void emit_code(LIR_Assembler* ce) override; 76 | 77 | virtual void visit(LIR_OpVisitState* visitor) override { 78 | visitor->do_slow_case(); 79 | if (src != NULL) visitor->do_input(src); 80 | if (slot != NULL) visitor->do_input(slot); 81 | if (new_val != NULL) visitor->do_input(new_val); 82 | } 83 | 84 | NOT_PRODUCT(virtual void print_name(outputStream* out) const { out->print("MMTkC1BarrierStub"); }); 85 | }; 86 | 87 | #endif // MMTK_OPENJDK_MMTK_BARRIER_SET_C1_HPP 88 | -------------------------------------------------------------------------------- /openjdk/mmtkBarrierSetC2.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_BARRIER_SET_C2_HPP 26 | #define MMTK_OPENJDK_MMTK_BARRIER_SET_C2_HPP 27 | 28 | #include "gc/shared/c2/barrierSetC2.hpp" 29 | #include "opto/addnode.hpp" 30 | #include "opto/arraycopynode.hpp" 31 | #include "opto/callnode.hpp" 32 | #include "opto/compile.hpp" 33 | #include "opto/convertnode.hpp" 34 | #include "opto/graphKit.hpp" 35 | #include "opto/idealKit.hpp" 36 | #include "opto/macro.hpp" 37 | #include "opto/narrowptrnode.hpp" 38 | #include "opto/node.hpp" 39 | #include "opto/type.hpp" 40 | 41 | class TypeOopPtr; 42 | class PhaseMacroExpand; 43 | class AllocateNode; 44 | class Node; 45 | class TypeFunc; 46 | 47 | class MMTkBarrierSetC2: public BarrierSetC2 { 48 | protected: 49 | /// Barrier elision test 50 | virtual bool can_remove_barrier(GraphKit* kit, PhaseTransform* phase, Node* src, Node* slot, Node* val, bool skip_const_null) const; 51 | /// Full pre-barrier 52 | virtual void object_reference_write_pre(GraphKit* kit, Node* src, Node* slot, Node* val) const {} 53 | /// Full post-barrier 54 | virtual void object_reference_write_post(GraphKit* kit, Node* src, Node* slot, Node* val) const {} 55 | 56 | virtual Node* store_at_resolved(C2Access& access, C2AccessValue& val) const { 57 | if (access.is_oop()) object_reference_write_pre(access.kit(), access.base(), access.addr().node(), val.node()); 58 | Node* store = BarrierSetC2::store_at_resolved(access, val); 59 | if (access.is_oop()) object_reference_write_post(access.kit(), access.base(), access.addr().node(), val.node()); 60 | return store; 61 | } 62 | virtual Node* atomic_cmpxchg_val_at_resolved(C2AtomicAccess& access, Node* expected_val, Node* new_val, const Type* value_type) const { 63 | if (access.is_oop()) object_reference_write_pre(access.kit(), access.base(), access.addr().node(), new_val); 64 | Node* result = BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); 65 | if (access.is_oop()) object_reference_write_post(access.kit(), access.base(), access.addr().node(), new_val); 66 | return result; 67 | } 68 | virtual Node* atomic_cmpxchg_bool_at_resolved(C2AtomicAccess& access, Node* expected_val, Node* new_val, const Type* value_type) const { 69 | if (access.is_oop()) object_reference_write_pre(access.kit(), access.base(), access.addr().node(), new_val); 70 | Node* load_store = BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); 71 | if (access.is_oop()) object_reference_write_post(access.kit(), access.base(), access.addr().node(), new_val); 72 | return load_store; 73 | } 74 | virtual Node* atomic_xchg_at_resolved(C2AtomicAccess& access, Node* new_val, const Type* value_type) const { 75 | if (access.is_oop()) object_reference_write_pre(access.kit(), access.base(), access.addr().node(), new_val); 76 | Node* result = BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type); 77 | if (access.is_oop()) object_reference_write_post(access.kit(), access.base(), access.addr().node(), new_val); 78 | return result; 79 | } 80 | 81 | public: 82 | virtual void clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const { 83 | BarrierSetC2::clone(kit, src, dst, size, is_array); 84 | } 85 | virtual bool array_copy_requires_gc_barriers(BasicType type) const { 86 | return true; 87 | } 88 | virtual bool is_gc_barrier_node(Node* node) const { 89 | if (node->Opcode() != Op_CallLeaf) return false; 90 | CallLeafNode *call = node->as_CallLeaf(); 91 | return call->_name != NULL && strcmp(call->_name, "mmtk_barrier_call") == 0; 92 | } 93 | static void expand_allocate(PhaseMacroExpand* x, 94 | AllocateNode* alloc, // allocation node to be expanded 95 | Node* length, // array length for an array allocation 96 | const TypeFunc* slow_call_type, // Type of slow call 97 | address slow_call_address); // Address of slow call 98 | }; 99 | 100 | class MMTkIdealKit: public IdealKit { 101 | inline void build_type_func_helper(const Type** fields) {} 102 | 103 | template 104 | inline void build_type_func_helper(const Type** fields, T t, Types... ts) { 105 | fields[0] = t; 106 | build_type_func_helper(fields + 1, ts...); 107 | } 108 | public: 109 | using IdealKit::IdealKit; 110 | inline Node* LShiftX(Node* l, Node* r) { return transform(new LShiftXNode(l, r)); } 111 | inline Node* AndX(Node* l, Node* r) { return transform(new AndXNode(l, r)); } 112 | inline Node* ConvL2I(Node* x) { return transform(new ConvL2INode(x)); } 113 | inline Node* CastXP(Node* x) { return transform(new CastX2PNode(x)); } 114 | inline Node* URShiftI(Node* l, Node* r) { return transform(new URShiftINode(l, r)); } 115 | inline Node* ConP(intptr_t ptr) { return makecon(TypeRawPtr::make((address) ptr)); } 116 | 117 | template 118 | inline const TypeFunc* func_type(Types... types) { 119 | const int num_types = sizeof...(types); 120 | const Type** fields = TypeTuple::fields(num_types); 121 | build_type_func_helper(fields + TypeFunc::Parms, types...); 122 | const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+num_types, fields); 123 | fields = TypeTuple::fields(0); 124 | const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields); 125 | return TypeFunc::make(domain, range); 126 | } 127 | }; 128 | 129 | #endif // MMTK_OPENJDK_MMTK_BARRIER_SET_C2_HPP 130 | -------------------------------------------------------------------------------- /openjdk/mmtkCollectorPolicy.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_MMTK_COLLECTOR_POLICY_HPP 2 | #define MMTK_OPENJDK_MMTK_COLLECTOR_POLICY_HPP 3 | 4 | class MMTkCollectorPolicy : public CollectorPolicy { 5 | protected: 6 | virtual void initialize_alignments() { 7 | _space_alignment = 1 << 19; 8 | _heap_alignment = _space_alignment; 9 | } 10 | public: 11 | MMTkCollectorPolicy() {} 12 | }; 13 | #endif // MMTK_OPENJDK_MMTK_COLLECTOR_POLICY_HPP 14 | -------------------------------------------------------------------------------- /openjdk/mmtkCollectorThread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "mmtk.h" 27 | #include "mmtkCollectorThread.hpp" 28 | 29 | MMTkCollectorThread::MMTkCollectorThread(void* context): NamedThread() { 30 | third_party_heap_collector = context; 31 | set_name("MMTk Collector Thread"); 32 | } 33 | 34 | void MMTkCollectorThread::run() { 35 | this->initialize_named_thread(); 36 | start_worker((void*) this, third_party_heap_collector); 37 | } 38 | -------------------------------------------------------------------------------- /openjdk/mmtkCollectorThread.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_COLLECTOR_THREAD_HPP 26 | #define MMTK_OPENJDK_MMTK_COLLECTOR_THREAD_HPP 27 | 28 | #include "runtime/perfData.hpp" 29 | #include "runtime/thread.hpp" 30 | 31 | class MMTkCollectorThread: public NamedThread { 32 | void* _context; 33 | public: 34 | // Constructor 35 | MMTkCollectorThread(void* _context); 36 | 37 | // No destruction allowed 38 | ~MMTkCollectorThread() { 39 | guarantee(false, "MMTkCollectorThread deletion must fix the race with VM termination"); 40 | } 41 | 42 | inline void* get_context() { 43 | return third_party_heap_collector; 44 | } 45 | 46 | // Entry for starting vm thread 47 | virtual void run(); 48 | }; 49 | 50 | #endif // MMTK_OPENJDK_MMTK_COLLECTOR_THREAD_HPP 51 | -------------------------------------------------------------------------------- /openjdk/mmtkFinalizerThread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "classfile/stringTable.hpp" 27 | #include "classfile/symbolTable.hpp" 28 | #include "mmtk.h" 29 | #include "mmtkFinalizerThread.hpp" 30 | #include "oops/oop.inline.hpp" 31 | #include "prims/jvmtiImpl.hpp" 32 | #include "runtime/interfaceSupport.inline.hpp" 33 | #include "runtime/javaCalls.hpp" 34 | #include "runtime/mutex.hpp" 35 | #include "runtime/mutexLocker.hpp" 36 | #include "runtime/os.hpp" 37 | #include "runtime/serviceThread.hpp" 38 | #include "services/diagnosticArgument.hpp" 39 | #include "services/diagnosticFramework.hpp" 40 | #include "services/gcNotifier.hpp" 41 | #include "services/lowMemoryDetector.hpp" 42 | 43 | MMTkFinalizerThread* MMTkFinalizerThread::instance = NULL; 44 | 45 | void MMTkFinalizerThread::initialize() { 46 | EXCEPTION_MARK; 47 | 48 | HandleMark hm; 49 | 50 | const char* name = "MMTk Finalizer Thread"; 51 | Handle string = java_lang_String::create_from_str(name, CHECK); 52 | 53 | // Initialize thread_oop to put it into the system threadGroup 54 | Handle thread_group (THREAD, Universe::system_thread_group()); 55 | Handle thread_oop = JavaCalls::construct_new_instance(SystemDictionary::Thread_klass(), 56 | vmSymbols::threadgroup_string_void_signature(), 57 | thread_group, 58 | string, 59 | CHECK); 60 | 61 | { 62 | MutexLocker mu(Threads_lock); 63 | MMTkFinalizerThread* thread = new MMTkFinalizerThread(&finalizer_thread_entry); 64 | 65 | // At this point it may be possible that no osthread was created for the 66 | // JavaThread due to lack of memory. We would have to throw an exception 67 | // in that case. However, since this must work and we do not allow 68 | // exceptions anyway, check and abort if this fails. 69 | if (thread == NULL || thread->osthread() == NULL) { 70 | vm_exit_during_initialization("java.lang.OutOfMemoryError", 71 | os::native_thread_creation_failed_msg()); 72 | } 73 | 74 | java_lang_Thread::set_thread(thread_oop(), thread); 75 | java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); 76 | java_lang_Thread::set_daemon(thread_oop()); 77 | thread->set_threadObj(thread_oop()); 78 | instance = thread; 79 | 80 | Threads::add(thread); 81 | Thread::start(thread); 82 | } 83 | } 84 | 85 | void MMTkFinalizerThread::finalizer_thread_entry(JavaThread* thread, TRAPS) { 86 | MMTkFinalizerThread* this_thread = MMTkFinalizerThread::instance; 87 | while (true) { 88 | // Wait until scheduled 89 | { 90 | ThreadBlockInVM tbivm(thread); 91 | MutexLockerEx mu(this_thread->m, Mutex::_no_safepoint_check_flag); 92 | while (!this_thread->is_scheduled) { 93 | this_thread->m->wait(Mutex::_no_safepoint_check_flag); 94 | } 95 | this_thread->is_scheduled = false; // Consume this request so we can accept the next. 96 | } 97 | 98 | // finalize objects 99 | while (true) { 100 | void* obj_ref = get_finalized_object(); 101 | if (obj_ref != NULL) { 102 | instanceOop obj = (instanceOop) obj_ref; 103 | 104 | // Invoke finalize() 105 | { 106 | HandleMark hm; 107 | JavaValue ret(T_VOID); 108 | instanceHandle handle_obj(this_thread, obj); 109 | TempNewSymbol finalize_method = SymbolTable::new_symbol("finalize", this_thread); 110 | Symbol* sig = vmSymbols::void_method_signature(); 111 | 112 | JavaCalls::call_virtual(&ret, handle_obj, obj->klass(), finalize_method, sig, this_thread); 113 | } 114 | } else { 115 | break; 116 | } 117 | } 118 | } 119 | } 120 | 121 | MMTkFinalizerThread::MMTkFinalizerThread(ThreadFunction entry_point) : JavaThread(entry_point) { 122 | this->is_scheduled = false; 123 | this->m = new Monitor(Mutex::suspend_resume, "mmtk-finalizer-monitor", true, Monitor::_safepoint_check_never); 124 | } 125 | 126 | void MMTkFinalizerThread::schedule() { 127 | assert(!Thread::current()->is_Java_thread(), "Supposed to be called by GC thread. Actually called by JavaThread."); 128 | MutexLockerEx mu(this->m, Mutex::_no_safepoint_check_flag); 129 | if (!this->is_scheduled) { 130 | this->is_scheduled = true; 131 | this->m->notify(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /openjdk/mmtkFinalizerThread.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_FINALIZER_THREAD_HPP 26 | #define MMTK_OPENJDK_MMTK_FINALIZER_THREAD_HPP 27 | 28 | #include "runtime/mutex.hpp" 29 | #include "runtime/perfData.hpp" 30 | #include "runtime/thread.hpp" 31 | 32 | // This mimics the example of hotspot/share/runtime/ServiceThread.hpp 33 | 34 | class MMTkFinalizerThread: public JavaThread { 35 | private: 36 | // Constructor 37 | MMTkFinalizerThread(ThreadFunction entry_point); 38 | 39 | // No destruction allowed 40 | ~MMTkFinalizerThread() { 41 | guarantee(false, "VMThread deletion must fix the race with VM termination"); 42 | } 43 | public: 44 | bool is_scheduled; 45 | Monitor* m; 46 | static MMTkFinalizerThread* instance; 47 | static void initialize(); 48 | static void finalizer_thread_entry(JavaThread* thread, TRAPS); 49 | 50 | void schedule(); 51 | }; 52 | 53 | #endif // MMTK_OPENJDK_MMTK_FINALIZER_THREAD_HPP 54 | -------------------------------------------------------------------------------- /openjdk/mmtkHeap.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_HEAP_HPP 26 | #define MMTK_OPENJDK_MMTK_HEAP_HPP 27 | 28 | #include "mmtkBarrierSet.hpp" 29 | #include "gc/shared/collectedHeap.hpp" 30 | #include "gc/shared/collectorPolicy.hpp" 31 | #include "gc/shared/gcPolicyCounters.hpp" 32 | #include "gc/shared/gcWhen.hpp" 33 | #include "gc/shared/oopStorage.hpp" 34 | #include "gc/shared/oopStorageParState.hpp" 35 | #include "gc/shared/strongRootsScope.hpp" 36 | #include "gc/shared/workgroup.hpp" 37 | #include "memory/iterator.hpp" 38 | #include "memory/metaspace.hpp" 39 | #include "mmtkCollectorPolicy.hpp" 40 | #include "mmtkFinalizerThread.hpp" 41 | #include "mmtkMemoryPool.hpp" 42 | #include "utilities/growableArray.hpp" 43 | #include "utilities/ostream.hpp" 44 | 45 | class GCMemoryManager; 46 | class MemoryPool; 47 | //class mmtkGCTaskManager; 48 | class MMTkVMCompanionThread; 49 | class MMTkHeap : public CollectedHeap { 50 | MMTkCollectorPolicy* _collector_policy; 51 | SoftRefPolicy _soft_ref_policy; 52 | MMTkMemoryPool* _mmtk_pool; 53 | GCMemoryManager* _mmtk_manager; 54 | HeapWord* _start; 55 | HeapWord* _end; 56 | static MMTkHeap* _heap; 57 | size_t _n_workers; 58 | Monitor* _gc_lock; 59 | ContiguousSpace* _space; 60 | int _num_root_scan_tasks; 61 | MMTkVMCompanionThread* _companion_thread; 62 | public: 63 | 64 | MMTkHeap(MMTkCollectorPolicy* policy); 65 | 66 | void schedule_finalizer(); 67 | 68 | inline static MMTkHeap* heap() { 69 | return _heap; 70 | } 71 | 72 | static HeapWord* allocate_from_tlab(Klass* klass, Thread* thread, size_t size); 73 | 74 | jint initialize(); 75 | void enable_collection(); 76 | 77 | virtual HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded); 78 | HeapWord* mem_allocate_nonmove(size_t size, bool* gc_overhead_limit_was_exceeded); 79 | 80 | MMTkVMCompanionThread* companion_thread() const { 81 | return _companion_thread; 82 | } 83 | 84 | 85 | Name kind() const { 86 | return CollectedHeap::ThirdPartyHeap; 87 | } 88 | const char* name() const { 89 | return "MMTk"; 90 | } 91 | static const char* version(); 92 | 93 | size_t capacity() const; 94 | size_t used() const; 95 | 96 | bool is_maximal_no_gc() const; 97 | 98 | size_t max_capacity() const; 99 | bool is_in(const void* p) const; 100 | bool is_in_reserved(const void* p) const; 101 | bool supports_tlab_allocation() const; 102 | 103 | bool supports_inline_contig_alloc() const { 104 | return MMTK_ENABLE_ALLOCATION_FASTPATH; 105 | } 106 | 107 | // The amount of space available for thread-local allocation buffers. 108 | size_t tlab_capacity(Thread *thr) const; 109 | 110 | // The amount of used space for thread-local allocation buffers for the given thread. 111 | size_t tlab_used(Thread *thr) const; 112 | 113 | void new_collector_thread() { 114 | _n_workers += 1; 115 | } 116 | 117 | Monitor* gc_lock() { 118 | return _gc_lock; 119 | } 120 | 121 | bool can_elide_tlab_store_barriers() const; 122 | 123 | 124 | bool can_elide_initializing_store_barrier(oop new_obj); 125 | 126 | // mark to be thus strictly sequenced after the stores. 127 | bool card_mark_must_follow_store() const; 128 | 129 | void collect(GCCause::Cause cause); 130 | 131 | // Perform a full collection 132 | void do_full_collection(bool clear_all_soft_refs); 133 | 134 | 135 | // Return the CollectorPolicy for the heap 136 | CollectorPolicy* collector_policy() const ; 137 | 138 | SoftRefPolicy* soft_ref_policy(); 139 | 140 | GrowableArray memory_managers() ; 141 | GrowableArray memory_pools(); 142 | 143 | // Iterate over all objects, calling "cl.do_object" on each. 144 | void object_iterate(ObjectClosure* cl); 145 | 146 | // Similar to object_iterate() except iterates only 147 | // over live objects. 148 | void safe_object_iterate(ObjectClosure* cl) ; 149 | 150 | HeapWord* block_start(const void* addr) const ; 151 | 152 | size_t block_size(const HeapWord* addr) const ; 153 | 154 | bool block_is_obj(const HeapWord* addr) const; 155 | 156 | jlong millis_since_last_gc() ; 157 | 158 | void prepare_for_verify() ; 159 | 160 | 161 | private: 162 | 163 | void initialize_serviceability() ; 164 | 165 | void set_mmtk_options(bool set_defaults); 166 | 167 | public: 168 | 169 | // Print heap information on the given outputStream. 170 | void print_on(outputStream* st) const ; 171 | 172 | 173 | // Print all GC threads (other than the VM thread) 174 | // used by this heap. 175 | void print_gc_threads_on(outputStream* st) const; 176 | 177 | // Iterator for all GC threads (other than VM thread) 178 | void gc_threads_do(ThreadClosure* tc) const; 179 | 180 | // Print any relevant tracing info that flags imply. 181 | // Default implementation does nothing. 182 | void print_tracing_info() const ; 183 | 184 | 185 | // An object is scavengable if its location may move during a scavenge. 186 | // (A scavenge is a GC which is not a full GC.) 187 | inline bool is_scavengable(oop obj) { return true; } 188 | // Registering and unregistering an nmethod (compiled code) with the heap. 189 | // Override with specific mechanism for each specialized heap type. 190 | virtual void register_nmethod(nmethod* nm); 191 | virtual void unregister_nmethod(nmethod* nm); 192 | 193 | // Heap verification 194 | void verify(VerifyOption option); 195 | 196 | void post_initialize(); 197 | 198 | void scan_roots(OopClosure& cl); 199 | 200 | void scan_roots_in_all_mutator_threads(OopClosure& cl); 201 | 202 | void scan_universe_roots(OopClosure& cl); 203 | void scan_jni_handle_roots(OopClosure& cl); 204 | void scan_object_synchronizer_roots(OopClosure& cl); 205 | void scan_management_roots(OopClosure& cl); 206 | void scan_jvmti_export_roots(OopClosure& cl); 207 | void scan_aot_loader_roots(OopClosure& cl); 208 | void scan_system_dictionary_roots(OopClosure& cl); 209 | void scan_code_cache_roots(OopClosure& cl); 210 | void scan_string_table_roots(OopClosure& cl); 211 | void scan_class_loader_data_graph_roots(OopClosure& cl); 212 | void scan_weak_processor_roots(OopClosure& cl); 213 | void scan_vm_thread_roots(OopClosure& cl); 214 | 215 | jlong _last_gc_time; 216 | }; 217 | 218 | 219 | #endif // MMTK_OPENJDK_MMTK_HEAP_HPP 220 | -------------------------------------------------------------------------------- /openjdk/mmtkMemoryPool.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "mmtkMemoryPool.hpp" 27 | 28 | MMTkMemoryPool::MMTkMemoryPool(HeapWord* start, HeapWord* end, 29 | const char* name, size_t init_size, 30 | bool support_usage_threshold) : 31 | CollectedMemoryPool(name, init_size, 32 | pointer_delta(start, end)*HeapWordSize, support_usage_threshold), 33 | 34 | _start(start), _end(end), _used_in_bytes(0){ 35 | } 36 | 37 | MemoryUsage MMTkMemoryPool::get_memory_usage() { 38 | size_t maxSize = (available_for_allocation() ? max_size() : 0); 39 | size_t used = used_in_bytes(); 40 | size_t committed = pointer_delta(_start, _end)*HeapWordSize; 41 | 42 | return MemoryUsage(initial_size(), used, committed, maxSize); 43 | } 44 | -------------------------------------------------------------------------------- /openjdk/mmtkMemoryPool.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_MEMORY_POOL_HPP 26 | #define MMTK_OPENJDK_MMTK_MEMORY_POOL_HPP 27 | 28 | #include "services/memoryPool.hpp" 29 | #include "services/memoryUsage.hpp" 30 | 31 | class MMTkMemoryPool : public CollectedMemoryPool { 32 | private: 33 | HeapWord* _start; 34 | HeapWord* _end; 35 | size_t _used_in_bytes; 36 | 37 | public: 38 | MMTkMemoryPool(HeapWord* start, HeapWord* end, const char* name, size_t init_size, bool support_usage_threshold); 39 | 40 | MemoryUsage get_memory_usage(); 41 | size_t used_in_bytes() { return _used_in_bytes; } 42 | size_t max_size() const { return pointer_delta(_start, _end)*HeapWordSize; } 43 | }; 44 | 45 | 46 | #endif // MMTK_OPENJDK_MMTK_MEMORY_POOL_HPP 47 | -------------------------------------------------------------------------------- /openjdk/mmtkMutator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "precompiled.hpp" 3 | #include "mmtk.h" 4 | #include "mmtkMutator.hpp" 5 | 6 | size_t MMTkMutatorContext::max_non_los_default_alloc_bytes = 0; 7 | 8 | MMTkMutatorContext MMTkMutatorContext::bind(::Thread* current) { 9 | if (FREE_LIST_ALLOCATOR_SIZE != sizeof(FreeListAllocator)) { 10 | printf("ERROR: Unmatched free list allocator size: rs=%zu cpp=%zu\n", FREE_LIST_ALLOCATOR_SIZE, sizeof(FreeListAllocator)); 11 | guarantee(false, "ERROR"); 12 | } 13 | return *((MMTkMutatorContext*) ::bind_mutator((void*) current)); 14 | } 15 | 16 | bool MMTkMutatorContext::is_ready_to_bind() { 17 | return ::openjdk_is_gc_initialized(); 18 | } 19 | 20 | HeapWord* MMTkMutatorContext::alloc(size_t bytes, Allocator allocator) { 21 | // All allocations with size larger than max non-los bytes will get to this slowpath here. 22 | // We will use LOS for those. 23 | assert(MMTkMutatorContext::max_non_los_default_alloc_bytes != 0, "max_non_los_default_alloc_bytes hasn't been initialized"); 24 | if (bytes >= MMTkMutatorContext::max_non_los_default_alloc_bytes) { 25 | allocator = AllocatorLos; 26 | } 27 | 28 | // FIXME: Proper use of slow-path api 29 | HeapWord* o = (HeapWord*) ::alloc((MMTk_Mutator) this, bytes, HeapWordSize, 0, allocator); 30 | // Post allocation hooks. Note that we can get a nullptr from mmtk core in the case of OOM. 31 | // Hence, only call post allocation hooks if we have a proper object. 32 | if (o != nullptr) { 33 | ::post_alloc((MMTk_Mutator) this, o, bytes, allocator); 34 | } 35 | return o; 36 | } 37 | 38 | void MMTkMutatorContext::flush() { 39 | ::flush_mutator((MMTk_Mutator) this); 40 | } 41 | 42 | void MMTkMutatorContext::destroy() { 43 | ::destroy_mutator((MMTk_Mutator) this); 44 | } 45 | -------------------------------------------------------------------------------- /openjdk/mmtkMutator.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MMTK_OPENJDK_MMTK_MUTATOR_HPP 3 | #define MMTK_OPENJDK_MMTK_MUTATOR_HPP 4 | 5 | #include "mmtk.h" 6 | #include "utilities/globalDefinitions.hpp" 7 | 8 | enum Allocator { 9 | AllocatorDefault = 0, 10 | AllocatorImmortal = 1, 11 | AllocatorLos = 2, 12 | AllocatorCode = 3, 13 | AllocatorReadOnly = 4, 14 | }; 15 | 16 | struct RustDynPtr { 17 | void* data; 18 | void* vtable; 19 | }; 20 | 21 | // These constants should match the constants defind in mmtk::util::alloc::allocators 22 | const int MAX_BUMP_ALLOCATORS = 6; 23 | const int MAX_LARGE_OBJECT_ALLOCATORS = 2; 24 | const int MAX_MALLOC_ALLOCATORS = 1; 25 | const int MAX_IMMIX_ALLOCATORS = 2; 26 | const int MAX_FREE_LIST_ALLOCATORS = 2; 27 | const int MAX_MARK_COMPACT_ALLOCATORS = 1; 28 | 29 | // The following types should have the same layout as the types with the same name in MMTk core (Rust) 30 | 31 | struct BumpAllocator { 32 | void* tls; 33 | void* cursor; 34 | void* limit; 35 | RustDynPtr space; 36 | void* context; 37 | }; 38 | 39 | struct LargeObjectAllocator { 40 | void* tls; 41 | void* space; 42 | void* context; 43 | }; 44 | 45 | struct ImmixAllocator { 46 | void* tls; 47 | void* cursor; 48 | void* limit; 49 | void* immix_space; 50 | void* context; 51 | uint8_t hot; 52 | uint8_t copy; 53 | void* large_cursor; 54 | void* large_limit; 55 | uint8_t request_for_large; 56 | uint8_t _align[7]; 57 | uint8_t line_opt_tag; 58 | uintptr_t line_opt; 59 | }; 60 | 61 | struct FLBlock { 62 | void* Address; 63 | }; 64 | 65 | struct FLBlockList { 66 | FLBlock first; 67 | FLBlock last; 68 | size_t size; 69 | char lock; 70 | }; 71 | 72 | struct FreeListAllocator { 73 | void* tls; 74 | void* space; 75 | void* context; 76 | FLBlockList* available_blocks; 77 | FLBlockList* available_blocks_stress; 78 | FLBlockList* unswept_blocks; 79 | FLBlockList* consumed_blocks; 80 | }; 81 | 82 | struct MallocAllocator { 83 | void* tls; 84 | void* space; 85 | void* context; 86 | }; 87 | 88 | struct MarkCompactAllocator { 89 | struct BumpAllocator bump_allocator; 90 | }; 91 | 92 | struct Allocators { 93 | BumpAllocator bump_pointer[MAX_BUMP_ALLOCATORS]; 94 | LargeObjectAllocator large_object[MAX_LARGE_OBJECT_ALLOCATORS]; 95 | MallocAllocator malloc[MAX_MALLOC_ALLOCATORS]; 96 | ImmixAllocator immix[MAX_IMMIX_ALLOCATORS]; 97 | FreeListAllocator free_list[MAX_FREE_LIST_ALLOCATORS]; 98 | MarkCompactAllocator markcompact[MAX_MARK_COMPACT_ALLOCATORS]; 99 | }; 100 | 101 | struct MutatorConfig { 102 | void* allocator_mapping; 103 | void* space_mapping; 104 | RustDynPtr prepare_func; 105 | RustDynPtr release_func; 106 | }; 107 | 108 | struct MMTkMutatorContext { 109 | Allocators allocators; 110 | RustDynPtr barrier; 111 | void* mutator_tls; 112 | RustDynPtr plan; 113 | MutatorConfig config; 114 | 115 | HeapWord* alloc(size_t bytes, Allocator allocator = AllocatorDefault); 116 | 117 | void flush(); 118 | void destroy(); 119 | 120 | static MMTkMutatorContext bind(::Thread* current); 121 | static bool is_ready_to_bind(); 122 | 123 | // Max object size that does not need to go into LOS. We get the value from mmtk-core, and cache its value here. 124 | static size_t max_non_los_default_alloc_bytes; 125 | }; 126 | #endif // MMTK_OPENJDK_MMTK_MUTATOR_HPP 127 | -------------------------------------------------------------------------------- /openjdk/mmtkRootsClosure.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_MMTK_ROOTS_CLOSURE_HPP 2 | #define MMTK_OPENJDK_MMTK_ROOTS_CLOSURE_HPP 3 | 4 | #include "memory/iterator.hpp" 5 | #include "mmtk.h" 6 | #include "oops/oop.hpp" 7 | #include "oops/oop.inline.hpp" 8 | #include "utilities/globalDefinitions.hpp" 9 | 10 | class MMTkRootsClosure : public OopClosure { 11 | SlotsClosure _slots_closure; 12 | void** _buffer; 13 | size_t _cap; 14 | size_t _cursor; 15 | 16 | template 17 | void do_oop_work(T* p, bool narrow) { 18 | T heap_oop = RawAccess<>::oop_load(p); 19 | if (!CompressedOops::is_null(heap_oop)) { 20 | if (UseCompressedOops && !narrow) { 21 | guarantee((uintptr_t(p) & (1ull << 63)) == 0, "test"); 22 | p = (T*) (uintptr_t(p) | (1ull << 63)); 23 | } 24 | _buffer[_cursor++] = (void*) p; 25 | if (_cursor >= _cap) { 26 | flush(); 27 | } 28 | } 29 | } 30 | 31 | void flush() { 32 | if (_cursor > 0) { 33 | NewBuffer buf = _slots_closure.invoke(_buffer, _cursor, _cap); 34 | _buffer = buf.buf; 35 | _cap = buf.cap; 36 | _cursor = 0; 37 | } 38 | } 39 | 40 | public: 41 | MMTkRootsClosure(SlotsClosure slots_closure): _slots_closure(slots_closure), _cursor(0) { 42 | NewBuffer buf = slots_closure.invoke(NULL, 0, 0); 43 | _buffer = buf.buf; 44 | _cap = buf.cap; 45 | } 46 | 47 | ~MMTkRootsClosure() { 48 | if (_cursor > 0) flush(); 49 | if (_buffer != NULL) { 50 | release_buffer(_buffer, _cursor, _cap); 51 | } 52 | } 53 | 54 | virtual void do_oop(oop* p) { do_oop_work(p, false); } 55 | virtual void do_oop(narrowOop* p) { do_oop_work(p, true); } 56 | }; 57 | 58 | class MMTkScanObjectClosure : public BasicOopIterateClosure { 59 | void* _trace; 60 | CLDToOopClosure follow_cld_closure; 61 | 62 | template 63 | void do_oop_work(T* p, bool narrow) { 64 | if (UseCompressedOops && !narrow) { 65 | guarantee((uintptr_t(p) & (1ull << 63)) == 0, "test"); 66 | p = (T*) (uintptr_t(p) | (1ull << 63)); 67 | } 68 | } 69 | 70 | public: 71 | MMTkScanObjectClosure(void* trace): _trace(trace), follow_cld_closure(this, false) {} 72 | 73 | virtual void do_oop(oop* p) { do_oop_work(p, false); } 74 | virtual void do_oop(narrowOop* p) { do_oop_work(p, true); } 75 | 76 | virtual bool do_metadata() { 77 | return true; 78 | } 79 | 80 | virtual void do_klass(Klass* k) { 81 | // follow_cld_closure.do_cld(k->class_loader_data()); 82 | // oop op = k->klass_holder(); 83 | // oop new_op = (oop) trace_root_object(_trace, op); 84 | // guarantee(new_op == op, "trace_root_object returned a different value %p -> %p", op, new_op); 85 | } 86 | 87 | virtual void do_cld(ClassLoaderData* cld) { 88 | follow_cld_closure.do_cld(cld); 89 | } 90 | 91 | virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } 92 | virtual bool idempotent() { return true; } 93 | }; 94 | 95 | // class MMTkCLDClosure : public CLDClosure { 96 | // public: 97 | // virtual void do_cld(ClassLoaderData* cld) { 98 | 99 | // printf("CLD: %p", p); 100 | // } 101 | // }; 102 | 103 | #endif // MMTK_OPENJDK_MMTK_ROOTS_CLOSURE_HPP 104 | -------------------------------------------------------------------------------- /openjdk/mmtkUpcalls.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Sun 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_UPCALLS_HPP 26 | #define MMTK_OPENJDK_MMTK_UPCALLS_HPP 27 | 28 | #include "mmtk.h" 29 | 30 | extern OpenJDK_Upcalls mmtk_upcalls; 31 | 32 | #endif // MMTK_OPENJDK_MMTK_UPCALLS_HPP 33 | 34 | -------------------------------------------------------------------------------- /openjdk/mmtkVMCompanionThread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "mmtk.h" 27 | #include "mmtkVMCompanionThread.hpp" 28 | #include "runtime/mutex.hpp" 29 | #include "logging/log.hpp" 30 | 31 | MMTkVMCompanionThread::MMTkVMCompanionThread(): 32 | NamedThread(), 33 | _desired_state(_threads_resumed), 34 | _reached_state(_threads_resumed) { 35 | set_name("MMTK VM Companion Thread"); 36 | _lock = new Monitor(Monitor::nonleaf, 37 | "MMTkVMCompanionThread::_lock", 38 | true, 39 | Monitor::_safepoint_check_never); 40 | } 41 | 42 | MMTkVMCompanionThread::~MMTkVMCompanionThread() { 43 | guarantee(false, "MMTkVMCompanionThread deletion must fix the race with VM termination"); 44 | } 45 | 46 | void MMTkVMCompanionThread::run() { 47 | this->initialize_named_thread(); 48 | 49 | for (;;) { 50 | // Wait for suspend request 51 | log_trace(gc)("MMTkVMCompanionThread: Waiting for suspend request..."); 52 | { 53 | MutexLockerEx locker(_lock, Mutex::_no_safepoint_check_flag); 54 | assert(_reached_state == _threads_resumed, "Threads should be running at this moment."); 55 | while (_desired_state != _threads_suspended) { 56 | _lock->wait(Mutex::_no_safepoint_check_flag); 57 | } 58 | assert(_reached_state == _threads_resumed, "Threads should still be running at this moment."); 59 | } 60 | 61 | // Let the VM thread stop the world. 62 | log_trace(gc)("MMTkVMCompanionThread: Letting VMThread execute VM op..."); 63 | VM_MMTkSTWOperation op(this); 64 | // VMThread::execute() is blocking. The companion thread will be blocked 65 | // here waiting for the VM thread to execute op, and the VM thread will 66 | // be blocked in do_mmtk_stw_operation() until a GC thread 67 | // calls request(_threads_resumed). 68 | VMThread::execute(&op); 69 | } 70 | } 71 | 72 | // Request stop-the-world or start-the-world. This method is supposed to be 73 | // called by a GC thread. 74 | // 75 | // If wait_until_reached is true, the caller will block until all Java threads 76 | // have stopped, or until they have been waken up. 77 | // 78 | // If wait_until_reached is false, the caller will return immediately, while 79 | // the companion thread will ask the VM thread to perform the state transition 80 | // in the background. The caller may call the wait_for_reached method to block 81 | // until the desired state is reached. 82 | void MMTkVMCompanionThread::request(stw_state desired_state, bool wait_until_reached) { 83 | assert(!Thread::current()->is_VM_thread(), "Requests can only be made by GC threads. Found VM thread."); 84 | assert(Thread::current() != this, "Requests can only be made by GC threads. Found companion thread."); 85 | assert(!Thread::current()->is_Java_thread(), "Requests can only be made by GC threads. Found Java thread."); 86 | 87 | MutexLockerEx locker(_lock, Mutex::_no_safepoint_check_flag); 88 | assert(_desired_state != desired_state, "State %d already requested.", desired_state); 89 | _desired_state = desired_state; 90 | _lock->notify_all(); 91 | 92 | if (wait_until_reached) { 93 | while (_reached_state != desired_state) { 94 | _lock->wait(Mutex::_no_safepoint_check_flag); 95 | } 96 | } 97 | } 98 | 99 | // Wait until the desired state is reached. Usually called after calling the 100 | // request method. Supposed to be called by a GC thread. 101 | void MMTkVMCompanionThread::wait_for_reached(stw_state desired_state) { 102 | assert(!Thread::current()->is_VM_thread(), "Supposed to be called by GC threads. Found VM thread."); 103 | assert(Thread::current() != this, "Supposed to be called by GC threads. Found companion thread."); 104 | assert(!Thread::current()->is_Java_thread(), "Supposed to be called by GC threads. Found Java thread."); 105 | 106 | MutexLockerEx locker(_lock, Mutex::_no_safepoint_check_flag); 107 | assert(_desired_state == desired_state, "State %d not requested.", desired_state); 108 | 109 | while (_reached_state != desired_state) { 110 | _lock->wait(Mutex::_no_safepoint_check_flag); 111 | } 112 | } 113 | 114 | // Called by the VM thread in `VM_MMTkSTWOperation`. 115 | // This method notify that all Java threads have yielded, and will block the VM thread (thereby 116 | // blocking Java threads) until the GC requests start-the-world. 117 | void MMTkVMCompanionThread::do_mmtk_stw_operation() { 118 | assert(Thread::current()->is_VM_thread(), "do_mmtk_stw_operation can only be executed by the VM thread"); 119 | 120 | { 121 | MutexLockerEx locker(_lock, Mutex::_no_safepoint_check_flag); 122 | 123 | // Tell the waiter thread that Java threads have stopped at yieldpoints. 124 | _reached_state = _threads_suspended; 125 | log_trace(gc)("do_mmtk_stw_operation: Reached _thread_suspended state. Notifying..."); 126 | _lock->notify_all(); 127 | 128 | // Wait until resume-the-world is requested 129 | while (_desired_state != _threads_resumed) { 130 | _lock->wait(Mutex::_no_safepoint_check_flag); 131 | } 132 | 133 | // Tell the waiter thread that Java threads will eventually resume from yieldpoints. This 134 | // function will return, and, as soon as the VM thread stops executing safepoint VM operations, 135 | // Java threads will resume from yieldpoints. 136 | // 137 | // Note: We have to notify *now* instead of after `VMThread::execute()`. For reasons unknown 138 | // (likely a bug in OpenJDK 11), the VMThread fails to notify the companion thread after 139 | // evaluating `VM_MMTkSTWOperation`, and continues to execute other VM operations (such as 140 | // `RevokeBias`). This leaves the companion thread blocking on `VMThread::execute()` until the 141 | // VM thread finishes executing the next batch of queued VM operations. If we notify after 142 | // `VMThread::execute` in `run()`, it will cause a deadlock like the following: 143 | // 144 | // - The companion thread is blocked at `VMThread::execute()`, waiting for the next batch of VM 145 | // operations to finish. 146 | // - The VM thread is blocked in `SafepointSynchronize::begin()`, waiting for all mutators to 147 | // reach safepoints. 148 | // - One mutator is allocating too fast and triggers a GC, which requires the `WorkerMonitor` 149 | // lock in mmtk-core. 150 | // - A GC worker is still executing `mmtk_resume_mutator`, holding the `WorkerMutator` (as the 151 | // last parked GC worker). It is asking the companion thread to resume mutators, and is still 152 | // waiting for the companion thread to reach the `_thread_resumed` state. As we see before, 153 | // the companion thread is waiting, too. 154 | // 155 | // By notifying now, we unblock the last parked GC worker before the companion thread returns 156 | // from `VMThread::execute`, allowing the GC worker to finish `resume_mutators`, breaking the 157 | // deadlock. When the next GC starts, the GC worker running `mmtk_stop_all_mutators` will need 158 | // to wait a little longer (as it always should) until the VM thread finishes executing other VM 159 | // operations and the companion thread is ready to respond to another request from GC workers. 160 | // 161 | // Also note that OpenJDK 17 changed the way the VM thread executes VM operations. The same 162 | // problem may not manifest in OpenJDK 17 or 21. 163 | assert(_desired_state == _threads_resumed, "start-the-world should be requested."); 164 | assert(_reached_state == _threads_suspended, "Threads should still be suspended at this moment."); 165 | _reached_state = _threads_resumed; 166 | log_trace(gc)("do_mmtk_stw_operation: Reached _thread_resumed state. Notifying..."); 167 | _lock->notify_all(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /openjdk/mmtkVMCompanionThread.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_VM_COMPANION_THREAD_HPP 26 | #define MMTK_OPENJDK_MMTK_VM_COMPANION_THREAD_HPP 27 | 28 | #include "mmtkVMOperation.hpp" 29 | #include "runtime/mutex.hpp" 30 | #include "runtime/perfData.hpp" 31 | #include "runtime/thread.hpp" 32 | #include "runtime/vmOperations.hpp" 33 | 34 | // This thread cooperates with the VMThread to allow stopping the world without 35 | // blocking any GC threads. 36 | // 37 | // In HotSpot, the way to stop all Java threads for stop-the-world GC is 38 | // letting the VMThread execute a blocking VM_Operation. However, the MMTk 39 | // expects the VM to provide two non-blocking methods to stop and start the 40 | // the world, whthout blocking the callers. This thread bridges the API gap 41 | // by calling VMThread::execute on behalf of GC threads upon reques so that it 42 | // blocks this thread instead of GC threads. 43 | class MMTkVMCompanionThread: public NamedThread { 44 | public: 45 | enum stw_state { 46 | _threads_suspended, 47 | _threads_resumed, 48 | }; 49 | private: 50 | Monitor* _lock; 51 | stw_state _desired_state; 52 | stw_state _reached_state; 53 | 54 | public: 55 | // Constructor 56 | MMTkVMCompanionThread(); 57 | ~MMTkVMCompanionThread(); 58 | 59 | virtual void run() override; 60 | 61 | // Interface for MMTk Core 62 | void request(stw_state desired_state, bool wait_until_reached); 63 | void wait_for_reached(stw_state reached_state); 64 | 65 | // Interface for the VM_MMTkSTWOperation 66 | void do_mmtk_stw_operation(); 67 | }; 68 | 69 | #endif // MMTK_OPENJDK_MMTK_VM_COMPANION_THREAD_HPP 70 | -------------------------------------------------------------------------------- /openjdk/mmtkVMOperation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Sun 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "mmtk.h" 27 | #include "mmtkVMCompanionThread.hpp" 28 | #include "mmtkVMOperation.hpp" 29 | #include "logging/log.hpp" 30 | 31 | VM_MMTkSTWOperation::VM_MMTkSTWOperation(MMTkVMCompanionThread *companion_thread): 32 | _companion_thread(companion_thread) { 33 | } 34 | 35 | void VM_MMTkSTWOperation::doit() { 36 | log_trace(vmthread)("Entered VM_MMTkSTWOperation::doit()."); 37 | _companion_thread->do_mmtk_stw_operation(); 38 | log_trace(vmthread)("Leaving VM_MMTkSTWOperation::doit()"); 39 | } 40 | -------------------------------------------------------------------------------- /openjdk/mmtkVMOperation.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Sun 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_MMTK_VM_OPERATION_HPP 26 | #define MMTK_OPENJDK_MMTK_VM_OPERATION_HPP 27 | 28 | #include "runtime/vmOperations.hpp" 29 | #include "runtime/vmThread.hpp" 30 | #include "thirdPartyHeapVMOperation.hpp" 31 | 32 | class VM_MMTkOperation : public VM_ThirdPartyOperation { 33 | }; 34 | 35 | class MMTkVMCompanionThread; 36 | class VM_MMTkSTWOperation : public VM_MMTkOperation { 37 | private: 38 | MMTkVMCompanionThread* _companion_thread; 39 | 40 | public: 41 | VM_MMTkSTWOperation(MMTkVMCompanionThread *companion_thread); 42 | virtual void doit() override; 43 | }; 44 | 45 | #endif // MMTK_OPENJDK_MMTK_VM_OPERATION_HPP 46 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeap.cpp: -------------------------------------------------------------------------------- 1 | #include "precompiled.hpp" 2 | #include "gc/shared/thirdPartyHeap.hpp" 3 | #include "mmtk.h" 4 | #include "thirdPartyHeap.hpp" 5 | #include "thirdPartyHeapArguments.hpp" 6 | 7 | namespace third_party_heap { 8 | 9 | GCArguments* new_gc_arguments() { 10 | return NULL; 11 | } 12 | 13 | void register_finalizer(void* obj) { 14 | add_finalizer(obj); 15 | } 16 | 17 | }; 18 | 19 | // #endif 20 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_THIRD_PARTY_HEAP_HPP 2 | #define MMTK_OPENJDK_THIRD_PARTY_HEAP_HPP 3 | 4 | #include "mmtkHeap.hpp" 5 | #include "mmtkMutator.hpp" 6 | 7 | typedef MMTkHeap ThirdPartyHeap; 8 | 9 | 10 | namespace third_party_heap { 11 | 12 | typedef MMTkMutatorContext MutatorContext; 13 | 14 | } 15 | #endif // MMTK_OPENJDK_THIRD_PARTY_HEAP_HPP 16 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeapArguments.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contactSUn 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "gc/shared/adaptiveSizePolicy.hpp" 27 | #include "gc/shared/collectorPolicy.hpp" 28 | #include "gc/shared/gcArguments.inline.hpp" 29 | #include "mmtkCollectorPolicy.hpp" 30 | #include "mmtkHeap.hpp" 31 | #include "runtime/globals_extension.hpp" 32 | #include "runtime/globals.hpp" 33 | #include "runtime/java.hpp" 34 | #include "runtime/vm_version.hpp" 35 | #include "thirdPartyHeapArguments.hpp" 36 | #include "utilities/defaultStream.hpp" 37 | 38 | size_t ThirdPartyHeapArguments::conservative_max_heap_alignment() { 39 | return CollectorPolicy::compute_heap_alignment(); 40 | } 41 | 42 | void ThirdPartyHeapArguments::initialize() { 43 | GCArguments::initialize(); 44 | assert(UseThirdPartyHeap , "Error, should UseThirdPartyHeap"); 45 | FLAG_SET_DEFAULT(UseTLAB, false); 46 | FLAG_SET_DEFAULT(UseCompressedClassPointers, UseCompressedOops); 47 | FLAG_SET_DEFAULT(ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads()); 48 | if (ParallelGCThreads == 0) { 49 | assert(!FLAG_IS_DEFAULT(ParallelGCThreads), "ParallelGCThreads should not be 0."); 50 | vm_exit_during_initialization("The flag -XX:+UseUseThirdPartyHeap can not be combined with -XX:ParallelGCThreads=0", NULL); 51 | } 52 | // Note: If you add an option here that may be forwarded to an MMTk option, 53 | // make sure to add appropriate code to MMTkHeap::set_mmtk_options. 54 | } 55 | 56 | CollectedHeap* ThirdPartyHeapArguments::create_heap() { 57 | return create_heap_with_policy(); 58 | } 59 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeapArguments.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contactSUn 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef MMTK_OPENJDK_THIRD_PARTY_HEAP_ARGUMENTS_HPP 26 | #define MMTK_OPENJDK_THIRD_PARTY_HEAP_ARGUMENTS_HPP 27 | 28 | #include "gc/shared/gcArguments.hpp" 29 | 30 | class CollectedHeap; 31 | 32 | class ThirdPartyHeapArguments : public GCArguments { 33 | public: 34 | virtual void initialize(); 35 | virtual size_t conservative_max_heap_alignment(); 36 | virtual CollectedHeap* create_heap(); 37 | }; 38 | 39 | #endif // MMTK_OPENJDK_THIRD_PARTY_HEAP_ARGUMENTS_HPP 40 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeapBarrierSet.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_THIRD_PARTY_HEAP_BARRIER_SET_HPP 2 | #define MMTK_OPENJDK_THIRD_PARTY_HEAP_BARRIER_SET_HPP 3 | 4 | #include "mmtkBarrierSet.hpp" 5 | 6 | typedef MMTkBarrierSet ThirdPartyHeapBarrierSet; 7 | 8 | #endif // MMTK_OPENJDK_THIRD_PARTY_HEAP_BARRIER_SET_HPP 9 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeapBarrierSetC2.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_THIRD_PARTY_HEAP_BARRIER_SET_C2_HPP 2 | #define MMTK_OPENJDK_THIRD_PARTY_HEAP_BARRIER_SET_C2_HPP 3 | 4 | class MMTkBarrierSetC2; 5 | 6 | typedef MMTkBarrierSetC2 ThirdPartyHeapBarrierSetC2; 7 | 8 | #endif // MMTK_OPENJDK_THIRD_PARTY_HEAP_BARRIER_SET_C2_HPP 9 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeapMutator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MMTK_OPENJDK_THIRD_PARTY_HEAP_MUTATOR_HPP 2 | #define MMTK_OPENJDK_THIRD_PARTY_HEAP_MUTATOR_HPP 3 | 4 | #include "mmtkMutator.hpp" 5 | 6 | 7 | namespace third_party_heap { 8 | 9 | typedef MMTkMutatorContext MutatorContext; 10 | 11 | } 12 | #endif // MMTK_OPENJDK_THIRD_PARTY_HEAP_MUTATOR_HPP 13 | -------------------------------------------------------------------------------- /openjdk/thirdPartyHeapVMOperation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Sun 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #include "precompiled.hpp" 26 | #include "thirdPartyHeapVMOperation.hpp" -------------------------------------------------------------------------------- /openjdk/thirdPartyHeapVMOperation.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This code is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * version 2 for more details (a copy is included in the LICENSE file that 13 | * accompanied this code). 14 | * 15 | * You should have received a copy of the GNU General Public License version 16 | * 2 along with this work; if not, write to the Free Software Foundation, 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Please contact Sun 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 | * or visit www.oracle.com if you need additional information or have any 21 | * questions. 22 | * 23 | */ 24 | 25 | #ifndef THIRD_PARTY_HEAP_VM_OPERATION_H 26 | #define THIRD_PARTY_HEAP_VM_OPERATION_H 27 | 28 | #include "runtime/vmOperations.hpp" 29 | 30 | class VM_ThirdPartyOperation : public VM_Operation { 31 | virtual VMOp_Type type() const override { 32 | return VMOp_ThirdPartyHeapOperation; 33 | } 34 | }; 35 | 36 | #endif // THIRD_PARTY_HEAP_VM_OPERATION_H -------------------------------------------------------------------------------- /tools/tracing/timeline/capture_openjdk.bt: -------------------------------------------------------------------------------- 1 | usdt:$MMTK:mmtk_openjdk:code_cache_roots { 2 | if (@enable_print) { 3 | printf("code_cache_roots,meta,%d,%lu,%lu,%lu\n", tid, nsecs, arg0, arg1); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tools/tracing/timeline/visualize_openjdk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def enrich_meta_extra(log_processor, name, tid, ts, gc, wp, args): 4 | if wp is not None: 5 | match name: 6 | case "code_cache_roots": 7 | nursery, mature = int(args[0]), int(args[1]) 8 | total = nursery + mature 9 | wp["args"] |= { 10 | "nursery_slots": nursery, 11 | "mature_slots": mature, 12 | "total_slots": total, 13 | } 14 | --------------------------------------------------------------------------------